Skip to content

Commit

Permalink
Use npm: instead of esm.sh; Introduce Database use
Browse files Browse the repository at this point in the history
  • Loading branch information
felix-schindler committed Aug 7, 2024
1 parent ee0c008 commit 0a44c11
Show file tree
Hide file tree
Showing 7 changed files with 101 additions and 84 deletions.
4 changes: 2 additions & 2 deletions components/home/Intro.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,11 @@ export default function Intro({ lang }: { lang: AllowedLanguage }) {
<div class="sm:flex sm:items-center">
<picture class="w-full" alt="Globe marking the region Xi'an, China">
<source
srcset={`/img/world.svg?dark=true&lang=${lang}`}
srcset={`/img/world.svg?dark=true&lang=${lang}&loc=mtvsyhelishb0ut`}
media="(prefers-color-scheme: dark)"
/>
<img
src={`/img/world.svg?lang=${lang}`}
src={`/img/world.svg?lang=${lang}&loc=mtvsyhelishb0ut`}
alt={translations[lang].globe_alt}
/>
</picture>
Expand Down
4 changes: 3 additions & 1 deletion core/i18n/mod.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@ import type { AllowedLanguage } from "@/core/types.ts";

const ALLOWED_LANGUAGES: Array<AllowedLanguage> = ["en", "de", "zh"];

export function isAllowedLanguage(lang: string): lang is AllowedLanguage {
export function isAllowedLanguage(
lang: string | null,
): lang is AllowedLanguage {
return ALLOWED_LANGUAGES.includes(lang as AllowedLanguage);
}

Expand Down
7 changes: 7 additions & 0 deletions core/colors.ts → core/mod.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,10 @@
import PocketBase from "pocketbase";
import type { TypedPocketBase } from "./types.ts";

// THE PocketBase instance
export const pb = new PocketBase("https://pb.schindlerfelix.de")
.autoCancellation(false) as TypedPocketBase;

/** @var Record<string, Record<number, string>> */
export const tw = {
red: {
Expand Down
31 changes: 31 additions & 0 deletions core/types.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,36 @@
import type PocketBase from "pocketbase";
import type { RecordService } from "pocketbase";

export type AllowedLanguage = "en" | "de" | "zh";

type RecordID = string;
type DateString = string;

export type State = {
language: AllowedLanguage;
};

type BaseFields = {
id: RecordID;
updated: DateString;
created: DateString;
};

export type Location = BaseFields & {
name_en: string;
name_de: string;
name_zh: string;
lat: number;
lon: number;
};

type Region = BaseFields & {
name_en: string;
name_de: string;
name_zh: string;
};

export interface TypedPocketBase extends PocketBase {
collection(idOrName: "regions"): RecordService<Region>;
collection(idOrName: "locations"): RecordService<Location>;
}
6 changes: 5 additions & 1 deletion deno.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,17 @@
"@preact/signals-core": "https://esm.sh/*@preact/signals-core@1.5.1",
"@std/http/cookie": "jsr:@std/http@^0.224.5/cookie",
"@std/path": "jsr:@std/path@^0.225.2",
"d3-geo": "npm:d3-geo@^3.1.1",
"d3-geo-projection": "npm:d3-geo-projection@^4.0.0",
"icons/": "https://deno.land/x/tabler_icons_tsx@0.0.7/tsx/",
"pocketbase": "npm:pocketbase@^0.21.3",
"preact": "https://esm.sh/preact@10.19.6",
"preact/": "https://esm.sh/preact@10.19.6/",
"prism/": "https://esm.sh/prismjs@1.29.0/components/",
"tailwindcss": "npm:tailwindcss@3.4.3",
"tailwindcss/": "npm:/tailwindcss@3.4.3/",
"tailwindcss/plugin": "npm:/tailwindcss@3.4.3/plugin.js"
"tailwindcss/plugin": "npm:/tailwindcss@3.4.3/plugin.js",
"topojson-client": "npm:topojson-client@^3.1.0"
},
"compilerOptions": {
"jsx": "react-jsx",
Expand Down
4 changes: 2 additions & 2 deletions routes/_middleware.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,9 @@ export async function handler(
if (hasFileExt) {
const res = await ctx.next();

if (res.ok) {
if (res.ok && !res.headers.has("cache-control")) {
// Add cache header for 15 days
res.headers.set("Cache-Control", "public, max-age=1296000, immutable");
res.headers.set("cache-control", "public, max-age=1296000, immutable");
}

return res;
Expand Down
129 changes: 51 additions & 78 deletions routes/img/world.svg.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
import { Handlers } from "$fresh/server.ts";
import type { Handlers } from "$fresh/server.ts";

import { feature } from "https://esm.sh/topojson-client@3.1.0";
import { geoSatellite } from "https://esm.sh/d3-geo-projection@4.0.0";
import { geoPath } from "https://esm.sh/d3-geo@3.1.0";
import { feature } from "topojson-client";
import { geoSatellite } from "d3-geo-projection";
import { geoPath } from "d3-geo";

import { tw } from "@/core/colors.ts";
import { pb, tw } from "@/core/mod.ts";
import topology from "@/core/land-110m.json" with { type: "json" };
import { isAllowedLanguage } from "@/core/i18n/mod.ts";
import type { AllowedLanguage } from "@/core/types.ts";
import type { State } from "@/core/types.ts";
import { AllowedLanguage } from "@/core/types.ts";

const land = feature(topology, topology.objects.land);

Expand All @@ -16,6 +17,11 @@ const distance = 8;
const w = 1000;
const h = 1000;
const rad_to_deg = 180 / Math.PI;
const multiply: Record<AllowedLanguage, number> = {
"de": 0.6,
"en": 0.6,
"zh": 1,
} as const;

const projection = geoSatellite()
.distance(distance)
Expand All @@ -26,71 +32,12 @@ const projection = geoSatellite()

const path = geoPath(projection);

type Region = {
name: string;
coords: [number, number];
multiply: number; // 0.6 for latin; 0.65 for mixed; 1 for chinese characters
};

const regions: Record<
AllowedLanguage,
Record<"stuttgart" | "xian" | "shanghai", Region>
> = {
en: {
stuttgart: {
name: "Stuttgart",
coords: [9.1770, 48.7823],
multiply: 0.6,
},
shanghai: {
name: "上海(Shanghai)",
coords: [121.4737, 31.2304],
multiply: 0.7,
},
xian: {
name: "西安(Xi'an) ",
coords: [108.9402, 34.3416],
multiply: 0.65,
},
},
de: {
stuttgart: {
name: "Stuttgart",
coords: [9.1770, 48.7823],
multiply: 0.6,
},
shanghai: {
name: "上海(Schanghai)",
coords: [121.4737, 31.2304],
multiply: 0.7,
},
xian: {
name: "西安(Xi'an) ",
coords: [108.9402, 34.3416],
multiply: 0.65,
},
},
zh: {
stuttgart: {
name: "斯图加特",
coords: [9.1770, 48.7823],
multiply: 1,
},
shanghai: {
name: "上海",
coords: [121.4737, 31.2304],
multiply: 1,
},
xian: {
name: "西安",
coords: [108.9402, 34.3416],
multiply: 1,
},
},
} as const;

function render(region: Region, isDark: boolean) {
const coords = region.coords;
function render(
name: string,
coords: [number, number],
multiply: number,
isDark: boolean,
) {
projection.rotate([-coords[0] - 30, -coords[1] * (30 / 90), 0]);
const dot = projection(coords);

Expand Down Expand Up @@ -150,7 +97,7 @@ function render(region: Region, isDark: boolean) {
<g transform="translate(${dot[0]},${dot[1]})">
<circle r="15" class="dot"/>
<rect x="40" y="-32.5" width="${
font_size * region.multiply * region.name.length + 40
font_size * multiply * name.length + 40
}" height="60" rx="10" class="highlight" />
<polygon points="25,0 40,-10 40,10" class="highlight" />
<text
Expand All @@ -160,26 +107,52 @@ function render(region: Region, isDark: boolean) {
alignment-baseline="middle"
dominant-baseline="middle"
style="font-family: 'Courier', 'Courier New'; font-size: ${font_size}px; text-transform: uppercase; font-weight: bold"
>${region.name}</text>
>${name}</text>
</g>`
: ""
}
</svg>
`;
}

export const handler: Handlers = {
GET(_req, ctx) {
export const handler: Handlers<never, State> = {
async GET(_req, ctx) {
const searchParams = ctx.url.searchParams;

// Get values from params
const loc = searchParams.get("loc");

if (loc === null) {
return new Response(undefined, { status: 400 });
}

const isDark = searchParams.has("dark");
let lang = searchParams.get("lang") ?? "en";
let lang = searchParams.get("lang");
if (!isAllowedLanguage(lang)) lang = "en";
const region = regions[lang as AllowedLanguage].shanghai;
lang as AllowedLanguage; // TODO: This shouldn't be needed

const location = await pb.collection("locations").getOne(loc);

let name = "";
switch (lang) {
case "en":
name = location.name_en;
break;
case "de":
name = location.name_de;
break;
case "zh":
name = location.name_zh;
break;
}

// Generate SVG
const svg = render(region, isDark).replace(
const svg = render(
name,
[location.lat, location.lon],
multiply[lang],
isDark,
).replace(
/\d\.\d+/g,
(match) => match.slice(0, 4),
);
Expand Down

0 comments on commit 0a44c11

Please sign in to comment.