<div id="app">
<pages-nav></pages-nav>
<div id='main-page' data-title='Color wheel'>
<div id='demo-wrapper'>
<h1>Demo </h1>
<div class='demo-container' :data-hide-text="(hide_text == true) ? 'on' : 'off'">
<demo></demo>
</div>
</div>
<div id='color-wheel-container'>
<color-wheel></color-wheel>
<div class='switch-mode'>
<color-theory-wheel :mode='selectedPickerMode' :static='true' wheel-style="white"
@click.native='modeSpinner()'> </color-theory-wheel>
<span class='mode-text'>{{(isCustom) ? "Custom" : pickerModeTitle}}</span>
</div>
<colors-display></colors-display>
</div>
</div>
<div id='color-theory-page' data-title='Color theory'>
<div class='inner-container'>
<div class='title'>
<h1>Color Theory</h1>
</div>
<div class='mixing'>
<h4>Mixing Colors</h4>
<div class='mixing-wrapper'>
<div class='additive-wrapper'>
<div class='additive-mixing color-mixing'>
<span class='cyan'></span>
<span class='yellow'></span>
<span class='magenta'></span>
</div>
<h5>CMYK</h5>
<h6>Additive</h6>
</div>
<div class='subtractive-wrapper'>
<div class='subtractive-mixing color-mixing'>
<span class='red'></span>
<span class='blue'></span>
<span class='green'></span>
</div>
<h5>RGB</h5>
<h6>Subtractive</h6>
</div>
</div>
</div>
<div class='relationships'>
<h4>Relationships</h4>
<div class='color-relations-wrapper'>
<color-theory-wheel @click.native='wheel_mode = "primary"' mode='primary' title='Primary Colors'
:static='true'>
</color-theory-wheel>
<color-theory-wheel @click.native='wheel_mode = "secondary"' mode='secondary'
title='Secondary Colors' :static='true'>
</color-theory-wheel>
<color-theory-wheel @click.native='wheel_mode = "tertiary"' mode='tertiary'
title='Tertiary Colors' :static='true'>
</color-theory-wheel>
<color-theory-wheel @click.native='wheel_mode = "temperature"' mode='temperature'
title='Temperature' :static='true'>
</color-theory-wheel>
</div>
</div>
<div class='modes'>
<h4>Modes</h4>
<div class='color-modes-wrapper'>
<color-theory-wheel @click.native='wheel_mode = m.name' :title='m.title' :mode='m.name'
:static='true' v-for='m in modes'></color-theory-wheel>
</div>
</div>
<div class='wheel'>
<color-theory-wheel :static="isStatic" :mode='wheel_mode' title='' :static='true'
data-labels='on'>
</color-theory-wheel>
</div>
</div>
</div>
<div id='about-page' data-title='About'>
<about></about>
</div>
</div>
<template id='color-wheel-template'>
<div id='color-wheel-wrapper'>
<div id='color-wheel-lightness' :style='lightnessStyle' draggable="false">
<div id='lightness-picker' draggable="false" :style='lightnessRotation'></div>
</div>
<div id='color-wheel' draggable="false" :data-moving='(pointerMoving) ? "yes" : "no"'>
<pointer v-for='(p, i) in pointerCount' :key="'pointer-'+i"
:class='{selected: selectedPointerIndex == i}' :index='i' :color-wheel='color_wheel'></pointer>
</div>
</div>
</template>
<template id='pointer-template'>
<div class='pointer' draggable="false" :data-index='index'
:style="{left: left, top: top, background: background}" :class="{enlarge: enlarge == true}"></div>
</template>
<template id='colors-display-template'>
<div id='colors-display'>
<div class='colors-containers'>
<div v-for='(c, i) in colors' class='color-container' :class="{selected: selectedPointerIndex == i }">
<div class='color-bg' :class='{entered: entered == i}' :style="getBackground(i)" draggable="true"
@dragstart="dragstart(i, $event)" @dragend="dragend" @dragenter="dragenter(i)">
<i class="fas fa-grip-horizontal"></i>
<div class='color-grads'>
<div v-for='(g, i) in c.palette' :style="{'background-color': g}"></div>
</div>
</div>
</div>
</div>
<div class='color-variations'>
<span class='arrow' :style='arrowStyle'></span>
<span class='title' @click='colorModelSpinner'>{{currentModel.name}} <i class="fas fa-sort"></i></span>
<span class='color-value' id='color-value-to-copy'>{{currentModel.value}}</span>
<span class='copy-value' data-clipboard-target="#color-value-to-copy" :data-copy-result='copy_message'
@mouseout="copy_message = ''" :data-message='(copy_message != "") ? "on" : "off"'>
<i class="far fa-copy"></i>
</span>
</div>
</div>
</template>
<template id='color-theory-wheel-template'>
<div class='color-theory-wheel' :data-mode='mode' :data-style='wheelStyle'>
<div class='colors-wrapper'>
<div class='colors-sections-wrapper'>
<div class='color-section' v-for='(c, i) in count' @mouseover='processHover(i)'
:class="{hover: highlightIndices.indexOf(i) > -1}"></div>
</div>
<div class='color-borders-wrapper'>
<div class='color-border' v-for='b in 6'></div>
</div>
</div>
<div class='color-theory-wheel-title'>{{title}}</div>
</div>
</template>
<template id='pages-nav-template'>
<nav id='pages-nav'>
<div class='page-dots'>
<div class='page-dot' v-for='(d, i) in pages' @mouseover='dotHover(i, $event)' @click='current_page = i'
:class="{active: current_page == i}"></div>
</div>
<div class='page-title' :style="{top: title_position +'px'}">{{pageTitle}}</div>
</nav>
</template>
<template id='about-template'>
<div id='about-container'>
<div class='color-wheel-title'>
<div id='logo'>
<div class='beak'>
<span></span>
</div>
<div class='body'>
</div>
<div class='eye'></div>
</div>
<div class='title'>Toucan Palatte Generator</div>
</div>
<div class='info-wrapper'>
<div class='about-container'>
<h4>About</h4>
<div class='about-wrapper'>
<p v-for='i in info'>{{i}}</p>
</div>
</div>
<div class='shortcuts-container'>
<h4>Shortcuts</h4>
<div class='shortcuts-wrapper'>
<div class='shortcut-row' v-for='s in shortcuts'>
<div class='shortcut-combination'>
<template v-for='(k, i) in s.keys'>
<kbd class='shortcut-key'
v-if='k.indexOf("mouse") == -1 && k != "+" && k != "/"'>{{k}}</kbd>
<span class='shortcut-plus' v-if='k == "+"'>+</span>
<span class='shortcut-plus' v-if='k == "/"'>/</span>
<span class='shortcut-mouse' :class='k' v-if='k.indexOf("mouse") > -1'>
<i></i>
</span>
</template>
</div>
<div class='shortcut-desc'>{{s.desc}}</div>
</div>
</div>
</div>
<div class='made-with-container'>
<h4>Made with</h4>
<div class='made-with-wrapper'>
<a :href="l.link" target='_blank' v-for='l in made_with'>{{l.title}}</a>
</div>
</div>
</div>
</div>
</template>
<template id='demo-template'>
<div class="d-flex" id="demo" :style='getNewStyle()' :data-darkmode="(settings.darkmode) ? 'on' : 'off'" :data-hide-text="(settings.hide_text) ? 'on' : 'off'">
<!-- Sidebar -->
<div class="border-right d-flex flex-column" id="sidebar-wrapper">
<div class="sidebar-heading">Dashboard </div>
<div class="list-group list-group-flush d-flex flex-column flex-grow-1">
<a href="#" class="list-group-item list-group-item-action d-flex align-items-center">
<i class="fas fa-home"></i><span>Home</span></a>
<a href="#" class="list-group-item list-group-item-action d-flex align-items-center">
<i class="fas fa-globe"></i>
<span>Overview</span></a>
<a href="#" class="list-group-item list-group-item-action d-flex align-items-center">
<i class="far fa-money-bill-alt"></i>
<span>Sales</span>
<span class="badge badge-primary badge-pill ml-auto">14</a>
<a href="#" class="list-group-item list-group-item-action d-flex align-items-center">
<i class="fas fa-user-circle"></i>
<span>Profile</span>
</a>
<a href="#" class="list-group-item list-group-item-action d-flex align-items-center">
<i class="fas fa-thermometer-quarter"></i>
<span>Status</span>
<span class="badge badge-success badge-pill ml-auto">2</span>
</a>
<a href="#" class="list-group-item list-group-item-action d-flex align-items-center">
<i class="fas fa-table"></i>
<span>Tabels</span></a>
<hr class='my3'>
<a href="#" class="list-group-item list-group-item-action d-flex align-items-center mt-auto">
<i class="fas fa-level-up-alt"></i>
<span>Upgrade</span>
</a>
</div>
</div>
<!-- /#sidebar-wrapper -->
<!-- Page Content -->
<div id="page-content-wrapper">
<nav class="navbar navbar-expand-lg navbar-light" id='top-navbar'>
<form class="form-inline mr-auto">
<input class="form-control mr-sm-2" type="search" placeholder="Search">
</form>
<ul class="navbar-nav">
<li class="nav-item mx-2">
<a class="nav-link" href="#">
<i class="far fa-bell"></i>
</a>
</li>
<li class="nav-item mx-2">
<a class="nav-link" href="#"><i class="fas fa-th-large"></i></a>
</li>
<li class="nav-item mx-2">
<a class="nav-link" href="#"><i class="fas fa-user"></i></a>
</li>
</ul>
</nav>
<div class="header bg-primary pb-6">
<div class="container-fluid">
<div class="header-body">
<!-- Card stats -->
<div class="row">
<div class="col-xl-4 col-md-6" v-for='card in admin_cards'>
<div class="card card-stats mb-4">
<!-- Card body -->
<div class="card-body">
<div class="row">
<div class="col">
<h5 class="card-title text-uppercase text-mute mb-0">{{card.title}}
</h5>
<div class="h2 font-weight-bold mb-0 mt-1">{{card.number}}</div>
</div>
<div class="col-auto">
<div class="icon icon-shape bg-gradient-red rounded-circle">
<i :class="card.icon_class"></i>
</div>
</div>
</div>
<p class="mt-3 mb-0 text-sm">
<span class="string-success mr-2"><i class="fa fa-arrow-up"></i>
{{card.percentage}}%</span>
<span class="text-nowrap">Since last month</span>
</p>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- /header -->
<div class="container-fluid">
<div class="row mb-4" id='graphs'>
<div class="col-xl-8">
<div class="card bg-default shadow-sm border-0">
<div class="card-header bg-transparent">
<div class="row align-items-center">
<div class="col">
<h6 class="text-light text-uppercase ls-1 mb-1">Overview</h6>
<h3 class="text-white mb-0">Visitors / Sale</h3>
</div>
<div class="col">
<ul class="nav nav-pills justify-content-end">
<li class="nav-item mr-2 mr-md-0" data-toggle="chart">
<a href="#" class="btn btn-primary btn-sm py-1 px-3"
data-toggle="tab" @click.stop.prevent='updateData("traffic")'
:class="{active: line_chart.source == 'traffic'}">
<span class="d-none d-md-block">Visitors</span>
<span class="d-md-none">V</span>
</a>
</li>
<li class="nav-item" data-toggle="chart">
<a href="#" class="btn btn-primary btn-sm py-1 px-3 mx-2"
data-toggle="tab" @click.stop.prevent="updateData('sales')"
:class="{active: line_chart.source == 'sales'}">
<span class="d-none d-md-block">Sales</span>
<span class="d-md-none">S</span>
</a>
</li>
</ul>
</div>
</div>
</div>
<div class="card-body">
<!-- Chart -->
<div class="chart">
<div class="chartjs-size-monitor">
<div class="chartjs-size-monitor-expand">
<div class=""></div>
</div>
<div class="chartjs-size-monitor-shrink">
<div class=""></div>
</div>
</div>
<chart :datasets='linechartDataset' :labels="line_chart.labels"
:options="line_chart.options"></chart>
</div>
</div>
</div>
</div>
<div class="col-xl-4" id='dashboard-settings'>
<div class="card shadow-sm border-0">
<div class="card-header bg-transparent">
<div class="row align-items-center">
<div class="col">
<h3 class="mb-0">Settings</h3>
</div>
</div>
</div>
<div class="card-body">
<div class='settings-row'>
<label class="switch">
<input type="checkbox" v-model='settings.darkmode'>
<span class='switch-toggle'></span>
<span class="text">Darkmode</span>
</label>
</div>
<div class='settings-row'>
<label class="switch">
<input type="checkbox" v-model='settings.default_sidebar_bg'>
<span class='switch-toggle'></span>
<span class="text">Default Sidebar Background</span>
</label>
</div>
<div class='settings-row hide-text'>
<label class="switch">
<input type="checkbox" v-model='settings.hide_text'>
<span class='switch-toggle'></span>
<span class="text">Hide Text</span>
</label>
</div>
</div>
</div>
</div>
</div>
<!-- /#graphs -->
<div class="row" id='stats'>
<div class="col-xl-7">
<div class="card border-0 shadow">
<div class="card-header border-0 bg-white">
<div class="row align-items-center">
<div class="col">
<h3 class="mb-0 text-uppercase">Page visits</h3>
</div>
<div class="col text-right">
<a href="#!" class="btn btn-sm btn-primary shadow-sm">See all</a>
</div>
</div>
</div>
<div class="table-responsive">
<!-- Projects table -->
<table class="table align-items-center table-flush">
<thead class="thead-light">
<tr>
<th class='border-bottom-0' scope="col">Page name</th>
<th class='border-bottom-0' scope="col">Visitors</th>
<th class='border-bottom-0' scope="col">Unique users</th>
<th class='border-bottom-0' scope="col">Bounce rate</th>
</tr>
</thead>
<tbody>
<tr v-for='row in page_visits'>
<th scope="row"> {{row.name}} </th>
<td> {{row.visitors}} </td>
<td> {{row.unique}} </td>
<td>
<i class="fas fa-arrow-up text-success mr-3"
v-if='row.direction == "up"'></i>
<i class="fas fa-arrow-down text-warning mr-3"
v-if='row.direction == "down"'></i>
{{row.rate}}
</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
<div class="col-xl-5 social-ref">
<div class="card border-0 shadow">
<div class="card-header border-0 bg-white">
<div class="row align-items-center">
<div class="col">
<h3 class="mb-0 text-uppercase">Social traffic</h3>
</div>
<div class="col text-right">
<a href="#!" class="btn btn-sm btn-primary shadow-sm">See all</a>
</div>
</div>
</div>
<div class="table-responsive">
<!-- Projects table -->
<table class="table align-items-center table-flush">
<thead class="thead-light">
<tr>
<th class='border-bottom-0' scope="col">Referral</th>
<th class='border-bottom-0' scope="col">Visitors</th>
<th class='border-bottom-0' scope="col"></th>
</tr>
</thead>
<tbody>
<tr v-for='row in social_ref'>
<th scope="row">
{{row.name}}
</th>
<td>
{{row.visitors}}
</td>
<td>
<div class="d-flex align-items-center">
<div class="progress">
<div class="progress-bar" role="progressbar"
:style="{width: row.percentage + '%'}"
:aria-valuenow="row.percentage" aria-valuemin="0"
aria-valuemax="100">{{row.percentage}}%
</div>
</div>
</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
</div>
<!-- /#stats -->
</div>
<footer class="footer pt-0">
<div class="row align-items-center justify-content-lg-between">
<div class="col-lg-6">
<div class="copyright text-center text-lg-left text-muted">
© 2021 <a href="#" class="font-weight-bold ml-1" target="_blank">Color wheel</a>
</div>
</div>
<div class="col-lg-6">
<ul class="nav nav-footer justify-content-center justify-content-lg-end">
<li class="nav-item">
<a href="#" class="nav-link" target="_blank">About Us</a>
</li>
<li class="nav-item">
<a href="#" class="nav-link" target="_blank">Blog</a>
</li>
<li class="nav-item">
<a href="#" class="nav-link" target="_blank">MIT License</a>
</li>
</ul>
</div>
</div>
</footer>
</div>
<!-- /#page-content-wrapper -->
</div>
</template>
@import url("https://fonts.googleapis.com/css2?family=Poppins:wght@400;700&display=swap");
@import url("https://fonts.googleapis.com/css2?family=Open+Sans&display=swap");
@import url("https://fonts.googleapis.com/css2?family=Skranji:wght@400;700&display=swap");
:root {
--bg-color: #ecf0f1;
--dark-accent: rgba(180, 180, 180, 0.2);
--darker-accent: lightgray;
--light-accent: rgba(180, 180, 180, 0.5);
--light-color: white;
--dark-color: black;
--site-main-color: #21749a;
--scrollbar-foreground: #b3cde0;
--scrolbar-background: rgba(255, 255, 255, 0);
}
:root {
--demo-bg-color: white;
--demo-sidebar-bg: white;
--demo-sidebar-hover: #{rgba(gray, 0.1)};
--demo-sidebar-hover-color: black;
--demo-primary-bg: #5e72e4;
--demo-primary-color: white;
--demo-sidebar-text-color: black;
--demo-btn-border: #465cda;
--demo-btn-bg: #{lighten(#5e72e4, 5%)};
--demo-btn-color: black;
--demo-btn-active-color: #fff;
--demo-btn-active: #{lighten(#5e72e4, 10%)};
--demo-btn-active-border: #{darken(#5e72e4, 10%)};
--demo-header-card: white;
--demo-header-card-text: #8898aa;
--demo-text-success: #28a745;
--demo-scrollbar-foreground: #b3cde0;
--demo-scrolbar-background: rgba(255, 255, 255, 0);
}
body {
background-color: var(--bg-color);
}
@mixin scrollbars(
$size: 4px,
$foreground-color: var(--scrollbar-foreground),
$background-color: var(--scrollbar-background)
) {
// For Google Chrome
&::scrollbar {
width: $size;
height: $size;
}
&::scrollbar-thumb {
background: $foreground-color;
border-radius: 0.3rem;
}
&::scrollbar-track {
background: $background-color;
}
// For Internet Explorer
& {
scrollbar-face-color: $foreground-color;
scrollbar-track-color: $background-color;
// firefox
scrollbar-width: thin;
scrollbar-color: $foreground-color $background-color;
}
}
@mixin ribbon($size: 0.4em) {
padding-bottom: 0.6em;
background-color: #21749a;
padding: 0.4em 2.3em;
font-size: 1.3rem;
color: white;
width: 70%;
margin-left: -0.5em;
margin-bottom: 1.2em;
margin-top: 0.6em;
position: relative;
white-space: nowrap;
}
#app {
position: fixed;
top: 0;
left: 0;
height: 100vh;
width: 100%;
overflow: auto;
box-sizing: border-box;
font-family: "Open Sans", sans-serif;
user-select: none;
overflow: hidden;
> div {
height: inherit;
width: inherit;
border-bottom: 1px solid;
box-sizing: border-box;
overflow: auto;
position: relative;
background: url("https://www.toptal.com/designers/subtlepatterns/patterns/frenchstucco.png");
}
#pages-nav {
position: fixed;
left: 0;
// border: 1px solid;
top: 50%;
z-index: 10;
transform: translateY(-50%);
margin-left: 0.4rem;
.page-dots:hover + .page-title {
opacity: 1;
}
.page-dot {
width: 0.5rem;
height: 0.5rem;
background-color: purple;
border-radius: 50%;
margin-bottom: 0.5rem;
cursor: pointer;
transition: all 0.3s;
opacity: 0.8;
&:hover {
opacity: 1;
}
&.active {
height: 1rem;
border-radius: 0.2rem;
}
}
.page-title {
position: absolute;
top: 0;
left: 1rem;
border-radius: 0.3em;
padding: 0.2em 1em;
background-color: purple;
color: white;
transform: translateY(-50%);
font-size: 0.7rem;
pointer-events: none;
transition: all 0.3s;
white-space: nowrap;
opacity: 0;
}
}
#main-page {
#color-wheel-container {
position: absolute;
top: 50%;
right: 3%;
transform: translateY(-50%);
border-radius: 0.3rem;
background-color: white;
//background-color: rgba(180, 180, 180, 0.2);
padding: 2rem;
box-shadow: 0 0 1em 0 rgba(0, 0, 0, 0.3);
.color-theory-wheel {
margin: 0;
width: auto;
left: initial;
top: initial;
.colors-wrapper {
height: 2rem;
width: 2rem;
border-radius: 50%;
}
}
.switch-mode {
padding: 0.2em 0.5em 0.2em 1em;
border-radius: 0.2em;
margin: 1em 0;
display: flex;
font-size: 1rem;
justify-content: center;
align-items: center;
cursor: pointer;
position: absolute;
top: 1%;
right: 2%;
&:hover {
.mode-text {
opacity: 1;
bottom: 115%;
}
}
.mode-text {
font-size: 0.6rem;
position: absolute;
bottom: 95%;
padding: 0.2rem 0.5rem;
background-color: lightgray;
border-radius: 0.2rem;
white-space: nowrap;
pointer-events: none;
transition: all 0.3s;
opacity: 0;
&::before {
top: 100%;
left: 50%;
height: 0.5rem;
width: 0.5rem;
background-color: lightgray;
transform: translate(-50%, -70%) rotate(45deg);
content: "";
position: absolute;
}
}
}
}
#colors-display {
display: flex;
flex-direction: column;
margin-top: 2rem;
.colors-containers {
display: flex;
> div {
flex-grow: 1;
min-width: 20%;
height: 2em;
position: relative;
.color-bg {
height: 100%;
display: flex;
justify-content: center;
align-items: flex-end;
color: rgba(black, 0.5);
transition: opacity 0.3s;
box-sizing: border-box;
&.entered {
border: 0.1em dashed gray;
opacity: 0.5;
}
&:hover i {
opacity: 1;
}
i {
opacity: 0;
transition: all 0.3s;
position: absolute;
bottom: 100%;
left: 50%;
transform: translate(-50%, -10%);
cursor: grab;
}
.color-grads {
display: flex;
height: 30%;
width: 100%;
div {
display: block;
width: 25%;
height: 100%;
}
}
}
}
}
.color-variations {
display: flex;
font-size: 0.7rem;
margin-top: 2em;
background-color: var(--dark-accent);
border-radius: 0.3em;
position: relative;
color: var(--dark-color);
.arrow {
position: absolute;
bottom: 100%;
left: 50%;
transform: translateX(-50%);
height: 0;
width: 0;
border-bottom: solid 0.6rem var(--dark-accent);
border-left: solid 0.6rem transparent;
border-right: solid 0.6rem transparent;
}
.title {
width: 25%;
display: block;
padding: 1em;
text-transform: uppercase;
cursor: pointer;
}
.color-value {
padding: 1em 0;
user-select: all;
}
.copy-value {
display: flex;
justify-content: center;
align-items: center;
font-size: 1.1em;
margin-left: auto;
cursor: pointer;
transition: all 0.3s;
padding: 1em;
background-color: var(--dark-accent);
position: relative;
&:hover {
background-color: var(--light-accent);
}
&[data-message="on"] {
&::after,
&::before {
opacity: 1;
}
}
&::after {
content: attr(data-copy-result);
padding: 0.5em 1em;
white-space: nowrap;
position: absolute;
top: 120%;
left: 50%;
transform: translatex(-50%);
background-color: var(--darker-accent);
pointer-events: none;
border-radius: 0.3em;
font-size: 0.7rem;
opacity: 0;
}
&::before {
content: "";
position: absolute;
top: 115%;
left: 50%;
transform: translatex(-50%) rotate(45deg);
background-color: var(--darker-accent);
pointer-events: none;
height: 1em;
width: 1em;
opacity: 0;
}
}
}
}
}
#color-theory-page {
display: flex;
justify-content: center;
align-items: center;
flex-direction: column;
h1 {
text-transform: uppercase;
font-weight: bold;
margin: 1.6em 0;
font-family: "Skranji", cursive;
line-height: 0;
}
.inner-container {
max-width: 1200px;
display: grid;
grid-template-columns: 0.7fr 1.3fr;
grid-template-areas:
"title title"
"mixing wheel"
"relationships wheel "
"modes wheel";
grid-row-gap: 1em;
h4 {
@include ribbon;
margin-bottom: 0.6em;
}
> div:not(.wheel):not(.title) {
font-size: 0.4em;
.color-theory-wheel {
cursor: pointer;
}
}
.title {
grid-area: title;
font-size: 1.5em;
font-weight: bold;
text-align: center;
text-transform: uppercase;
}
.mixing {
grid-area: mixing;
background-color: white;
border-radius: 0.3em;
box-shadow: 0 0 0.6em 0 rgba(180, 180, 180, 0.8);
.mixing-wrapper {
justify-content: space-around;
> div {
justify-content: center;
display: flex;
flex-direction: column;
align-items: center;
}
h5 {
font-weight: bold;
margin: 0;
}
h6 {
font-size: 1.6em;
margin: 0;
}
}
}
.relationships {
grid-area: relationships;
background-color: white;
border-radius: 0.3em;
box-shadow: 0 0 0.6em 0 rgba(180, 180, 180, 0.8);
}
.modes {
grid-area: modes;
background-color: white;
border-radius: 0.3em;
box-shadow: 0 0 0.6em 0 rgba(180, 180, 180, 0.8);
}
.terms {
grid-area: terms;
}
.meaning {
grid-area: meaning;
}
.wheel {
grid-area: wheel;
font-size: 3em;
display: flex;
flex-direction: column;
}
.mixing-wrapper,
.color-modes-wrapper,
.color-relations-wrapper {
display: flex;
flex-wrap: wrap;
justify-content: center;
}
.color-mixing {
height: 12em;
width: 12em;
position: relative;
isolation: isolate;
span {
border-radius: 50%;
height: inherit;
width: inherit;
display: block;
position: absolute;
left: 50%;
top: 50%;
width: 50%;
height: 50%;
transform: translate(-50%, -50%);
mix-blend-mode: screen;
}
&.subtractive-mixing span {
&.green {
background-color: lime;
transform: translate(-20%, -30%);
}
&.red {
background-color: red;
transform: translate(-50%, -70%);
}
&.blue {
background-color: blue;
transform: translate(-80%, -30%);
}
}
&.additive-mixing span {
mix-blend-mode: multiply;
&.cyan {
background-color: cyan;
transform: translate(-20%, -30%);
}
&.magenta {
background-color: magenta;
transform: translate(-50%, -70%);
}
&.yellow {
background-color: yellow;
transform: translate(-80%, -30%);
}
}
}
}
}
#about-page {
#about-container {
margin: 0 auto;
padding: 0 2em;
max-width: 1350px;
}
.color-wheel-title {
display: flex;
justify-content: center;
padding: 2rem;
margin: 3rem 0;
.title {
font-size: 2.6rem;
font-weight: bold;
font-family: "Skranji", cursive;
}
}
.info-wrapper {
$shortcut-color: #888888;
display: flex;
justify-content: space-around;
> div {
font-size: 0.8em;
line-height: 2;
text-align: justify;
background-color: white;
box-shadow: 0 0 0.3em 0 rgba(128, 128, 128, 0.45098039215686275);
border-radius: 0.3em;
h4 {
@include ribbon;
}
> div {
padding: 0 3em;
}
}
.shortcuts-container {
width: 45%;
font-size: 0.9em;
.shortcut-row {
margin-bottom: 1em;
display: flex;
.shortcut-combination {
width: 35%;
display: flex;
align-items: center;
margin-right: 1em;
justify-content: flex-start;
.shortcut-key {
color: $shortcut-color;
box-shadow: 0.05em 0.05em 0 rgba(0, 0, 0, 0.2);
border: 1px solid #ccc;
margin: 0 0.1em;
padding: 0.1em 0.5em;
border-radius: 0.25em;
background: #f3f3f3;
min-height: 2em;
min-width: 2em;
display: flex;
justify-content: center;
align-items: center;
}
}
.shortcut-desc {
font-size: 0.8em;
}
}
.shortcut-plus {
color: $shortcut-color;
margin: 0 0.4em;
}
.shortcut-mouse {
height: 0.5rem;
width: 0.5rem;
border-radius: 50%;
background: darken(#d2d2d2, 5%);
position: relative;
&::after,
&:before {
position: absolute;
bottom: 105%;
left: 50%;
transform: translateX(-50%) rotate(45deg);
border: 0.1em solid transparent;
border-left: 0.1em solid $shortcut-color;
border-top: 0.1em solid $shortcut-color;
height: 0.35em;
width: 0.35em;
}
&::after {
top: 105%;
transform: translateX(-50%) rotate(225deg);
}
&.mouse-wheel-up {
&::before {
content: "";
}
}
&.mouse-wheel {
&::after,
&::before {
content: "";
}
}
&.mouse-click-left {
height: 1.5em;
width: 0.8em;
border-radius: 0.3em;
overflow: hidden;
&::before {
content: "";
top: 0;
transform: unset;
left: 0;
border: 0;
background-color: $shortcut-color;
border-radius: 0 0 0.2em 0;
}
}
}
}
.made-with-container {
width: 20%;
a {
display: block;
font-size: 1.1em;
color: rgba(0, 0, 0, 0.7);
margin-bottom: 1em;
text-decoration: none;
padding: 0.3em;
position: relative;
transition: all 0.3s;
&::before {
position: absolute;
top: 100%;
width: 0;
transition: all 0.5s ease-in-out;
content: "";
height: 0.3em;
background-color: rgba(180, 180, 180, 0.2);
}
&:hover {
color: black;
&::before {
width: 100%;
}
}
}
}
.about-container {
width: 25%;
}
}
#logo {
height: 7em;
width: 7em;
position: relative;
font-size: 0.4em;
$dark: #000923;
margin: 0 3em;
.beak {
height: 30%;
width: 60%;
position: absolute;
right: 0;
border-radius: 50% 51% 100% 0% / 0% 100% 0% 0%;
background-color: #fa9c21;
background-image: radial-gradient(circle at 80% 80%, #ed3027, #fa9c21);
overflow: hidden;
span {
position: absolute;
bottom: 0;
right: 0;
border-radius: 50%;
background-color: $dark;
height: 2em;
width: 2em;
transform: translate(50%, 50%);
}
}
.body {
height: 100%;
width: 40%;
position: absolute;
left: 0;
top: 0;
border-radius: 100% 0% 100% 0% / 40% 60% 50% 60%;
background-image: linear-gradient($dark, lighten($dark, 10%));
}
.eye {
border-radius: 2em 0 0 2em;
background-color: #525252;
position: absolute;
top: 0%;
right: 60%;
height: 30%;
width: 20%;
}
}
}
}
#color-wheel-wrapper {
height: 15rem;
width: 15rem;
position: relative;
#color-wheel-lightness {
--selected-color: gray;
position: absolute;
bottom: 0;
height: 100%;
width: 100%;
background-color: green;
z-index: 0;
border-radius: 50%;
box-shadow: 0 0 1em 0.1em rgba(180, 180, 180, 0.5);
#lightness-picker {
height: 100%;
width: 100%;
&::before {
content: "";
position: absolute;
bottom: 100%;
left: 50%;
transform: translateX(-50%);
height: 0;
width: 0;
border-top: solid 0.5rem black;
border-left: solid 0.5rem transparent;
border-right: solid 0.5rem transparent;
}
}
}
#color-wheel {
border-radius: 50%;
height: calc(98% - 0.5em);
width: calc(98% - 0.5em);
position: absolute;
left: calc(1% + 0.25em);
top: calc(1% + 0.25em);
z-index: 1;
box-sizing: border-box;
box-shadow: 0 0 0 0.1em white;
overflow: hidden;
--level: 50%;
background-image: linear-gradient(red, transparent var(--level)),
linear-gradient(240deg, yellow, transparent var(--level)),
linear-gradient(-60deg, green, transparent var(--level)),
linear-gradient(0deg, cyan, transparent var(--level)),
linear-gradient(60deg, blue, transparent var(--level)),
linear-gradient(120deg, magenta, transparent var(--level)),
radial-gradient(gray, white 70%);
&[data-moving="yes"] {
cursor: none !important;
.pointer {
cursor: none !important;
&.selected {
height: 8%;
width: 8%;
}
}
}
.pointer {
border-radius: 50%;
height: 3%;
width: 3%;
position: absolute;
left: 50%;
top: 50%;
box-shadow: inset 0 0 5px 5px white;
cursor: pointer;
z-index: 0;
transition: width 0.2s, height 0.2s;
transform: translate(-50%, -50%);
&.selected {
box-shadow: inset 0 0 0 3px white, 0 0 0px 2px rgba(black, 0.5);
z-index: 1;
height: 6%;
width: 6%;
}
&.enlarge {
width: 15%;
height: 15%;
box-shadow: inset 0 0 0 1px rgba(white, 0.5),
0 0 0px 1px rgba(black, 0.1);
}
}
}
}
.color-theory-wheel {
left: 10%;
top: 10%;
margin: 2em;
width: 10em;
.color-theory-wheel-title {
color: gray;
font-size: 1.3em;
text-align: center;
}
.colors-wrapper {
height: 10em;
width: 10em;
border-radius: 50%;
background-color: white;
position: relative;
border: 1px solid gray;
&::before {
background-color: white;
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
content: "";
height: 15%;
width: 15%;
border-radius: 50%;
z-index: 5;
}
}
.color-borders-wrapper {
width: 98%;
height: 98%;
position: relative;
position: absolute;
top: 1%;
left: 1%;
overflow: hidden;
border-radius: 50%;
pointer-events: none;
.color-border {
position: absolute;
height: 110%;
width: 0.05em;
background-color: white;
top: 50%;
left: 50%;
z-index: 3;
transform: rotate(15deg);
@for $i from 1 through 6 {
&:nth-child(#{$i}) {
$rotate: $i * 30deg + 15;
transform: translate(-50%, -50%) rotate($rotate);
}
}
}
}
&[data-mode="mono"] .color-section.hover::after {
content: "";
position: absolute;
top: 0%;
left: 50%;
transform: translateX(-50%);
background-image: repeating-radial-gradient(
circle at 50% 50%,
rgba(white, 0.5) 0 35%,
rgba(white, 0.3) 30% 53%,
transparent 50% 100%
);
height: 200%;
width: 373%;
border-radius: 50%;
}
&[data-style="white"] {
.colors-wrapper {
background-color: white;
position: relative;
border: 0;
box-shadow: 0 0 0.5rem 0 rgba(gray, 0.6);
}
.color-section {
&:not(.hover) {
background-color: #eee !important;
&::before {
content: unset;
}
}
&.hover {
background-color: lightgray !important;
}
}
.colors-wrapper::before {
content: unset;
}
}
&[data-mode="temperature"] .color-border:nth-child(5) {
width: 0.3em;
z-index: 5;
&::after {
content: "";
height: 100%;
width: 54%;
border-right: 0.05em dashed gray;
position: absolute;
left: 0;
top: 0;
box-sizing: border-box;
}
}
&[data-labels="on"] .color-section.hover::after {
opacity: 1;
}
.colors-sections-wrapper {
width: 98%;
height: 98%;
position: relative;
position: absolute;
top: 1%;
left: 1%;
overflow: hidden;
border-radius: 50%;
.color-section {
height: 50%;
width: 27%;
position: absolute;
left: 50%;
bottom: 50%;
transform-origin: bottom center;
transition: background-color 0.3s;
overflow: hidden;
box-sizing: border-box;
clip-path: polygon(50% 100%, 0 0, 100% 0);
&::before {
position: absolute;
top: 0;
left: 0;
height: 100%;
width: 100%;
content: "";
transition: all 0.3s;
background-image: linear-gradient(
0deg,
rgba(lightgray, 0.3),
rgba(90, 90, 90, 0.2)
);
}
&::after {
position: absolute;
top: 0;
padding: 1em;
border-radius: 0.3em;
left: 50%;
transform: translateX(-50%) rotate(90deg);
height: 50%;
font-size: 1rem;
display: flex;
justify-content: center;
align-items: center;
white-space: pre;
color: white;
text-shadow: 0 0 0.2em gray;
text-transform: capitalize;
opacity: 0;
transition: all 0.3s;
}
$colors: 0 22 33 49 59 81 117 181 245 266 293 314;
$light: 50 50 50 50 50 50 41 33 42 50 43 48;
$names: (
"red",
"red-orange",
"orange",
"yellow-orange",
"yellow",
"yellow-green",
"green",
"blue-green",
"blue",
"blue-violet",
"violet",
"red-violet"
);
@for $i from 0 through 11 {
&:nth-child(#{$i + 1}) {
$rotate: $i * 30deg;
$hue: nth($colors, $i + 1);
$lightness: nth($light, $i + 1);
transform: translateX(-50%) rotate($rotate);
background-color: hsla($hue, 100%, 50%, 0.2);
&.hover {
background-color: hsla($hue, 100%, $lightness, 1);
}
&::after {
content: nth($names, $i + 1);
@if ($i < 6) {
transform: translateX(-50%) rotate(270deg);
}
}
}
}
}
}
}
#demo-wrapper {
height: 90vh;
width: 75vw;
left: 5vw;
top: 5vh;
position: relative;
background-color: white;
border-radius: 0.2em;
max-width: 1200px;
display: flex;
flex-direction: column;
box-shadow: 0 0 0.9em 0 rgba(180, 180, 180, 0.6);
.demo-container {
padding: 2em;
overflow: auto;
}
h1 {
display: flex;
align-items: center;
@include ribbon();
}
}
#demo {
height: 100%;
width: 100%;
left: 0;
top: 0;
position: relative;
overflow: hidden;
border: 1px solid lightgray;
border-radius: 0.3em;
background-color: var(--demo-bg-color);
color: var(--demo-text-color);
&[data-hide-text="on"] {
text-indent: -2000px;
.settings-row.hide-text {
text-indent: initial;
}
}
&[data-darkmode="on"] {
--demo-bg-color: #282b34;
--demo-sidebar-bg: #282b34;
--demo-sidebar-hover: #{rgba(white, 0.1)};
--demo-sidebar-hover-color: white;
--demo-text-color: white;
--demo-sidebar-text-color: white;
--demo-card-bg: #1e1e1e;
.container-fluid {
.card {
background-color: var(--demo-card-bg);
box-shadow: 0 0.125rem 0.25rem rgba(lightgray, 0.1);
}
.bg-white {
background-color: var(--demo-card-bg) !important;
}
thead th {
background-color: var(--demo-card-bg) !important;
}
}
.table th,
.table td,
.border-right {
border-color: rgba(white, 0.2) !important;
}
}
.bg-primary {
background-color: var(--demo-primary-bg) !important;
}
.btn-primary,
.progress-bar {
background-color: var(--demo-btn-bg);
color: var(--demo-btn-color);
}
.btn-primary {
border-color: var(--demo-btn-border);
&:focus {
box-shadow: unset !important;
}
&.active {
background-color: var(--demo-btn-active);
border-color: var(--demo-btn-active-border);
color: var(--demo-btn-active-color);
}
}
#dashboard-settings {
.settings-row {
font-size: 0.8rem;
.switch {
display: flex;
align-items: center;
cursor: pointer;
.switch-toggle {
border-radius: 1rem;
width: 1.5rem;
height: 0.8rem;
background-color: #b0bec5;
transition: all 0.3s;
position: relative;
margin-right: 0.4em;
&::before {
width: 0.4rem;
height: 0.4rem;
position: absolute;
left: 0.2rem;
top: 0.2rem;
content: "";
border-radius: 50%;
background-color: rgba(white, 0.5);
transition: all 0.3s;
}
}
input[type="checkbox"] {
display: none;
&:checked + .switch-toggle {
background-color: #1976d2;
&::before {
left: 100%;
transform: translateX(calc(-100% - 0.2rem));
background-color: rgba(white, 0.5);
}
}
}
}
}
}
#sidebar-wrapper {
margin-left: -15rem;
transition: margin 0.25s ease-out;
background-color: white;
padding: 0em;
background-color: var(--demo-sidebar-bg);
color: var(--demo-sidebar-text-color);
.sidebar-heading {
padding: 0;
font-size: 1.2rem;
display: flex;
justify-content: center;
align-items: center;
padding: 2em 0;
}
.list-group {
width: 14em;
font-size: 0.9rem;
padding: 0.5em;
.list-group-item {
padding: 0.7em 1em 0.7em 0.2em;
background-color: transparent;
color: var(--demo-sidebar-text-color);
}
> a {
border: 0;
border-radius: 0.3rem;
transition: background-color 0.3s;
font-weight: normal;
&:hover {
background-color: var(--demo-sidebar-hover);
color: var(--demo-sidebar-hover-color);
}
i {
width: 2.5em;
text-align: center;
font-size: 1rem;
margin-right: 0.5rem;
}
}
}
}
#page-content-wrapper {
min-width: 100vw;
overflow: auto;
@include scrollbars(
4px,
var(--demo-scrollbar-foreground),
var(--demo-scrollbar-background)
);
#top-navbar {
padding: 1.3em 2em;
background-color: var(--demo-primary-bg) !important;
input[type="search"] {
border-radius: 0.6em;
outline: 0;
transition: all 0.3s;
border: 0;
background-color: rgba(white, 0.6);
&:focus {
width: 20em;
background-color: white;
}
}
border-bottom: 1px solid rgba(255, 255, 255, 0.1);
}
.nav-link {
color: var(--demo-primary-color);
}
.string-success {
color: var(--demo-text-success);
}
.container-fluid {
padding: 2em 2em 8em 2em;
.header-body {
.card {
border-radius: 0.375rem;
background-color: var(--demo-header-card);
border: 0;
color: var(--demo-header-card-text-1);
.text-mute {
color: var(--demo-header-card-text-2);
}
.card-title,
p {
font-size: 0.8rem;
}
.h2 {
font-size: 1.5rem;
}
.icon {
height: 3rem;
width: 3rem;
display: inline-flex;
align-items: center;
justify-content: center;
font-size: 1.2em;
background-color: rgba(gray, 0.1);
}
}
}
h6 {
font-size: 0.7rem;
}
h3 {
font-size: 1rem !important;
}
h5 {
font-size: 0.7rem !important;
}
.btn-sm {
font-size: 0.75rem;
}
.text-mute {
color: #8898aa;
}
.bg-default {
background-color: #172b4d !important;
}
#graphs {
margin-top: -7em;
}
#stats {
font-size: 0.8rem;
thead th {
color: #8898aa;
background-color: #f6f9fc;
font-weight: normal;
text-transform: uppercase;
font-size: 0.8em;
}
.progress {
width: 100%;
font-size: 0.7em;
}
.social-ref td:last-child {
width: 50%;
}
}
}
footer {
padding: 2em;
font-size: 0.8rem;
a {
color: inherit;
}
}
}
}
@media (min-width: 768px) {
#demo {
#sidebar-wrapper {
margin-left: 0;
}
#page-content-wrapper {
min-width: 0;
width: 100%;
}
}
}
@media (max-width: 700px) {
html {
font-size: 12px;
}
#app{
h1, .color-wheel-title .title{
font-size: 2rem !important;
}
#color-wheel-wrapper {
height: 12rem;
width: 12rem;
}
#color-theory-page {
h5{
font-size: 1.4em;
}
.color-theory-wheel-title{
font-size: 1.7em;
}
.inner-container {
max-width: 100%;
grid-template-columns: 1fr 1fr 1fr;
grid-template-areas:
"title title title"
"wheel wheel wheel"
"mixing relationships modes";
grid-row-gap: 0.5em;
.color-theory-wheel {
margin: 1em auto;
}
.modes, .relationships{
.color-theory-wheel{
margin: 1em 4em;
}
}
}
}
#about-page{
.info-wrapper{
display: block;
> .about-container, .shortcuts-container, .made-with-container{
width: 100%;
}
> div > div{
padding: 1em 2em;
}
}
}
}
}
View Compiled
/**
* Uitlity method to map state from observable to components.
* The methods will convert snake_case keys to camelCase
* @param Array state arary of state keys to be mapped
*/
const mapState = function (state) {
let returnState = {};
if (!Array.isArray(state))
return returnState;
state.forEach(s => {
let key = s.split("_").map((k, i) => {
let replaceKey = k.replace(/^./, (m) => m.toUpperCase());
return (i > 0) ? replaceKey : k;
}).join("");
returnState[key] = function () {
return store[s];
}
});
return returnState;
}
/**
* Utility methods to map mutations to compoenent
* @param Array methods array of methods keys to be mapped
*/
const mapMethods = function (methods) {
let returnMethods = {};
if (!Array.isArray(methods))
return returnMethods;
methods.forEach(m => {
returnMethods[m] = mutations[m];
});
return returnMethods;
}
/**
* Observable is used in place to Vuex as a simple state management alterantive
*/
let store = Vue.observable({
picker_modes: [{
name: "comple",
title: "Complementary"
}, {
name: "split",
title: "Split Complementary"
}, {
name: "mono",
title: "Monochromatic"
}, {
name: "analog",
title: "Analogous"
}, {
name: "tri",
title: "Triadic"
}, {
name: "square",
title: "Square"
}, {
name: "tetra",
title: "Tetradic"
}],
selected_picker_mode: "single",
is_custom: false,
picker_mode_title: function () {
const currentMode = Object.values(this.picker_modes).filter(m => {
if (m.name == this.selected_picker_mode && m.name != "custom")
return m.title;
});
if (currentMode[0] == undefined)
return "";
return currentMode[0].title;
},
pointer_count: function () {
const mode = this.selected_picker_mode;
let count = 0;
switch (mode) {
case "single":
count = 1;
break;
case "comple":
count = 2;
break;
case "split":
case "analog":
case "mono":
case "tri":
count = 3;
break;
case "square":
case "tetra":
count = 4;
break;
}
return count;
},
pointer_sepration: {
"comple": [180, 180],
"split": [140, 140, 80],
"analog": [40, 40, 280],
"mono": [
[0.3, 0.3, 0.6],
[-0.3, 0.3, 0.3],
[-0.6, -0.3, 0.3]
],
"tri": [120, 120, 120],
"square": [90, 90, 90, 90],
"tetra": [120, 60, 120, 60],
},
wheel_demo_indices: {
"comple": [0, 6],
"analog": [0, 1, 11],
"mono": [0],
"split": [0, 5, 7],
"tri": [0, 4, 8],
"tetra": [0, 4, 6, 10],
"square": [0, 3, 6, 9],
"temperature": [Array(12).keys()],
"primary": [0, 4, 8],
"secondary": [2, 6, 10],
"tertiary": [1, 3, 5, 7, 9, 11]
},
selected_pointer_index: 0,
colors: [{
degrees: 80,
saturation: 100,
lightness: 50,
lightnessRotate: 90,
left: 0,
top: 0,
palette: {
darkest: "",
darker: "",
lighter: "",
lightest: ""
}
}],
ctrl_pressed: false,
pointer_moving: false
});
let mutations = {
updateMode: function (mode) {
if (mode == 'custom') {
store.is_custom = true;
} else {
store.is_custom = false;
store.selected_picker_mode = mode;
store.selected_pointer_index = 0;
}
},
updateColor: function (index, newColors) {
const currentColors = store.colors[index];
const updatedColor = Object.assign({}, currentColors, newColors);
const {
degrees: h,
saturation: s,
lightness: l
} = updatedColor;
const color = tinycolor(`hsl(${h}, ${s}%, ${l}%)`);
updatedColor.palette = {
darkest: color.clone().darken(30).toHslString(),
darker: color.clone().darken(15).toHslString(),
lighter: color.clone().lighten(15).toHslString(),
lightest: color.clone().lighten(30).toHslString(),
}
updatedColor.hsl = color.toHslString();
Vue.set(store.colors, index, updatedColor);
},
removeColor: function (start) {
store.colors.splice(start);
},
swapColors: function (from, to) {
const a = store.colors[from];
const b = store.colors[to];
Vue.set(store.colors, from, b);
Vue.set(store.colors, to, a);
},
updatePointerIndex: function (newIndex) {
store.selected_pointer_index = parseInt(newIndex);
},
updateCtrl: function (newValue) {
store.ctrl_pressed = newValue;
},
updateWheelMode: function (index) {
store.picker_modes[index];
store.wheel_demo_mode = mode;
},
updateMoving: function (isMoving) {
store.pointer_moving = isMoving;
}
};
Vue.component('pointer', {
template: "#pointer-template",
props: ['index', 'color-wheel'],
data: () => {
return {
pointer_clicked: false,
enlarge: false,
enlargeTimeout: null
}
},
created: function () {
if (this.index == this.selectedPointerIndex) {
window.addEventListener('keydown', event => {
switch (event.code) {
case "ArrowUp":
case "ArrowDown":
this.changeSaturation(event.code);
event.preventDefault();
break;
case "ArrowLeft":
case "ArrowRight":
this.changeHue(event.code);
event.preventDefault();
break;
}
});
}
// check if lightness change and update class for 1 seconds
this.$parent.$on("lightnessChange", () => {
if (this.index == this.selectedPointerIndex) {
this.enlarge = true;
clearTimeout(this.enlargeTimeout);
this.enlargeTimeout = setTimeout(() => {
this.enlarge = false;
}, 700);
}
});
},
mounted: function () {
// Create object for the current element
let newObject = {
degrees: 260,
saturation: 100,
lightness: 50,
light: 90,
palette: {
darkest: "",
darker: "",
lighter: "",
lightest: ""
}
}
// update or add new color item if required
this.updateColor(this.index, newObject);
// assign events
document.addEventListener("mousedown", this.mouseDown);
document.addEventListener("mouseup", e => this.pointer_clicked = false);
document.addEventListener("mousemove", this.movePointer);
// this event is needed when picker mode changes
this.$parent.$on('updateFirstPointer', data => {
if (this.index == 0) {
const coord = this.getPointerPosition(this.colors[0]);
const firstColor = Object.assign(this.colors[0], coord);
this.updateColor(this.index, firstColor);
}
});
this.$parent.$on('updateOtherPointers', data => {
if (this.isCustom != true)
this.getstyle();
});
},
methods: {
mapMethods(["updateColor", "removeColor", "updatePointerIndex", "updateMode", "updateMoving"]),
mouseDown: function (e) {
if (e.target.id == 'color-wheel') {
this.pointer_clicked = true;
if (this.ctrlPressed)
this.updateMode("custom");
else
this.updatePointerIndex(0);
}
if (e.target.classList.contains("pointer")) {
this.pointer_clicked = true;
const pointerIndex = e.target.getAttribute("data-index");
this.updatePointerIndex(pointerIndex);
if (this.ctrlPressed)
this.updateMode("custom");
}
},
changeSaturation: function (direction) {
// increase or decrease by 5 if ctrl is pressed, otherwise jsut 1
let factor = 1;
if (this.ctrlPressed == true)
factor = 5;
// Get current color and update saturation accordingly.
const currentColor = this.colors[this.selectedPointerIndex];
let newSaturation = (direction == "ArrowDown") ? currentColor.saturation + factor : currentColor.saturation - factor;
// value can only be betwen 0 and 100, no need to loop
newSaturation = Math.max(0, Math.min(100, newSaturation));
// merge new values with old current and overwrite degrees
let newColor = Object.assign(currentColor, {
saturation: newSaturation
});
// get position for the new values
newColor = Object.assign(newColor, this.getPointerPosition(newColor));
// update color picker then update other pickers
this.updateColor(this.selectedPointerIndex, newColor);
this.$parent.$emit('updateOtherPointers');
},
changeHue: function (direction) {
// increase or decrease by 5 if ctrl is pressed, otherwise jsut 1
let factor = 1;
if (this.ctrlPressed == true)
factor = 5;
// Get current color and update hue accordingly.
const currentColor = this.colors[this.selectedPointerIndex];
let newHue = (direction == "ArrowLeft") ? currentColor.degrees + factor : currentColor.degrees - factor;
// value can only be betwen 0 and 360
if (newHue > 360)
newHue = 0;
if (newHue < 0)
newHue = 360;
// merge new values with old current and overwrite degrees
let newColor = Object.assign(currentColor, {
degrees: newHue
});
// get position for the new values
newColor = Object.assign(newColor, this.getPointerPosition(newColor));
// update current color then update other colors
this.updateColor(this.selectedPointerIndex, newColor);
this.$parent.$emit('updateOtherPointers');
},
getPointerPosition: function (currentColor) {
const wheel_radius = this.colorWheel.radius;
const angle = currentColor.degrees;
const distance = currentColor.saturation * wheel_radius / 100;
// radians start from right center turing count clockwis.
// hsl degress start top center turning clockwise.
// we need to adujst the angle to provide the right measuerments
const radians = (angle - 90) * (Math.PI / 180);
const left = wheel_radius + distance * Math.cos(radians);
const top = wheel_radius + distance * Math.sin(radians);
return {
top: top.toFixed(2),
left: left.toFixed(2)
}
},
movePointer: function (e) {
if (!this.pointer_clicked || this.index != this.selectedPointerIndex)
return;
const wheel = this.colorWheel;
let left = e.clientX - wheel.x;
let top = e.clientY - wheel.y;
// calcuate distance of the picker dot from color wheel
const dx = wheel.radius - left;
const dy = wheel.radius - top;
let distance = Math.sqrt(dx * dx + dy * dy);
// get angle so we can get coords once mouse outside color wheel
let angle = Math.atan2(dy, dx);
angle = angle < 0 ? (angle += Math.PI * 2) : angle;
if (distance > wheel.radius) {
left = wheel.radius - wheel.radius * Math.cos(angle);
top = wheel.radius - wheel.radius * Math.sin(angle);
}
// Dont make distance greater than radius
if (distance >= wheel.radius)
distance = wheel.radius;
let saturation = distance * 100 / wheel.radius;
// -90 is to start from top center to avoid discrepancy between circle start point
// and HSL start point
let hslDegree = angle * 180 / Math.PI - 90;
// after 270 degrees hsl will be a negative value starting from -90 to 0
if (hslDegree < 0)
hslDegree = 270 + (90 - Math.abs(hslDegree));
let color = {
degrees: Math.round(hslDegree),
saturation: Math.round(saturation),
lightness: 50,
left: left.toFixed(2),
top: top.toFixed(2)
}
this.updateColor(this.selectedPointerIndex, color);
this.$parent.$emit('updateOtherPointers');
},
getstyle: function () {
if (this.colors[this.index] == undefined)
return;
const mode = this.selectedPickerMode;
const selectedIndex = this.selectedPointerIndex;
const anchorColor = this.colors[selectedIndex];
const pointer = this.index;
const separation = this.pointerSepration[mode];
// We need to loop through the array values. i.e if we reach the end start again to get all values
let separationValues = [];
if (this.index < selectedIndex)
separationValues = [separation.slice(selectedIndex + 1), separation.slice(0, this.index + 1)];
else
separationValues = this.pointerSepration[mode].slice(selectedIndex + 1, this.index + 1);
// Calculate hue degree by accumlating previous values in array
let seprationDegree = 0;
if (separationValues.length != 0)
seprationDegree = separationValues.reduce((acc, value) => acc + value);
if (pointer != selectedIndex) {
let newColor = {};
newColor.seprationDegree = seprationDegree;
if (mode != 'mono') {
// change hue degree and keep within 360 for tinyscript
let degrees = anchorColor.degrees + seprationDegree;
if (degrees > 360)
degrees = degrees - 360;
newColor.degrees = degrees;
newColor.saturation = anchorColor.saturation;
} else {
// for monochrome change saturation other change hue degree
let newSaturation = anchorColor.saturation
if (selectedIndex != 0)
newSaturation = 100 - anchorColor.saturation;
// For mono colors, the factor is third. Once we get it we can subtract
// from anchor color to get new one. (factor is negative to move forward when subtracting
// and backgward when positive)
const third = newSaturation * separation[selectedIndex][pointer];
let saturation = anchorColor.saturation - (third);
// Saturation can not exceed 100% or be less than 0
if (saturation > 100)
saturation = 100;
if (saturation < 0)
saturation = 0;
newColor.degrees = anchorColor.degrees;
newColor.saturation = saturation;
}
newColor.lightness = this.colors[pointer].lightness;
let coord = this.getPointerPosition(newColor);
newColor = Object.assign(newColor, coord);
this.updateColor(pointer, newColor);
}
},
},
computed: {
mapState(["selected_picker_mode", "pointer_count", "pointer_sepration", "colors", "ctrl_pressed", "is_custom", "selected_pointer_index"]),
selectedColor: function () {
return this.colors[this.selectedPointerIndex];
},
left: function () {
if (this.colors[this.index] == undefined)
return 0;
return this.colors[this.index].left + "px";
},
top: function () {
if (this.colors[this.index] == undefined)
return 0;
return this.colors[this.index].top + "px";
},
background: function () {
if (this.enlarge == false)
return '';
let c = this.selectedColor;
return `hsl(${c.degrees}, ${c.saturation}%, ${c.lightness}%)`
}
},
watch: {
selectedPickerMode: function () {
this.$parent.$emit('updateOtherPointers');
this.$parent.$emit('updateFirstPointer');
},
pointer_clicked: function(isClicked){
this.updateMoving(isClicked);
}
},
destroyed: function () {
this.removeColor(this.index);
}
});
Vue.component('color-wheel', {
template: "#color-wheel-template",
data: () => {
return {
color_wheel: {},
lightness_picker_el: null,
timeout: null
}
},
created: function () {
// attach events to move picker inside color wheel
document.addEventListener("mousedown", e => {
if (e.target.id == 'lightness-picker')
this.lightness_clicked = true;
});
document.addEventListener("mouseup", e => this.lightness_clicked = false);
document.addEventListener("mousemove", this.moveLightness);
// update wheel position and size on window resize
window.addEventListener("resize", this.updateWheelPosition);
// update selected index when number is pressed
window.addEventListener('keydown', event => {
switch (event.code) {
case "Digit1":
case "Digit2":
case "Digit3":
case "Digit4":
const index = parseInt(event.key);
if (index <= this.pointerCount)
this.updatePointerIndex(index - 1);
break;
}
});
},
mounted: function () {
// get color wheel dimensions, position and radius
this.color_wheel = this.$el.querySelector("#color-wheel").getBoundingClientRect();
this.color_wheel.radius = this.color_wheel.height / 2;
this.updateMode("comple");
this.lightness_picker_el = this.$el.querySelector("#lightness-picker");
this.$el.addEventListener('wheel', this.changeLightness);
document.querySelector("#app").addEventListener("scroll", this.updateWheelPosition);
},
methods: {
mapMethods(["updateColor", "updatePointerIndex", "initColors", "updateMode", "removeColor"]),
changeLightness: function (e) {
let rotate = this.currentColor.lightnessRotate;
let factor = (this.ctrlPressed) ? 5 : 1;
let newRotate = 0;
if (e.deltaY < 0)
newRotate = rotate + factor;
else
newRotate = rotate - factor;
if (newRotate < 0)
newRotate = 360;
if (newRotate > 360)
newRotate = 0;
// get lightness percentage. if over 180
const lightnessRotate = (newRotate > 180) ? 360 - newRotate : newRotate;
const lightness = lightnessRotate * 100 / 180;
this.updateColor(this.selectedPointerIndex, {
lightness: Math.round(lightness),
lightnessRotate: Math.round(newRotate)
});
// emit event to enlarge picker
this.$emit('lightnessChange');
e.preventDefault();
},
moveLightness: function (e) {
if (!this.lightness_clicked)
return;
let left = e.clientX - this.color_wheel.x;
let top = e.clientY - this.color_wheel.y;
const dx = this.color_wheel.radius - left;
const dy = this.color_wheel.radius - top;
// get angle
let angle = Math.atan2(dy, dx);
// -90 to start from from top center
let degrees = angle * 180 / Math.PI - 90;
// the first quarter will be over positive and the rest of the circle will negative degrees.
// Adjust for that case
if (degrees < 0)
degrees = 360 - Math.abs(degrees);
// get lightness percentage. if over 180
const lightnessRotate = (degrees > 180) ? 360 - degrees : degrees;
const lightness = lightnessRotate * 100 / 180;
// emit event to enlarge picker
this.$emit('lightnessChange');
this.updateColor(this.selectedPointerIndex, {
lightness: Math.round(lightness),
lightnessRotate: Math.round(degrees)
});
},
updateWheelPosition: function (e) {
clearTimeout(this.timeout);
this.timeout = setTimeout(() => {
this.color_wheel = this.$el.querySelector("#color-wheel").getBoundingClientRect();
this.color_wheel.radius = this.color_wheel.height / 2;
}, 500);
}
},
computed: {
mapState(["colors", "pointer_count", "selected_pointer_index", "selected_picker_mode", "ctrl_pressed", "pointer_moving"]),
currentColor() {
return this.colors[this.selectedPointerIndex];
},
lightnessStyle: function () {
let c = this.currentColor;
const start = `hsl(${c.degrees}, ${c.saturation}%, 0%)`;
const middle = `hsl(${c.degrees}, ${c.saturation}%, 50%)`;
const end = `hsl(${c.degrees}, ${c.saturation}%, 90%)`;
return {
backgroundImage: `linear-gradient(180deg, ${start}, ${middle}, ${end})`
}
},
lightnessRotation: function () {
const rotate = this.currentColor.lightnessRotate;
//const rotate = lightness * 180 / 100;
return {
transform: `rotate(${rotate}deg)`
}
},
pointerCount() {
return store.pointer_count();
}
}
});
Vue.component('color-theory-wheel', {
template: "#color-theory-wheel-template",
props: {
mode: "split",
title: "",
static: false,
wheelStyle: ""
},
data: () => {
return {
current_hover: 0,
count: 12
}
},
methods: {
processHover: function (index) {
if (this.static == true)
return [];
this.current_hover = index;
}
},
computed: {
mapState(["wheel_demo_indices"]),
modeIndices: function () {
return this.wheelDemoIndices[this.mode];
},
highlightIndices: function () {
if (this.modeIndices == undefined)
return [];
return this.modeIndices.map(i => {
let newCount = this.current_hover + i
if (newCount >= this.count)
newCount = newCount - this.count;
return newCount;
})
}
},
watch: {
mode: function (newMode) {
switch (newMode) {
case "primary":
case "secondary":
case "tertiary":
case "tempreature":
this.current_hover = 0;
break;
}
}
}
});
Vue.component('colors-display', {
template: "#colors-display-template",
data: () => {
return {
entered: -1,
dragged: -1,
colors_models: [{
name: "hsl",
value: ""
}, {
name: "rgb",
value: ""
}, {
name: "hex",
value: ""
}, {
name: "hsv",
value: ""
}],
current_model_index: 0,
copy_message: ""
}
},
mounted: function () {
const clipboard = new ClipboardJS('.copy-value');
clipboard.on('success', e => {
this.copy_message = "copied!"
e.clearSelection();
});
clipboard.on('error', e => {
this.copy_message = "fAILED!"
});
},
methods: {
mapMethods(['swapColors']),
getBackground: function (index) {
const c = this.colors[index];
return {
"background-color": c.hsl
}
},
dragstart: function (index, e) {
this.dragged = index;
e.dataTransfer.setData('text/plain', 'dummy');
},
dragend: function () {
this.swapColors(this.dragged, this.entered);
this.entered = -1;
},
dragenter: function (index) {
this.entered = index;
},
colorModelSpinner: function () {
const currentIndex = this.current_model_index;
const models = this.colors_models;
let nextIndex = currentIndex + 1;
if (nextIndex > models.length - 1)
nextIndex = 0;
this.current_model_index = nextIndex;
},
},
computed: {
mapState(["colors", "selected_pointer_index", ]),
tinycolor: function () {
const c = this.colors[this.selectedPointerIndex];
return tinycolor(`hsl(${c.degrees}, ${c.saturation}%, ${c.lightness}%)`);
},
currentModel: function () {
const model_index = this.current_model_index;
return this.colorsModelsValues[model_index];
},
colorsModelsValues: function () {
//const colorObject = {};
return this.colors_models.map(c => {
return {
name: c.name,
value: this[c.name]
};
});
},
hsl: function () {
return this.tinycolor.toHslString();
},
rgb: function () {
return this.tinycolor.toRgbString();
},
hex: function () {
return this.tinycolor.toHexString();
},
hsv: function () {
return this.tinycolor.toHsvString();
},
pointerCount: function () {
return store.pointer_count();
},
arrowStyle: function () {
const pointer = this.selectedPointerIndex;
const width = 100 / this.pointerCount;
const left = (width * pointer) + (width / 2);
return {
left: `${left}%`
}
}
}
});
Vue.component('pages-nav', {
template: '#pages-nav-template',
data() {
return {
current_page: 0,
pages: [],
hovered_dot_index: -1,
hovered_dot_position: null,
title_position: 0,
container: null
};
},
created: function () {
window.addEventListener('keydown', event => {
switch (event.code) {
case "PageUp":
if(this.current_page > 0)
this.current_page--;
event.preventDefault();
break;
case "PageDown":
if(this.current_page < 2)
this.current_page++;
event.preventDefault();
break;
}
});
},
mounted() {
this.container = document.querySelector("#app");
let divs = document.querySelectorAll("#app > div");
for (i = 0; i < divs.length; ++i) {
let element = divs[i];
const obj = {
index: i,
title: element.getAttribute("data-title"),
element: element
}
this.pages.push(obj);
}
},
methods: {
dotHover: function (index, event) {
this.hovered_dot_index = index;
const offsetTop = event.target.offsetTop;
const height = event.target.getBoundingClientRect().height;
this.title_position = offsetTop + (height / 2);
}
},
computed: {
pageTitle: function () {
if (this.hovered_dot_index == -1)
return "";
return this.pages[this.hovered_dot_index].title;
}
},
watch: {
current_page: function (newVal) {
let height = this.container.getBoundingClientRect().height;
this.container.scrollTo({
top: height * newVal,
left: 0,
behavior: 'smooth'
});
}
}
});
Vue.component('about', {
template: '#about-template',
data() {
return {
info: ['This project provides a complete, easy and intuitive palette generator. Using the color wheel, you can create any type of palette and with live preview you can see how colors would match (or not) on a real website.',
'In addition, keyboard shortcuts and mouse wheel are used to fine-tune selection and provide greater control over the end results.',
'I have added a color theory summary to provide a general understanding of how colors are used.'
],
shortcuts: [{
keys: ['up', '/', 'down'],
desc: "Decrease / Increase saturation by 1%"
},
{
keys: ['left', '/', 'right'],
desc: "Increase / Decrease hue by 1 degree"
},
{
keys: ['ctrl', '+', 'up', '/', 'down'],
desc: "Decrease / Increase saturation by 5%"
},
{
keys: ['ctrl', '+', 'left', '/', 'right'],
desc: "Increase / Decrease hue by 5 degrees"
},
{
keys: ["mouse-wheel"],
desc: "Increase / decrease lightness by 1 degree"
},
{
keys: ["Ctrl", "+", "mouse-wheel"],
desc: "Increase / decrease lightness by 5 degrees"
},
{
keys: ["1", "2", "3", "4"],
desc: "Select color pointer"
},
{
keys: ["ctrl", "+", "mouse-click-left"],
desc: "Custom color mode"
},
{
keys: ["page down", "/", "page up"],
desc: "Move between sections"
},
{
keys: ["ctrl", "+", "m"],
desc: "Cycle between color modes"
}
],
made_with: [{
title: "vue.js",
link: "https://vuejs.org/"
},
{
title: "Bootstrap",
link: "https://getbootstrap.com/"
},
{
title: "TinyColor",
link: "https://bgrins.github.io/TinyColor/"
},
{
title: "Charts.js",
link: "https://www.chartjs.org/"
},
{
title: "clipboard.js",
link: "https://clipboardjs.com/"
},
{
title: "Font Awesome",
link: "https://fontawesome.com/"
},
{
title: "Google fonts",
link: "https://fonts.google.com/"
}
]
};
},
mounted() {
},
methods: {
},
computed: {
}
});
Vue.component('chart', {
template: '<canvas ref="myChart" :width="width" :height="height"></canvas>',
data() {
return {
chart: null
};
},
props: {
type: {
type: String,
default: "line"
},
width: {
type: Number,
validator: value => value > 0,
default: 651
},
height: {
type: Number,
validator: value => value > 0,
default: 350
},
labels: Array,
datasets: {
type: Array,
required: true
},
options: Object
},
mounted() {
this.chart = new Chart(this.$refs.myChart, {
type: this.type,
data: {
labels: this.labels,
datasets: this.datasets
},
options: this.options,
});
},
beforeDestroy() {
if (this.chart) {
this.chart.destroy()
}
},
watch: {
datasets(newDatasets) {
this.chart.data.datasets = newDatasets;
this.chart.update();
}
},
});
Vue.component('demo', {
template: "#demo-template",
data: () => {
return {
settings: {
darkmode: false,
default_sidebar_bg: false,
hide_text: false
},
chart: null,
admin_cards: [{
title: "Total traffic",
number: "214,126",
percentage: "5.1",
icon_class: "fas fa-eye"
},
{
title: "New users",
number: "12,186",
percentage: "2.6",
icon_class: "fas fa-users"
},
{
title: "Sales",
number: "3,186",
percentage: "8.1",
icon_class: "fas fa-dollar-sign"
}
],
page_visits: [{
name: "/color-wheel/",
visitors: "7,548",
unique: "657",
rate: "31,85%",
direction: "up"
}, {
name: "/color-wheel/theory.html",
visitors: "4,548",
unique: "201",
rate: "40,25%",
direction: "down"
}, {
name: "/color-wheel/index.html",
visitors: "3,268",
unique: "321",
rate: "35,25%",
direction: "up"
}, {
name: "/color-wheel/about.html",
visitors: "2,548",
unique: "186",
rate: "42,25%",
direction: "down"
}, ],
social_ref: [{
name: "facebook",
visitors: "7,548",
percentage: "60"
}, {
name: "codepen",
visitors: "10,548",
percentage: "70"
}, {
name: "google",
visitors: "6,548",
percentage: "40"
}, {
name: "instagram",
visitors: "2,548",
percentage: "25"
}],
line_chart: {
source: "traffic",
labels: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
traffic_chart: [{
label: 'Visitors',
fill: false,
data: [131800, 131150, 141004, 151042, 161074, 141878, 161768, 175987, 181897, 192872, 203224, 214126],
borderColor: "white",
borderWidth: 5,
pointRadius: 0,
borderCapStyle: "round"
}],
sales_chart: [{
label: 'Sales',
fill: false,
data: [2015, 45897, 4598, 15042, 16074, 45987, 12356, 78971, 87865, 12587, 14963, 12008],
borderColor: "white",
borderWidth: 5,
pointRadius: 0,
borderCapStyle: "round"
}],
options: {
tooltips: {
mode: 'index',
intersect: false
},
legend: {
display: false
},
animation: {
onComplete: function (ss) {
//console.log(ss);
}
},
scales: {
yAxes: [{
ticks: {
callback: function (value, index, values) {
if (value == 0)
return 0;
return value.toString().slice(0, -3) + 'k';
},
padding: 10,
fontColor: "lightgray"
},
gridLines: {
borderDash: [2, 4],
zeroLineWidth: 0,
drawBorder: false,
}
}],
xAxes: [{
ticks: {
fontColor: "lightgray"
}
}]
}
}
}
}
},
mounted: function () {
this.style = document.documentElement.style;
},
methods: {
updateData: function (type) {
Vue.set(this.line_chart, "source", type);
},
mostReadable: function (color, grades) {
const matchAgainst = Object.values(grades);
return tinycolor.mostReadable(color, matchAgainst).toHslString();
},
getNewStyle: function () {
if (this.selectedPickerMode == "single" || this.colors.length < 2)
return;
const newColors = {};
const first = this.colors[0];
const second = this.colors[1];
const third = this.colors[2] || {};
const fourth = this.colors[3] || {};
let firstColor = tinycolor(first.hsl);
// Header bg color and text color
newColors['--demo-primary-bg'] = first.hsl;
newColors['--demo-primary-color'] = this.mostReadable(first.hsl, first.palette);
// Button colors (active, hover, .. etc)
newColors['--demo-btn-bg'] = first.palette.darker;
newColors['--demo-btn-border'] = first.palette.darkest;
newColors['--demo-btn-color'] = (firstColor.isDark()) ? "white" : "black";
newColors['--demo-btn-active-color'] = this.mostReadable(first.palette.lighter, first.palette);
newColors['--demo-btn-active'] = first.palette.lighter;
newColors['--demo-btn-active-border'] = first.palette.darkest;
// header color
newColors['--demo-header-card'] = second.hsl;
newColors['--demo-header-card-text-1'] = this.mostReadable(second.hsl, second.palette);
newColors['--demo-header-card-text-2'] = this.mostReadable(second.hsl, second.palette);
newColors['--demo-text-success'] = this.mostReadable(second.hsl, first.palette);
switch (this.selectedPickerMode) {
case "comple":
if (this.settings.default_sidebar_bg == false) {
const sidebarHover = this.mostReadable(first.hsl, first.palette);
newColors['--demo-sidebar-bg'] = first.palette.lighter;
newColors['--demo-sidebar-hover'] = sidebarHover;
newColors['--demo-sidebar-hover-color'] = this.mostReadable(sidebarHover, first.palette);
newColors['--demo-sidebar-text-color'] = (firstColor.isDark()) ? "white" : "black";
}
break;
case "square":
case "tetra":
if(this.colors.length < 4)
return;
newColors['--demo-scrollbar-foreground'] = fourth.palette.darkest;
newColors['--demo-scrollbar-background'] = fourth.palette.lighter;
case "split":
case "analog":
case "mono":
case "tri":
case "square":
case "tetra":
if(this.colors.length < 3)
return;
const thirdColor = tinycolor(third.hsl);
if (this.settings.default_sidebar_bg == false) {
const sidebarHover = this.mostReadable(third.hsl, second.palette);
newColors['--demo-sidebar-bg'] = third.palette.lighter;
newColors['--demo-sidebar-hover'] = this.mostReadable(third.hsl, third.palette);
newColors['--demo-sidebar-hover-color'] = this.mostReadable(sidebarHover, third.palette);
newColors['--demo-sidebar-text-color'] = (thirdColor.isDark()) ? "white" : "black";
}
break;
}
return newColors
}
},
computed: {
mapState(["colors", "selected_picker_mode"]),
linechartDataset: function () {
if (this.line_chart.source == 'traffic')
return this.line_chart.traffic_chart
return this.line_chart.sales_chart;
},
}
});
new Vue({
el: "#app",
data: {
wheel_mode: "comple",
hide_text: false
},
created: function () {
window.addEventListener('keyup', e => {
this.updateCtrl(false);
});
window.addEventListener('keydown', e => {
if (e.ctrlKey == true)
this.updateCtrl(true);
});
window.addEventListener('keydown', e => {
if (e.code == 'KeyM' && this.ctrlPressed)
this.modeSpinner();
});
},
methods: {
updateMode: mutations.updateMode,
updateCtrl: mutations.updateCtrl,
modeSpinner: function () {
if (this.isCustom == true) {
this.updateMode(this.selectedPickerMode)
return;
}
const currentMode = this.selectedPickerMode;
const modeIndex = this.modes.findIndex(m => m.name == currentMode);
const nextIndex = (modeIndex + 1 > this.modes.length - 1) ? 0 : modeIndex + 1;
const nextMode = this.modes[nextIndex].name;
this.updateMode(nextMode);
},
cancelCustom: function () {
this.updateMode(this.selectedPickerMode);
}
},
computed: {
mapState(["picker_modes", "selected_picker_mode", "colors", "selected_pointer_index", "is_custom", "ctrl_pressed"]),
modes() {
let modes = [];
this.pickerModes.map(m => {
modes.push(m);
});
if (modes.length == 0)
return [];
return modes;
},
endColor: function () {
const c = this.colors[this.selectedPointerIndex];
return {
"background-color": `hsl(${c.degrees}, ${c.saturation}%, ${c.lightness}%)`
}
},
isStatic: function () {
let static = false;
switch (this.wheel_mode) {
case "primary":
case "secondary":
case "tertiary":
case "tempreature":
static = true;
break;
}
return static;
},
pickerModeTitle: function () {
return store.picker_mode_title();
}
}
})