Skip to content

Commit

Permalink
Add gamut selector
Browse files Browse the repository at this point in the history
  • Loading branch information
jamesnw committed Dec 11, 2024
1 parent 525812e commit 5c83b32
Show file tree
Hide file tree
Showing 8 changed files with 86 additions and 13 deletions.
45 changes: 45 additions & 0 deletions src/lib/components/GamutSelect.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
<script lang="ts">
import { GAMUTS } from '$lib/constants';
import { gamut } from '$lib/stores';
</script>

<div data-field="color-format">
<label for="color-format" data-label>Gamut</label>
<select name="color-format" id="color-format" bind:value={$gamut}>
{#each GAMUTS as gamut (gamut.format)}
{#if gamut}
<option value={gamut.format}>{gamut.name}</option>
{/if}
{/each}
</select>
</div>

<style lang="scss">
@use 'config';
[data-field='color-format'] {
align-items: center;
column-gap: var(--gutter);
display: grid;
grid-template:
'format-label' auto
'format-input' auto / 1fr;
justify-content: end;
@include config.above('sm-page-break') {
grid-template: 'format-label format-input' auto / 1fr minmax(10rem, auto);
}
}
label {
grid-area: format-label;
@include config.above('sm-page-break') {
text-align: right;
}
}
select {
grid-area: format-input;
}
</style>
2 changes: 2 additions & 0 deletions src/lib/components/Header.svelte
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
<script lang="ts">
import GamutSelect from '$lib/components/GamutSelect.svelte';
import SpaceSelect from '$lib/components/SpaceSelect.svelte';
import Icon from '$lib/components/util/Icon.svelte';
</script>
Expand All @@ -9,6 +10,7 @@
<span class="sr-only">OddContrast</span>
</h1>
<SpaceSelect />
<GamutSelect />
</header>

<style lang="scss">
Expand Down
2 changes: 1 addition & 1 deletion src/lib/components/SpaceSelect.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
</script>

<div data-field="color-format">
<label for="color-format" data-label>Color Format</label>
<label for="color-format" data-label>Format</label>
<select name="color-format" id="color-format" bind:value={$format}>
{#each spaces as space (space.id)}
{#if space}
Expand Down
16 changes: 13 additions & 3 deletions src/lib/components/colors/Sliders.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
import type { Writable } from 'svelte/store';
import { type ColorFormatId, SLIDERS } from '$lib/constants';
import { ColorSpace } from '$lib/stores';
import { ColorSpace, gamut } from '$lib/stores';
import { getSpaceFromFormatId, sliderGradient } from '$lib/utils';
interface Props {
Expand All @@ -20,7 +20,12 @@
SLIDERS[format].map((id) => {
const coord = spaceObject.coords[id];
const range = coord?.range ?? coord?.refRange ?? [0, 1];
const gradient = sliderGradient($color, id, range);
const gradient = sliderGradient({
color: $color,
channel: id,
range: range,
gamut: $gamut,
});
return {
id,
name: coord?.name ?? '',
Expand All @@ -37,7 +42,12 @@
);
let alphaGradient = $derived(
sliderGradient($color, 'alpha', [0, $color.alpha]),
sliderGradient({
color: $color,
channel: 'alpha',
range: [0, $color.alpha],
gamut: $gamut,
}),
);
const handleInput = (
Expand Down
8 changes: 8 additions & 0 deletions src/lib/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,14 @@ export const FORMATS: ColorFormatId[] = [
'srgb',
];

export type ColorGamutId = 'srgb' | 'p3' | 'rec2020';

export const GAMUTS: { name: string; format: ColorGamutId }[] = [
{ name: 'sRGB', format: 'srgb' },
{ name: 'P3', format: 'p3' },
{ name: 'Rec2020', format: 'rec2020' },
];

export interface FormatGroup {
name: string;
formats: ColorFormatId[];
Expand Down
4 changes: 3 additions & 1 deletion src/lib/stores.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import { writable } from 'svelte/store';

// eslint-disable-next-line import/no-unresolved
import { browser, dev } from '$app/environment';
import type { ColorFormatId } from '$lib/constants';
import type { ColorFormatId, ColorGamutId } from '$lib/constants';

// Register supported color spaces
ColorSpace.register(HSL);
Expand All @@ -32,6 +32,7 @@ export { ColorSpace };

export const INITIAL_VALUES = {
format: 'p3' as ColorFormatId,
gamut: 'p3' as ColorGamutId,
bg_coord: [0.0967, 0.167, 0.4494] as [number, number, number],
fg_coord: [0.951, 0.675, 0.7569] as [number, number, number],
alpha: 1,
Expand All @@ -49,6 +50,7 @@ const INITIAL_FG = {
};

export const format = writable<ColorFormatId>(INITIAL_VALUES.format);
export const gamut = writable<ColorGamutId>(INITIAL_VALUES.gamut);
export const bg = writable<PlainColorObject>(INITIAL_BG);
export const fg = writable<PlainColorObject>(INITIAL_FG);

Expand Down
20 changes: 13 additions & 7 deletions src/lib/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,16 +9,22 @@ import {
to,
} from 'colorjs.io/fn';

import { type ColorFormatId, FORMATS } from '$lib/constants';
import { type ColorFormatId, type ColorGamutId, FORMATS } from '$lib/constants';

export const getSpaceFromFormatId = (formatId: ColorFormatId) =>
formatId === 'hex' ? 'srgb' : formatId;

export const sliderGradient = (
color: PlainColorObject,
channel: string,
range: [number, number],
) => {
export const sliderGradient = ({
color,
channel,
range,
gamut,
}: {
color: PlainColorObject;
channel: string;
range: [number, number];
gamut: ColorGamutId;
}) => {
const start = clone(color);
const end = clone(color);
if (channel === 'alpha') {
Expand All @@ -44,7 +50,7 @@ export const sliderGradient = (
}

gradientSteps.forEach((step, index) => {
if (inGamut(step, 'p3')) {
if (inGamut(step, gamut)) {
if (wasInGamut === false) {
inGamutSteps.push(`transparent ${stepWidth * (index + 1)}%`);
}
Expand Down
2 changes: 1 addition & 1 deletion src/sass/initial/_layout.scss
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ body {
display: grid;
gap: var(--shim) var(--double-gutter);
grid-area: header;
grid-template: 'logo colorspace' auto / auto 1fr;
grid-template: 'logo colorspace gamut' auto / auto 1fr;

@include config.above('sm-page-break') {
gap: var(--double-gutter);
Expand Down

0 comments on commit 5c83b32

Please sign in to comment.