Skip to content

Commit 04ba438

Browse files
committed
Add Alpine.js color palette demo.
1 parent 1d85481 commit 04ba438

File tree

4 files changed

+1759
-0
lines changed

4 files changed

+1759
-0
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ with.
1010

1111
## My JavaScript Demos - I Love JavaScript!
1212

13+
* [Color Palette Utility In Alpine.js](https://bennadel.github.io/JavaScript-Demos/demos/color-palette)
1314
* [Using Both Tab And Arrow Keys For Keyboard Navigation](https://bennadel.github.io/JavaScript-Demos/demos/tab-group)
1415
* [Using Margins With Four-Sided Positioning In CSS](https://bennadel.github.io/JavaScript-Demos/demos/four-sided-margins)
1516
* [Nesting The pointer-events Property In CSS](https://bennadel.github.io/JavaScript-Demos/demos/nested-pointer-events-css)

demos/color-palette/index.htm

Lines changed: 176 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,176 @@
1+
<!doctype html>
2+
<html lang="en">
3+
<head>
4+
<meta charset="utf-8" />
5+
<meta name="viewport" content="width=device-width, initial-scale=1" />
6+
<title>
7+
Color Palette Utility In Alpine.js
8+
</title>
9+
<link rel="stylesheet" type="text/css" href="./main.css" />
10+
</head>
11+
<body
12+
x-data="App"
13+
@hashchange.window="handleGlobalHashchange( $event )"
14+
@keydown.window="handleGlobalKeydown( $event )"
15+
@dragover.document="handleGlobalDropEvents( $event )"
16+
@drop.document="handleGlobalDropEvents( $event )"
17+
@paste.document="handlePaste( $event )"
18+
@resize.window.debounce.250ms="handleResize( $event )">
19+
20+
<header class="masthead">
21+
<h1 class="masthead__title">
22+
Color Palette Utility In Alpine.js
23+
</h1>
24+
25+
<button @click="addSwatch()" class="masthead__add">
26+
Add Color
27+
</button>
28+
29+
<a
30+
@click="downloadPaletteAsPNG( $event.currentTarget )"
31+
download="palette.png"
32+
class="masthead__download">
33+
PNG
34+
</a>
35+
<a
36+
@click="downloadPaletteAsSVG( $event.currentTarget )"
37+
download="palette.svg"
38+
class="masthead__download">
39+
SVG
40+
</a>
41+
</header>
42+
43+
<main class="panels">
44+
<template x-for="( swatch, i ) in palette" :key="swatch.id">
45+
46+
<div class="panels__item">
47+
48+
<!-- Begin: Panel. -->
49+
<div
50+
tabindex="0"
51+
@focusin="handleFocusin( i )"
52+
class="panel"
53+
:class="{
54+
'panel--active': ( activeSwatchIndex === i ),
55+
'panel--narrow': isNarrowPanels
56+
}"
57+
:style="{ backgroundColor: swatch.hex }">
58+
59+
<h2 class="panel-name">
60+
<span class="panel-name__hex"
61+
x-text="swatch.hex">
62+
</span>
63+
<span class="panel-name__hsl">
64+
<span x-text="swatch.hue"></span> &middot;
65+
<span x-text="swatch.saturation"></span> &middot;
66+
<span x-text="swatch.lightness"></span>
67+
</span>
68+
</h2>
69+
70+
<div class="panel-settings">
71+
<input
72+
type="range"
73+
x-model.number="swatch.hue"
74+
@keydown="handleRangeKeydown( $event )"
75+
@input="handleRangeInput( $event, swatch )"
76+
min="0"
77+
max="360"
78+
step="1"
79+
class="panel-settings__range hue"
80+
/>
81+
<input
82+
type="range"
83+
x-model.number="swatch.saturation"
84+
@keydown="handleRangeKeydown( $event )"
85+
@input="handleRangeInput( $event, swatch )"
86+
min="0"
87+
max="100"
88+
step="0.1"
89+
class="panel-settings__range saturation"
90+
/>
91+
<input
92+
type="range"
93+
x-model.number="swatch.lightness"
94+
@keydown="handleRangeKeydown( $event )"
95+
@input="handleRangeInput( $event, swatch )"
96+
min="0"
97+
max="100"
98+
step="0.1"
99+
class="panel-settings__range lightness"
100+
/>
101+
</div>
102+
103+
<div class="panel-tools">
104+
<button @click="moveSwatchLeft( i )" class="panel-tools__button">
105+
<svg>
106+
<title>Arrow Left</title>
107+
<use xlink:href="#arrow-left"></use>
108+
</svg>
109+
</button>
110+
<button
111+
@click="toggleLock( i )"
112+
class="panel-tools__button"
113+
:class="{
114+
'panel-tools__button--locked': swatch.isLocked
115+
}">
116+
<template x-if="swatch.isLocked">
117+
<svg>
118+
<title>Locked</title>
119+
<use xlink:href="#lock-locked"></use>
120+
</svg>
121+
</template>
122+
<template x-if="( ! swatch.isLocked )">
123+
<svg>
124+
<title>Unlocked</title>
125+
<use xlink:href="#lock-unlocked"></use>
126+
</svg>
127+
</template>
128+
</button>
129+
<button @click="removeSwatch( i )" class="panel-tools__button">
130+
<svg>
131+
<title>Remove</title>
132+
<use xlink:href="#trash"></use>
133+
</svg>
134+
</button>
135+
<button @click="moveSwatchRight( i )" class="panel-tools__button">
136+
<svg>
137+
<title>Arrow Right</title>
138+
<use xlink:href="#arrow-right"></use>
139+
</svg>
140+
</button>
141+
</div>
142+
143+
</div>
144+
<!-- End: Panel. -->
145+
146+
</div>
147+
148+
</template>
149+
</main>
150+
151+
<!-- Begin: SVG sprite sheet (https://streamlinehq.com). -->
152+
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" style="display: none ;">
153+
<symbol id="lock-locked" viewBox="0 0 24 24">
154+
<path d="M19.5 9.5h-0.75V6.75a6.75 6.75 0 0 0 -13.5 0V9.5H4.5a2 2 0 0 0 -2 2V22a2 2 0 0 0 2 2h15a2 2 0 0 0 2 -2V11.5a2 2 0 0 0 -2 -2Zm-7.5 9a2 2 0 1 1 2 -2 2 2 0 0 1 -2 2ZM16.25 9a0.5 0.5 0 0 1 -0.5 0.5h-7.5a0.5 0.5 0 0 1 -0.5 -0.5V6.75a4.25 4.25 0 0 1 8.5 0Z" fill="currentColor" stroke-width="1"></path>
155+
</symbol>
156+
<symbol id="lock-unlocked" viewBox="0 0 24 24">
157+
<path d="M19.5 9.5h-0.75V6.75A6.75 6.75 0 0 0 5.53 4.81a1.25 1.25 0 0 0 2.4 0.72 4.25 4.25 0 0 1 8.32 1.22V9a0.5 0.5 0 0 1 -0.5 0.5H4.5a2 2 0 0 0 -2 2V22a2 2 0 0 0 2 2h15a2 2 0 0 0 2 -2V11.5a2 2 0 0 0 -2 -2Zm-7.5 9a2 2 0 1 1 2 -2 2 2 0 0 1 -2 2Z" fill="currentColor" stroke-width="1"></path>
158+
</symbol>
159+
<symbol id="arrow-left" viewBox="0 0 24 24">
160+
<path d="M22.5 10.5H7a0.25 0.25 0 0 1 -0.25 -0.25v-3a1 1 0 0 0 -1.71 -0.71L0.29 11.29a1 1 0 0 0 0 1.42l4.78 4.77a1 1 0 0 0 0.71 0.3 1 1 0 0 0 1 -1v-3A0.25 0.25 0 0 1 7 13.5h15.5a1.5 1.5 0 0 0 0 -3Z" fill="currentColor" stroke-width="1"></path>
161+
</symbol>
162+
<symbol id="arrow-right" viewBox="0 0 24 24">
163+
<path d="m23.71 11.29 -4.78 -4.78a1 1 0 0 0 -1.09 -0.21 1 1 0 0 0 -0.62 0.92v3a0.25 0.25 0 0 1 -0.25 0.25H1.5a1.5 1.5 0 0 0 0 3H17a0.25 0.25 0 0 1 0.25 0.25v3a1 1 0 0 0 1 1 1 1 0 0 0 0.71 -0.3l4.78 -4.77A1.05 1.05 0 0 0 24 12a1 1 0 0 0 -0.29 -0.71Z" fill="currentColor" stroke-width="1"></path>
164+
</symbol>
165+
<symbol id="trash" viewBox="0 0 24 24">
166+
<path d="M19.5 7.5h-15A0.5 0.5 0 0 0 4 8v14a2 2 0 0 0 2 2h12a2 2 0 0 0 2 -2V8a0.5 0.5 0 0 0 -0.5 -0.5Zm-9.25 13a0.75 0.75 0 0 1 -1.5 0v-9a0.75 0.75 0 0 1 1.5 0Zm5 0a0.75 0.75 0 0 1 -1.5 0v-9a0.75 0.75 0 0 1 1.5 0Z" fill="currentColor" stroke-width="1"></path>
167+
<path d="M22 4h-4.75a0.25 0.25 0 0 1 -0.25 -0.25V2.5A2.5 2.5 0 0 0 14.5 0h-5A2.5 2.5 0 0 0 7 2.5v1.25a0.25 0.25 0 0 1 -0.25 0.25H2a1 1 0 0 0 0 2h20a1 1 0 0 0 0 -2ZM9 3.75V2.5a0.5 0.5 0 0 1 0.5 -0.5h5a0.5 0.5 0 0 1 0.5 0.5v1.25a0.25 0.25 0 0 1 -0.25 0.25h-5.5A0.25 0.25 0 0 1 9 3.75Z" fill="currentColor" stroke-width="1"></path>
168+
</symbol>
169+
</svg>
170+
<!-- End: SVG sprite sheet. -->
171+
172+
<script type="text/javascript" src="./main.js" defer></script>
173+
<script type="text/javascript" src="../../vendor/alpine/3.13.5/alpine.3.13.5.min.js" defer></script>
174+
175+
</body>
176+
</html>

demos/color-palette/main.css

Lines changed: 160 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,160 @@
1+
2+
html {
3+
box-sizing: border-box ;
4+
}
5+
html *,
6+
html *:before,
7+
html *:after {
8+
box-sizing: inherit ;
9+
}
10+
11+
html,
12+
body {
13+
margin: 0 ;
14+
padding: 0 ;
15+
min-height: 100vh ;
16+
}
17+
18+
body {
19+
display: flex ;
20+
flex-direction: column ;
21+
font-family: monospace ;
22+
font-size: 18px ;
23+
line-height: 1.4 ;
24+
}
25+
26+
button,
27+
input {
28+
font-family: inherit ;
29+
font-size: inherit ;
30+
}
31+
32+
button {
33+
background-color: #ffffff ;
34+
border: 1px solid #666666 ;
35+
border-radius: 3px ;
36+
padding: 7px 13px ;
37+
cursor: pointer ;
38+
}
39+
40+
.masthead {
41+
align-items: center ;
42+
background: #ffffff ;
43+
border-bottom: 1px solid #222222 ;
44+
display: flex ;
45+
flex: 0 0 auto ;
46+
gap: 20px ;
47+
padding: 10px 20px ;
48+
}
49+
.masthead__title {
50+
margin: 0 auto 0 0 ;
51+
white-space: nowrap ;
52+
}
53+
.masthead__add {
54+
padding: 10px 20px ;
55+
}
56+
.masthead__download {
57+
background-color: #333333 ;
58+
border: 1px solid #000000 ;
59+
border-radius: 3px ;
60+
color: #ffffff ;
61+
cursor: pointer ;
62+
padding: 7px 13px ;
63+
text-decoration: none ;
64+
}
65+
66+
.panels {
67+
display: flex ;
68+
flex: 1 1 auto ;
69+
}
70+
.panels__item {
71+
flex: 1 1 auto ;
72+
position: relative ;
73+
}
74+
75+
.panel {
76+
align-items: center ;
77+
justify-content: flex-end ;
78+
display: flex ;
79+
flex-direction: column ;
80+
inset: 0 ;
81+
padding: 20px ;
82+
position: absolute ;
83+
}
84+
.panel--active {
85+
box-shadow: inset 0px 0px 0px 7px #ffffff ;
86+
outline: 4px solid #000000 ;
87+
outline-offset: -4px ;
88+
}
89+
90+
.panel-name {
91+
background-color: #fafafa ;
92+
border-radius: 5px ;
93+
margin: 0 ;
94+
padding: 6px 12px 5px ;
95+
text-align: center ;
96+
}
97+
.panel-name__hex {
98+
color: #212121 ;
99+
display: block ;
100+
font-size: 26px ;
101+
}
102+
.panel-name__hsl {
103+
color: #999999 ;
104+
display: block ;
105+
font-size: 13px ;
106+
}
107+
108+
.panel-settings {
109+
margin: 10px 0px 10px 0px ;
110+
width: 100% ;
111+
}
112+
.panel-settings__range {
113+
display: block ;
114+
margin: 15px 0px ;
115+
width: 100% ;
116+
}
117+
118+
.panel-tools {
119+
display: flex ;
120+
gap: 15px ;
121+
justify-content: center ;
122+
width: 100% ;
123+
}
124+
.panel-tools__button {
125+
border: none ;
126+
border-radius: 30px ;
127+
cursor: pointer ;
128+
padding: 10px ;
129+
}
130+
.panel-tools__button--locked {
131+
background-color: #121212 ;
132+
color: #fafafa ;
133+
}
134+
.panel-tools__button svg {
135+
display: block ;
136+
height: 20px ;
137+
width: 20px ;
138+
}
139+
140+
/*
141+
For when the panels are narrow and the tools no longer fit.
142+
143+
Note: I had tried to do this with a CSS container query; however, it seems that the
144+
container queries do not play nicely with flexbox since the flexbox items are sized
145+
based on their contents and "containers" need to be sized based on their context (not
146+
their contents - at least, from what I am understanding).
147+
*/
148+
149+
.panel--narrow .panel-tools {
150+
align-items: center ;
151+
display: none ;
152+
flex-direction: column ;
153+
left: 0px ;
154+
position: absolute ;
155+
right: 0px ;
156+
top: 20px ;
157+
}
158+
.panel--narrow:hover .panel-tools {
159+
display: flex ;
160+
}

0 commit comments

Comments
 (0)