Skip to content

Commit

Permalink
Merge pull request #227 from oddbird/swap-colors
Browse files Browse the repository at this point in the history
Add button and drag to swap colors
  • Loading branch information
jgerigmeyer authored Feb 5, 2025
2 parents 6d1e4e0 + ad9a6f9 commit b653d98
Show file tree
Hide file tree
Showing 9 changed files with 130 additions and 10 deletions.
41 changes: 40 additions & 1 deletion src/lib/components/colors/Header.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import CopyButton from '$lib/components/util/CopyButton.svelte';
import type { ColorFormatId } from '$lib/constants';
import { switchColors } from '$lib/stores';
import { getSpaceFromFormatId } from '$lib/utils';
interface Props {
Expand All @@ -12,6 +13,8 @@
format: ColorFormatId;
}
const CUSTOM_MIMETYPE = 'text/odd';
let { type, color, format }: Props = $props();
let targetSpace = $derived(getSpaceFromFormatId(format));
Expand All @@ -20,6 +23,7 @@
let editing = $state(false);
let inputValue = $state('');
let hasError = $state(false);
let isDragging = false;
// When not editing, sync input value with color (e.g. when sliders change)
$effect(() => {
Expand Down Expand Up @@ -80,6 +84,32 @@
break;
}
};
const onDragStart = (event: DragEvent) => {
isDragging = true;
if (!event.dataTransfer) return;
event.dataTransfer.clearData();
event.dataTransfer.setData(CUSTOM_MIMETYPE, type);
};
const onDrop = (event: DragEvent | undefined) => {
const droppedType = event?.dataTransfer?.getData(CUSTOM_MIMETYPE);
const dragIsFromOther =
type === 'fg' ? droppedType === 'bg' : droppedType === 'fg';
if (dragIsFromOther) {
switchColors();
}
};
const makeDropable = (event: DragEvent) => {
// DataTransfer values are not available on dragover, but because the types
// of items is available, we can use a custom mimetype to check if a swatch
// is the drag target.
if (!isDragging && event?.dataTransfer?.types.includes(CUSTOM_MIMETYPE)) {
// Cancelling the event signals that the dragged item can be dropped here.
event.preventDefault();
}
};
</script>

<div
Expand All @@ -88,7 +118,16 @@
data-column="tool"
data-needs-changes={hasError}
>
<div class="swatch {type}"></div>
<div
role="complementary"
class="swatch {type}"
draggable="true"
ondrop={onDrop}
ondragenter={makeDropable}
ondragover={makeDropable}
ondragstart={onDragStart}
ondragend={() => (isDragging = false)}
></div>
<label for="{type}-color" data-label>
{displayType} Color
</label>
Expand Down
9 changes: 9 additions & 0 deletions src/lib/components/colors/SwitchButton.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<script lang="ts">
import Icon from '$lib/components/util/Icon.svelte';
import { switchColors } from '$lib/stores';
</script>

<button type="button" onclick={switchColors} data-btn="icon switch">
<Icon name="switch" />
<span class="sr-only">Swap colors</span></button
>
15 changes: 12 additions & 3 deletions src/lib/components/colors/index.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
import Sliders from '$lib/components/colors/Sliders.svelte';
import SupportWarning from '$lib/components/colors/SupportWarning.svelte';
import { bg, fg, format } from '$lib/stores';
import SwitchButton from './SwitchButton.svelte';
</script>

<h2 class="sr-only">Check the contrast ratio between two colors</h2>
Expand All @@ -13,12 +15,14 @@
<form data-form="contrast-checker" data-layout="color-form">
<Header type="bg" color={bg} format={$format} />
<Sliders type="bg" color={bg} format={$format} />

<div data-actions="swap-colors">
<SwitchButton />
</div>
<Header type="fg" color={fg} format={$format} />
<Sliders type="fg" color={fg} format={$format} />
</form>

<div data-layout="split">
<div data-layout="color-formats">
<Formats type="bg" color={$bg} format={$format} />
<Formats type="fg" color={$fg} format={$format} />
</div>
Expand All @@ -31,6 +35,11 @@
}
[data-layout] {
column-gap: var(--triple-gutter);
column-gap: var(--gutter);
}
[data-actions='swap-colors'] {
display: grid;
place-content: center;
}
</style>
2 changes: 2 additions & 0 deletions src/lib/components/util/Icon.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
import OddBird from '$lib/icons/OddBird.svelte';
import Twitter from '$lib/icons/Twitter.svelte';
import Warning from '$lib/icons/Warning.svelte';
import Switch from '$src/lib/icons/Switch.svelte';
const icons: Record<string, Component> = {
check: Check,
Expand All @@ -25,6 +26,7 @@
oddbird: OddBird,
linkedin: LinkedIn,
mastodon: Mastodon,
switch: Switch,
};
interface Props {
Expand Down
17 changes: 17 additions & 0 deletions src/lib/icons/Switch.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<script lang="ts">
let props = $props();
</script>

<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 512 512"
width="26"
height="26"
{...props}
>
<path
id="switch"
data-name="switch"
d="M406.6 374.6l96-96c12.5-12.5 12.5-32.8 0-45.3l-96-96c-12.5-12.5-32.8-12.5-45.3 0s-12.5 32.8 0 45.3L402.7 224l-293.5 0 41.4-41.4c12.5-12.5 12.5-32.8 0-45.3s-32.8-12.5-45.3 0l-96 96c-12.5 12.5-12.5 32.8 0 45.3l96 96c12.5 12.5 32.8 12.5 45.3 0s12.5-32.8 0-45.3L109.3 288l293.5 0-41.4 41.4c-12.5 12.5-12.5 32.8 0 45.3s32.8 12.5 45.3 0z"
/>
</svg>
8 changes: 7 additions & 1 deletion src/lib/stores.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import {
REC_2020,
sRGB,
} from 'colorjs.io/fn';
import { writable } from 'svelte/store';
import { get, writable } from 'svelte/store';

// eslint-disable-next-line import/no-unresolved
import { browser, dev } from '$app/environment';
Expand Down Expand Up @@ -57,6 +57,12 @@ export const reset = () => {
fg.set(INITIAL_FG);
};

export const switchColors = () => {
const temp = get(bg);
bg.set(get(fg));
fg.set(temp);
};

/* c8 ignore next 5 */
if (browser && dev) {
bg.subscribe(($bg) => (window.bg = $bg));
Expand Down
3 changes: 3 additions & 0 deletions src/sass/config/scale/_ui.scss
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,6 @@ $icon-medium: 1.5em;
$ratio-width: 10rem;
$range-thumb-size: 1.35rem;
$range-input: 0.85rem;
$triangle-width: var(--shim);
$triangle-height: var(--shim-plus);
$switch-space: var(--double-gutter);
16 changes: 12 additions & 4 deletions src/sass/initial/_layout.scss
Original file line number Diff line number Diff line change
Expand Up @@ -69,20 +69,28 @@ body {
grid-template-columns: auto 1fr;
}

[data-layout~='split'] {
[data-layout~='color-formats'] {
display: grid;

@include config.above('sm-page-break') {
grid-template-columns: 1fr 1fr;
grid-template-columns: 1fr var(--switch-space) 1fr;
}
}

[data-content='formats'] {
@include config.above('sm-page-break') {
&:last-of-type {
grid-column: 3;
}
}
}

[data-layout='color-form'] {
@include config.above('sm-page-break') {
display: grid;
grid-template:
'bginput fginput' auto
'bgslide fgslide' auto / 1fr 1fr;
'bginput switch fginput' auto
'bgslide . fgslide' auto / 1fr var(--switch-space) 1fr;
}
}

Expand Down
29 changes: 28 additions & 1 deletion src/sass/patterns/_buttons.scss
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
/// # Button Pattern
/// @group buttons

@use '../config';

button {
font-family: inherit;
font-size: inherit;
Expand All @@ -25,7 +27,8 @@ button {
var(--btn-padding-inline, var(--gutter));
transition:
color var(--fast),
background-color var(--fast) transform var(--fast);
background-color var(--fast),
transform var(--fast);

&:hover,
&:focus {
Expand All @@ -47,3 +50,27 @@ button {
transform: scale(1.15);
}
}

[data-btn~='switch'] {
--icon-size: var(--icon-medium);

block-size: fit-content;
margin-block-end: var(--spacer);

@include config.below('sm-page-break') {
[data-icon] {
transform: rotate(90deg);
}
}

&:hover,
&:focus {
--outline-width: thin;

transform: var(--transform, rotate(180deg));

@media (prefers-reduced-motion: reduce) {
--transform: scale(1.1);
}
}
}

0 comments on commit b653d98

Please sign in to comment.