Skip to content

Commit

Permalink
introduce colors page
Browse files Browse the repository at this point in the history
blocked by #1019.
  • Loading branch information
EthanThatOneKid committed Mar 13, 2024
1 parent ed23f55 commit 4c330d9
Show file tree
Hide file tree
Showing 8 changed files with 270 additions and 2 deletions.
58 changes: 56 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@
"@size-limit/file": "^8.2.6",
"@sveltejs/adapter-auto": "^2.0.0",
"@sveltejs/kit": "^1.20.4",
"@types/css": "^0.0.37",
"@types/html-to-text": "^9.0.1",
"@types/qrcode": "^1.5.1",
"@types/rss": "^0.0.30",
Expand All @@ -65,6 +66,7 @@
"@googleapis/calendar": "^7.0.0",
"@js-temporal/polyfill": "^0.4.4",
"cropperjs": "^1.5.13",
"css": "^3.0.0",
"html-to-text": "^9.0.5",
"lc-dailies": "github:acmcsufoss/lc-dailies#npm",
"pomo": "github:ethanthatonekid/pomo#npm",
Expand Down
74 changes: 74 additions & 0 deletions src/routes/(site)/_colors/+page.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
<script lang="ts">
import type { PageData } from './$types';
import Spacing from '$lib/public/legacy/spacing.svelte';
import Color from './color.svelte';
export let data: PageData;
</script>

<Spacing --min="175px" --med="200px" --max="200px" />

<svelte:head>
<title>Colors | ACM at CSUF</title>
</svelte:head>

<main class="responsive-width">
<section id="top">
<div class="header">
<h1 class="size-lg">Colors</h1>
</div>
<ul>
{#each data.colors as color (color.id)}
<li><Color data={color} /></li>
{/each}
</ul>
</section>

<p>
<a href="#top">Back to top</a> | <a href="/global.css">global.css</a>
</p>
</main>

<Spacing --min="40px" --med="95px" --max="120px" />

<style lang="scss">
.responsive-width {
width: min(80ch, 80vw);
margin: 0 auto;
}
h1 {
display: flex;
align-items: center;
justify-content: center;
margin: 0;
}
main {
width: 100%;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
section {
width: min(800px, 80vw);
max-width: 540px;
margin: 0 auto;
margin-bottom: 50px;
p {
margin: 1em 0;
word-break: break-word;
}
a {
transition: 0.25s ease-in-out;
&:hover {
color: var(--acm-blue);
}
}
}
}
</style>
7 changes: 7 additions & 0 deletions src/routes/(site)/_colors/+page.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import type { PageLoadEvent } from './$types';
import { parseGlobalCSS } from './colors';

export async function load({ fetch }: PageLoadEvent) {
const globalCSS = await fetch('/global.css').then((r) => r.text());
return { colors: parseGlobalCSS(globalCSS) };
}
7 changes: 7 additions & 0 deletions src/routes/(site)/_colors/color-id.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<script lang="ts">
import type { Color } from './colors';
export let data: Color;
</script>

<code class="color-id" style:--color={data.hex}>{data.id}</code>
26 changes: 26 additions & 0 deletions src/routes/(site)/_colors/color-pill.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
<script lang="ts">
import type { Color } from './colors';
import { copy } from '$lib/public/copy/copy';
export let data: Color;
function copyColor() {
copy(`var(${data.id})`, 'Copied color to clipboard', 'Failed to copy color to clipboard');
}
</script>

<!-- svelte-ignore a11y-click-events-have-key-events a11y-no-noninteractive-element-to-interactive-role -->
<code
role="button"
tabindex="0"
class="color-pill"
style:--color={data.hex}
on:click={() => copyColor()}>{data.hex} ({data.rgb.join(', ')})</code
>

<style>
.color-pill {
text-decoration: underline;
text-decoration-color: var(--color);
}
</style>
18 changes: 18 additions & 0 deletions src/routes/(site)/_colors/color.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
<script lang="ts">
import type { Color } from './colors';
import ColorPill from './color-pill.svelte';
import ColorID from './color-id.svelte';
export let data: Color;
</script>

<div id={data.id} class="color-container size-md" style:--color={data.hex}>
<ColorID {data} />:
<ColorPill {data} />
</div>

<style>
.color-container {
border-left: 5px solid var(--color);
}
</style>
80 changes: 80 additions & 0 deletions src/routes/(site)/_colors/colors.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
import type { Stylesheet, Declaration } from 'css';
import { parse } from 'css';

export interface Color {
id: string;
hex: string;
rgb: [number, number, number];
}

export function parseGlobalCSS(source: string): Color[] {
const ast = parse(source);
return fromAST(ast);
}

function fromAST(ast: Stylesheet): Color[] {
const colors: Color[] = [];
for (const rule of ast.stylesheet?.rules ?? []) {
if (!('selectors' in rule)) {
continue;
}

if (!rule.selectors?.find((s) => s.endsWith(':root'))) {
continue;
}

for (const decl of rule?.declarations ?? []) {
const color = fromDecl(decl);
if (color) {
colors.push(color);
}
}
}

return colors.toSorted((a, b) => a.id.localeCompare(b.id));
}

function fromDecl({ property, value }: Declaration): Color | null {
if (property === undefined || value === undefined) {
return null;
}

switch (true) {
case /^\d{1,3}, \d{1,3}, \d{1,3}$/.test(value): {
const [r, g, b] = value.split(', ').map(Number);
return {
id: property,
hex: rgb2hex(r, g, b),
rgb: [r, g, b],
};
}

case /^#([0-9a-f]{3}){1,2}$/i.test(value): {
const [r, g, b] = hex2rgb(value);
return {
id: property,
hex: value,
rgb: [r, g, b],
};
}

default: {
return null;
}
}
}

function hex2rgb(hex: string): [number, number, number] {
hex = hex.trim().replace(/^#/, '');
return [
parseInt(hex.slice(1, 3), 16),
parseInt(hex.slice(3, 5), 16),
parseInt(hex.slice(5, 7), 16),
];
}

function rgb2hex(r: number, g: number, b: number): string {
return `#${r.toString(16).padStart(2, '0')}${g.toString(16).padStart(2, '0')}${b
.toString(16)
.padStart(2, '0')}`;
}

0 comments on commit 4c330d9

Please sign in to comment.