Skip to content

Commit

Permalink
chore: Rework i18n types, update blog path, update some styles
Browse files Browse the repository at this point in the history
  • Loading branch information
kiosion committed Mar 3, 2024
1 parent 8cb99a3 commit 2d91b4c
Show file tree
Hide file tree
Showing 40 changed files with 632 additions and 214 deletions.
3 changes: 2 additions & 1 deletion .lintstagedrc.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
"./svelte-app/node_modules/.bin/eslint --fix"
],
"svelte-app/src/languages/*.json": [
"deno run --no-npm --allow-read --allow-write ./svelte-app/scripts/sort-json.ts"
"bun ./svelte-app/scripts/lint-json.ts",
"bun ./svelte-app/scripts/generate-types.ts"
]
}
5 changes: 3 additions & 2 deletions svelte-app/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,16 @@
"dev:backed": "vite dev --mode backed --host",
"package": "svelte-kit package",
"preview": "vite preview",
"generate": "bun ./scripts/generate-types && pnpm eslint --fix \"./types/**/*.ts\"",
"test": "test:vitest; test:playwright",
"test:vitest": "MODE=testing vitest --run",
"test:playwright": "playwright test",
"coverage": "vitest run --coverage",
"check": "svelte-check --tsconfig ./tsconfig.json",
"check:watch": "svelte-check --tsconfig ./tsconfig.json --watch",
"format": "prettier --write ./src/**/*.{ts,svelte}",
"format:json": "deno run --no-npm --allow-read --allow-write ./scripts/sort-json.ts ./src/languages/en.json ./src/languages/fr.json --fix",
"lint": "pnpm format && pnpm eslint --fix \"./src/**/*.{ts,svelte}\""
"format:json": "bun ./scripts/lint-json.ts ./src/languages/en.json ./src/languages/fr.json",
"lint": "pnpm format && pnpm eslint --fix \"./src/**/*.{ts,svelte}\" \"./types/**/*.ts\""
},
"devDependencies": {
"@playwright/test": "1.41.2",
Expand Down
51 changes: 0 additions & 51 deletions svelte-app/scripts/check-translations.ts

This file was deleted.

45 changes: 45 additions & 0 deletions svelte-app/scripts/generate-types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import fs from 'fs';
import path from 'path';

const sourceDir = path.join(__dirname, '../src');
const translationDir = path.join(sourceDir, 'languages');
const typesDir = path.join(__dirname, '../types/generated');

const readLocaleFile = (locale: string) => {
const filePath = path.join(translationDir, `${locale}.json`);
const fileContent = fs.readFileSync(filePath, 'utf-8');
return JSON.parse(fileContent);
};

const extractKeys = (obj: object, prefix = ''): string[] =>
Object.entries(obj).flatMap(([key, value]) => {
const newKey = prefix ? `${prefix}.${key}` : key;
if (typeof value === 'object' && value !== null && !Array.isArray(value)) {
return extractKeys(value, newKey);
}
return newKey;
});

const generateTypes = (keys: string[]) => {
const unionType = keys
.map((key) => (key.includes("'") ? `"${key}"` : `'${key}'`))
.join(' | ');

return `export type LocaleKey = ${unionType};`;
};

const compareLocales = (locale1: object, locale2: object) => {
const keys1 = extractKeys(locale1);
const keys2 = extractKeys(locale2);
return keys1.filter((key) => keys2.includes(key));
};

const enLocale = readLocaleFile('en');
const frLocale = readLocaleFile('fr');

const commonKeys = compareLocales(enLocale, frLocale);
const typesContent = generateTypes(commonKeys);

fs.writeFileSync(path.join(typesDir, 'index.ts'), typesContent);

console.log('Generated types for locales: ./types/generated/index.ts');
34 changes: 34 additions & 0 deletions svelte-app/scripts/lint-json.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import { readFileSync, writeFileSync } from 'fs';

const args = Bun.argv.slice(2);
const filePaths: string[] = args;

if (!filePaths.length) {
throw new Error('[sort-json] No file path(s) provided');
} else if (filePaths.some((p) => !p.match(/\.json$/i))) {
throw new Error('[sort-json] File(s) must be JSON');
}

const sortObjectKeys = (obj: Record<string, unknown>) => {
const sortedKeys = Object.keys(obj).sort();

return sortedKeys.reduce((acc, key) => {
if (typeof obj[key] === 'object' && !Array.isArray(obj[key])) {
acc[key] = sortObjectKeys(obj[key] as Record<string, unknown>);
}
acc[key] = obj[key];
return acc;
}, {});
};

filePaths.forEach((filePath) => {
if (!filePath.match(/languages\/[a-z]{2}\.json/i)) {
return;
}

const contents = JSON.parse(readFileSync(filePath, 'utf-8'));
const sortedContents = sortObjectKeys(contents);

writeFileSync(filePath, JSON.stringify(sortedContents, null, 2), 'utf-8');
console.log(`[sort-json] Sorted '${filePath}'`);
});
50 changes: 0 additions & 50 deletions svelte-app/scripts/sort-json.ts

This file was deleted.

10 changes: 6 additions & 4 deletions svelte-app/src/components/about/timeline-section.svelte
Original file line number Diff line number Diff line change
@@ -1,19 +1,21 @@
<script lang="ts">
import { displayMonthDuration, displayRange } from '$lib/date';
import { t } from '$lib/i18n';
import TimelineItem from '$components/about/timeline-item.svelte';
import type { WorkTimelineItem } from '$types';
export let section: WorkTimelineItem[];
const title = section[0].title;
const title = section[0].title,
id = Math.random().toString(36).substring(7);
</script>

<section>
<section role="group" aria-labelledby="{id}-heading">
<div>
<h2>{title}</h2>
<p>
<h2 id="{id}-heading">{title}</h2>
<p aria-label={$t('Duration')}>
{$displayRange(section[section.length - 1].range.start, section[0].range.end)} &bull;
{$displayMonthDuration(
section[section.length - 1].range.start,
Expand Down
2 changes: 1 addition & 1 deletion svelte-app/src/components/document/content/footer.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
{/if}
<div>
<ArrowButton
href={model === 'post' ? $linkTo('/blog') : $linkTo('/work')}
href={model === 'post' ? $linkTo('/thoughts') : $linkTo('/work')}
align="left"
fullWidth
preload
Expand Down
2 changes: 1 addition & 1 deletion svelte-app/src/components/document/content/header.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@
</div>
<ArrowButton
class="focusOutline-sm -mb-1 hidden flex-1 whitespace-nowrap sm:block"
href={model === 'post' ? $linkTo('/blog') : $linkTo('/work')}
href={model === 'post' ? $linkTo('/thoughts') : $linkTo('/work')}
align="right"
fullWidth
preload
Expand Down
2 changes: 1 addition & 1 deletion svelte-app/src/components/document/route.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@
? data.desc.length > 160
? `${data.desc.slice(0, 160 - 3)}...`
: data.desc
: $t(`A ${model === 'post' ? 'post' : 'project'} on kio.dev`);
: $t(`A ${model === 'post' ? 'blog post' : 'project'} on kio.dev`);
</script>

<svelte:head>
Expand Down
14 changes: 14 additions & 0 deletions svelte-app/src/components/experiments/card.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<script lang="ts">
export let title: string, description: string;
</script>

<section>
<div>
<h3>{title}</h3>
<p>{description}</p>
</div>

<slot />
</section>

<style lang="scss"></style>
14 changes: 4 additions & 10 deletions svelte-app/src/components/header.svelte
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
<script lang="ts">
import { NAV_LINKS } from '$lib/consts';
import { linkTo } from '$lib/i18n';
import LanguageControls from '$components/controls/language-toggle.svelte';
import ThemeToggle from '$components/controls/theme-toggle.svelte';
import Divider from '$components/divider.svelte';
import NavLink from '$components/nav/header-link.svelte';
import HeaderLogo from '$components/nav/header-logo.svelte';
</script>

<header>
<nav aria-label="Main navigation">
<a href={$linkTo('/')} aria-label="Home">kio.dev</a>
<HeaderLogo />
<div>
{#each NAV_LINKS as link, i}
<NavLink {link} />
Expand Down Expand Up @@ -41,25 +41,19 @@
@apply justify-start gap-2 pr-0;
}
:global(.dark) & {
@include dark {
@apply text-light/90;
}
}
div {
@apply flex flex-row items-center justify-end gap-5 pr-1.5 pt-0.5 text-dark/80;
:global(.dark) & {
@include dark {
@apply text-light/80;
}
}
a {
@apply w-fit select-none rounded-sm font-code text-lg font-extrabold transition-[color];
@include focus-state(sm);
}
span {
@apply cursor-default select-none;
}
Expand Down
8 changes: 5 additions & 3 deletions svelte-app/src/components/headings/headed-block.svelte
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
<script lang="ts">
export let heading: string,
testId: string | undefined = undefined;
export const id = Math.random().toString(36).substring(2);
</script>

<section data-test-id={testId}>
<h1>{heading}</h1>
<div><slot /></div>
<section {id} data-test-id={testId}>
<h1 id="{id}-heading">{heading}</h1>
<div><slot {id} /></div>
</section>

<style lang="scss">
Expand Down
8 changes: 4 additions & 4 deletions svelte-app/src/components/link.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -18,23 +18,23 @@

<Hoverable let:hovered>
<Tooltip
text={link?.length > 50 ? `${link.slice(0, 50)}...` : link ?? $t('Visit')}
text={link && link.length > 50 ? `${link.slice(0, 50 - 3)}...` : link ?? $t('Visit')}
delay={300}
>
<svelte:element
this={type}
href={link}
target={$$props.newtab ? '_blank' : undefined}
rel={$$props.newtab ? 'noopener noreferrer' : undefined}
class="focusOutline-sm rounded-sm from-accent-light underline decoration-accent-light underline-offset-[2px] dark:decoration-accent-dark {hovered
? 'decoration-[3px]'
: 'decoration-2'} transition-[text-decoration-color]"
tabindex="0"
aria-label={$$props['aria-label']}
{...$$restProps}
href={link}
on:click={() => dispatch('click')}
on:keyup={(e) => e.key === 'Enter' && dispatch('click')}
role={type === 'a' ? 'link' : 'button'}
aria-label={$$props['aria-label']}
{...$$restProps}
>
<slot />
</svelte:element>
Expand Down
4 changes: 2 additions & 2 deletions svelte-app/src/components/lists/document-list.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,14 @@
export let documents: (ProjectDocument | PostDocument)[];
</script>

<div>
<div role="group" {...$$restProps}>
{#each documents as document}
<ListItem {document} />
{/each}
</div>

<style lang="scss">
div {
@apply flex w-full flex-col gap-7 pt-5;
@apply flex w-full flex-col gap-8 pt-5;
}
</style>
Loading

0 comments on commit 2d91b4c

Please sign in to comment.