Skip to content

Commit 8dabc00

Browse files
committed
let you grab colors
1 parent 7aa5f5f commit 8dabc00

File tree

2 files changed

+65
-3
lines changed

2 files changed

+65
-3
lines changed

src/routes/theme/ColorCard.svelte

Lines changed: 45 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,12 @@
44
MaterialDynamicColors,
55
hexFromArgb,
66
} from "@material/material-color-utilities";
7+
import { createEventDispatcher } from "svelte";
78
export let fg: string;
89
export let bg: string;
910
export let scheme: DynamicScheme;
11+
export let grabbing: boolean;
12+
1013
type Color =
1114
| "primary"
1215
| "onPrimary"
@@ -45,19 +48,59 @@
4548
| "surfaceContainerHigh"
4649
| "surfaceContainerHighest"
4750
| "surfaceTint";
51+
52+
let state = 0;
53+
const dispatch = createEventDispatcher();
4854
$: bgColor = hexFromArgb(MaterialDynamicColors[bg as Color].getArgb(scheme));
4955
$: fgColor = hexFromArgb(MaterialDynamicColors[fg as Color].getArgb(scheme));
56+
$: if (!grabbing) state = 0;
5057
</script>
5158

52-
<div style="background-color: {bgColor}; color: {fgColor};">
59+
<div
60+
class="card"
61+
style="background-color: {bgColor}; color: {fgColor};"
62+
role={grabbing ? "button" : undefined}
63+
on:click={(e) => {
64+
if (state) {
65+
if (state == 2) {
66+
navigator.clipboard.writeText(bgColor);
67+
} else {
68+
navigator.clipboard.writeText(fgColor);
69+
}
70+
dispatch("grabbed");
71+
}
72+
}}
73+
on:mousemove={(e) => {
74+
if (grabbing) {
75+
const rect = e.currentTarget.getBoundingClientRect();
76+
const y = Math.min(Math.max(e.clientY - rect.top, 0), rect.height) / rect.height;
77+
state = y < 0.3 ? 1 : 2;
78+
}
79+
}}
80+
on:mouseleave={() => {
81+
state = 0;
82+
}}
83+
>
5384
<p class="m3-font-headline-small">{bg}</p>
5485
<p class="m3-font-body-large">{fg} text</p>
86+
{#if state}
87+
<div class="overlay" style:background-color={state == 2 ? bgColor : fgColor} />
88+
{/if}
5589
</div>
5690

5791
<style>
58-
div {
92+
.card {
5993
padding: 1rem;
6094
white-space: pre-wrap;
95+
position: relative;
96+
}
97+
.card[role="button"] {
98+
cursor: pointer;
99+
}
100+
.overlay {
101+
position: absolute;
102+
inset: 0;
103+
pointer-events: none;
61104
}
62105
p {
63106
margin: 0;

src/routes/theme/SchemeShowcase.svelte

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
import iconCopy from "@ktibow/iconset-material-symbols/content-copy-outline";
55
import iconLight from "@ktibow/iconset-material-symbols/light-mode-outline";
66
import iconDark from "@ktibow/iconset-material-symbols/dark-mode-outline";
7+
import iconGrab from "@ktibow/iconset-material-symbols/unarchive-outline";
78
import { onMount } from "svelte";
89
910
import StyleFromScheme from "$lib/misc/StyleFromScheme.svelte";
@@ -14,6 +15,7 @@
1415
export let schemeLight: DynamicScheme;
1516
export let schemeDark: DynamicScheme;
1617
let showDark = false;
18+
let grabbing = false;
1719
1820
const copyUsage = () =>
1921
navigator.clipboard.writeText(
@@ -35,7 +37,13 @@
3537
<h2 class="m3-font-title-large">Your scheme 🎉</h2>
3638
<div class="color-container">
3739
{#each pairs as [bgName, fgName]}
38-
<ColorCard scheme={showDark ? schemeDark : schemeLight} fg={fgName} bg={bgName} />
40+
<ColorCard
41+
scheme={showDark ? schemeDark : schemeLight}
42+
fg={fgName}
43+
bg={bgName}
44+
{grabbing}
45+
on:grabbed={() => (grabbing = false)}
46+
/>
3947
{/each}
4048
</div>
4149
<div class="buttons">
@@ -47,6 +55,17 @@
4755
<Icon icon={showDark ? iconLight : iconDark} />
4856
{showDark ? "Light" : "Dark"}
4957
</Button>
58+
{#if grabbing}
59+
<Button type="tonal" iconType="left" on:click={() => (grabbing = false)}>
60+
<Icon icon={iconGrab} />
61+
Stop grab
62+
</Button>
63+
{:else}
64+
<Button type="tonal" iconType="left" on:click={() => (grabbing = true)}>
65+
<Icon icon={iconGrab} />
66+
Grab
67+
</Button>
68+
{/if}
5069
</div>
5170
</div>
5271

0 commit comments

Comments
 (0)