Skip to content

Commit

Permalink
refactor: design & cleanup
Browse files Browse the repository at this point in the history
  • Loading branch information
QuiiBz committed Sep 1, 2024
1 parent 08c87fb commit 728c778
Show file tree
Hide file tree
Showing 10 changed files with 164 additions and 294 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,5 @@ db.sqlite*
.DS_Store
*.log
.env
.env*
*.tsbuildinfo
2 changes: 1 addition & 1 deletion apps/dashboard/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
"@vercel/speed-insights": "^1.0.10",
"clsx": "^2.1.1",
"fuse.js": "^7.0.0",
"next": "14.2.3",
"next": "14.2.7",
"next-themes": "^0.3.0",
"react": "^18",
"react-colorful": "^5.6.1",
Expand Down
1 change: 0 additions & 1 deletion apps/dashboard/src/app/api/fonts/route.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import { getFontData } from "../../../lib/fonts";

export const dynamic = "force-static";
export const runtime = "nodejs";

export async function GET() {
return Response.json(await getFontData());
Expand Down
97 changes: 0 additions & 97 deletions apps/dashboard/src/components/RightPanel/AddFont.tsx

This file was deleted.

50 changes: 23 additions & 27 deletions apps/dashboard/src/components/RightPanel/FontSection.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { useElementsStore } from "../../stores/elementsStore";
import { ColorPicker } from "../ColorPicker";
import { FontPreview } from "../FontPreview";
import { useFontsStore } from "../../stores/fontsStore";
import { AddFont } from "./AddFont";
import { FontSelector } from "./FontSelector";

const SPACES_REGEX = /\s+/g;

Expand All @@ -28,10 +28,8 @@ export function FontSection({ selectedElement }: FontSectionProps) {
<Text size="1">Font</Text>
<Flex direction="row" gap="2" className="justify-between">
<Select.Root
onValueChange={(value) => {
const font = value;
const weights = allFonts.find((f) => f.name === font)?.weights;

onValueChange={(font) => {
const weights = allFonts.find(({ name }) => name === font)?.weights;
if (!installedFonts.has(font)) {
installFont(font);
}
Expand All @@ -55,11 +53,28 @@ export function FontSection({ selectedElement }: FontSectionProps) {
))}
</Select.Content>
</Select.Root>

<AddFont selectedElement={selectedElement} />
<FontSelector selectedElement={selectedElement} />
</Flex>

<Grid columns="2" gap="2">
<TextField.Root
color="gray"
onChange={(event) => {
updateElement({
...selectedElement,
fontSize: event.target.valueAsNumber,
});
}}
type="number"
value={selectedElement.fontSize}
variant="soft"
>
<Tooltip content="Font size">
<TextField.Slot>
<FontSizeIcon />
</TextField.Slot>
</Tooltip>
<TextField.Slot>px</TextField.Slot>
</TextField.Root>
<Select.Root
onValueChange={(value) => {
updateElement({
Expand All @@ -81,25 +96,6 @@ export function FontSection({ selectedElement }: FontSectionProps) {
))}
</Select.Content>
</Select.Root>
<TextField.Root
color="gray"
onChange={(event) => {
updateElement({
...selectedElement,
fontSize: event.target.valueAsNumber,
});
}}
type="number"
value={selectedElement.fontSize}
variant="soft"
>
<Tooltip content="Font size">
<TextField.Slot>
<FontSizeIcon />
</TextField.Slot>
</Tooltip>
<TextField.Slot>px</TextField.Slot>
</TextField.Root>
<ColorPicker
onChange={(color) => {
updateElement({
Expand Down
83 changes: 83 additions & 0 deletions apps/dashboard/src/components/RightPanel/FontSelector.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
import { Popover, Button, TextField, Flex, Badge } from "@radix-ui/themes";
import Fuse from "fuse.js";
import { useMemo, useState } from "react";
import { useFontsStore } from "../../stores/fontsStore";
import { useElementsStore } from "../../stores/elementsStore";
import { FontPreview } from "../FontPreview";
import type { OGElement } from "../../lib/types";
import { useDebounce } from "../../lib/hooks/useDebounce";
import { DEFAULT_FONTS } from "../../lib/fonts";

interface FontSelectorProps {
selectedElement: OGElement & { tag: "p" | "span" };
}

export function FontSelector({ selectedElement }: FontSelectorProps) {
const { allFonts, installedFonts, installFont } = useFontsStore();
const updateElement = useElementsStore((state) => state.updateElement);
const fuse = useMemo(
() => new Fuse(allFonts, { keys: ["name"] }),
[allFonts],
);
const [search, setSearch] = useState("");
const [isOpen, setIsOpen] = useState(false);
const debouncedSearch = useDebounce(search, 200);

const searchedFonts = fuse
.search(debouncedSearch)
.slice(0, 8)
.map(({ item }) => item.name);

return (
<Popover.Root open={isOpen} onOpenChange={setIsOpen}>
<Popover.Trigger>
<Button size="2" variant="soft" color="gray">
+
</Button>
</Popover.Trigger>
<Popover.Content width="300px">
<Flex gap="3" direction="column">
<TextField.Root
placeholder="Search ny fontsource font..."
value={search}
onChange={(event) => {
setSearch(event.target.value);
}}
/>
<Flex gap="1" direction="column">
{searchedFonts.map((font) => (
<Button
variant="soft"
color="gray"
key={font}
onClick={() => {
installFont(font);
const weights = allFonts.find(
({ name }) => name === font,
)?.weights;

updateElement({
...selectedElement,
fontFamily: font,
fontWeight: weights?.includes(selectedElement.fontWeight)
? selectedElement.fontWeight
: 400,
});

setIsOpen(false);
}}
>
<FontPreview font={font} />
{DEFAULT_FONTS.includes(font) ? (
<Badge color="blue">Pre-installed</Badge>
) : installedFonts.has(font) ? (
<Badge color="green">Installed</Badge>
) : null}
</Button>
))}
</Flex>
</Flex>
</Popover.Content>
</Popover.Root>
);
}
52 changes: 25 additions & 27 deletions apps/dashboard/src/lib/fonts.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,21 @@
import type { OGElement } from "./types";

export interface Font {
name: string;
weights: number[];
}

export interface FontData {
name: string;
data: ArrayBuffer;
weight: number;
}

const fontsCache = new Map<string, FontData>();

/**
* Default fonts that are available in the editor.
*/
export const DEFAULT_FONTS = [
"Roboto",
"Open Sans",
Expand All @@ -14,7 +30,8 @@ export const DEFAULT_FONTS = [
];

/**
* Adds the font stylesheet to the document body
* Adds the font stylesheet to the document body.
*
* The font is loaded asynchronously, so it may not be available immediately
* and the caller should make sure to wait for the font to be loaded before
* using it.
Expand Down Expand Up @@ -44,16 +61,8 @@ export function maybeLoadFont(font: string, weight: number) {
document.head.appendChild(style);
}

export interface FontData {
name: string;
data: ArrayBuffer;
weight: number;
}

const fontsCache = new Map<string, FontData>();

/**
* Load all fonts used in the given elements from Bunny Fonts. The fonts are
* Load all fonts used in the given elements from sourcefonts. The fonts are
* returned as an `ArrayBuffer`, along with the font name and weight.
*/
export async function loadFonts(elements: OGElement[]): Promise<FontData[]> {
Expand All @@ -69,17 +78,13 @@ export async function loadFonts(elements: OGElement[]): Promise<FontData[]> {
return fontCache;
}

if (element.tag !== "p" && element.tag !== "span")
throw new Error("unreachable!");

const data = await fetch(
getFontURL(element.fontFamily, element.fontWeight),
).then((response) => response.arrayBuffer());

const fontData: FontData = {
name: element.fontFamily,
data,

weight: element.fontWeight,
};

Expand All @@ -89,26 +94,21 @@ export async function loadFonts(elements: OGElement[]): Promise<FontData[]> {
);
}

export async function getFontData() {
/**
* Get a list of all available fonts from Fontsource.
*/
export async function getFontData(): Promise<Font[]> {
interface FontsourceFont {
id: string;
family: string;
subsets: string[];
weights: number[];
styles: string[];
defSubset: string;
variable: boolean;
lastModified: Date;
category: string;
license: string;
type: string;
}

const res = await fetch("https://api.fontsource.org/v1/fonts", {
const response = await fetch("https://api.fontsource.org/v1/fonts", {
cache: "no-store",
});

const data = (await res.json()) as FontsourceFont[];
const data = (await response.json()) as FontsourceFont[];

return data
.filter(({ styles }) => styles.includes("normal"))
Expand All @@ -119,8 +119,6 @@ export async function getFontData() {
}));
}

export type Font = Awaited<ReturnType<typeof getFontData>>[number];

export function getFontURL(fontName: string, weight: number) {
const fontID = fontName.toLowerCase().replaceAll(" ", "-");
return `https://cdn.jsdelivr.net/fontsource/fonts/${fontID}@latest/latin-${weight}-normal.woff`;
Expand Down
Loading

0 comments on commit 728c778

Please sign in to comment.