From 283a3c34b449c37fa328daf6f2b5aed523d77690 Mon Sep 17 00:00:00 2001 From: Eli <88557639+lishaduck@users.noreply.github.com> Date: Thu, 18 Jan 2024 16:21:23 -0600 Subject: [PATCH] feat: more dynamic pages --- src/content/getting-started.md | 5 ++ src/content/guarantees-in-life.md | 15 ++++ src/content/pricing.md | 5 ++ src/content/programs.md | 5 ++ src/content/solar.md | 15 +++- src/fresh.gen.ts | 2 - src/routes/monies/guarantees-in-life.tsx | 27 ------- src/utils/site-organization.ts | 90 +++++++++++++++++------- src/utils/solutions.ts | 15 ++-- src/utils/type-helpers.ts | 7 ++ 10 files changed, 126 insertions(+), 60 deletions(-) create mode 100644 src/content/getting-started.md create mode 100644 src/content/guarantees-in-life.md create mode 100644 src/content/pricing.md create mode 100644 src/content/programs.md delete mode 100644 src/routes/monies/guarantees-in-life.tsx diff --git a/src/content/getting-started.md b/src/content/getting-started.md new file mode 100644 index 00000000..5a3de104 --- /dev/null +++ b/src/content/getting-started.md @@ -0,0 +1,5 @@ +--- +title: Getting Started +description: Getting Started with green energy! +category: green +--- diff --git a/src/content/guarantees-in-life.md b/src/content/guarantees-in-life.md new file mode 100644 index 00000000..6940670e --- /dev/null +++ b/src/content/guarantees-in-life.md @@ -0,0 +1,15 @@ +--- +title: Taxes +description: "There are only two guarantees in life: death and taxes." +category: monies +--- + +## Tax Rebates + +Looking for information about tax rebates and incentives for green +energy? + +Please keep in mind that, like death, taxes are a certainty, and thus +tax evasion is illegal. If you wish to avoid taxes, please consult a +registered accountant rather than willy-nilly skipping them based on +our advice. diff --git a/src/content/pricing.md b/src/content/pricing.md new file mode 100644 index 00000000..7f0d778b --- /dev/null +++ b/src/content/pricing.md @@ -0,0 +1,5 @@ +--- +title: Pricing +description: Pricing for green energy +category: monies +--- diff --git a/src/content/programs.md b/src/content/programs.md new file mode 100644 index 00000000..cdbdc7d3 --- /dev/null +++ b/src/content/programs.md @@ -0,0 +1,5 @@ +--- +title: Programs +description: Green energy programs +category: green +--- diff --git a/src/content/solar.md b/src/content/solar.md index 95dc9cf3..89f83900 100644 --- a/src/content/solar.md +++ b/src/content/solar.md @@ -1,10 +1,21 @@ --- title: Solar Energy Solutions description: Solar Energy is an undertapped energy resource. +category: solar --- - - ## What is it? Solar panels are useful. They collect energy from the sun, and can be placed on roofs discreetly. + +## Cost + +## Tax Rebates + +## Best Practices + +## Buy Now + +You can use our [online calculator](/calculator/) to calculate costs and buy _your_ solar energy solution today! + +## Sources diff --git a/src/fresh.gen.ts b/src/fresh.gen.ts index 7ba0dfd1..5e58a0f2 100644 --- a/src/fresh.gen.ts +++ b/src/fresh.gen.ts @@ -8,7 +8,6 @@ import * as $_app from "./routes/_app.tsx"; import * as $_layout from "./routes/_layout.tsx"; import * as $about from "./routes/about.tsx"; import * as $index from "./routes/index.tsx"; -import * as $monies_guarantees_in_life from "./routes/monies/guarantees-in-life.tsx"; import * as $solutions_slug_ from "./routes/solutions/[slug].tsx"; import * as $HeaderMenu from "./islands/HeaderMenu.tsx"; import { type Manifest } from "$fresh/server.ts"; @@ -21,7 +20,6 @@ const manifest = { "./routes/_layout.tsx": $_layout, "./routes/about.tsx": $about, "./routes/index.tsx": $index, - "./routes/monies/guarantees-in-life.tsx": $monies_guarantees_in_life, "./routes/solutions/[slug].tsx": $solutions_slug_, }, islands: { diff --git a/src/routes/monies/guarantees-in-life.tsx b/src/routes/monies/guarantees-in-life.tsx deleted file mode 100644 index 1d624f26..00000000 --- a/src/routes/monies/guarantees-in-life.tsx +++ /dev/null @@ -1,27 +0,0 @@ -import { Head } from "$fresh/runtime.ts"; -import type { JSX } from "preact"; -import { Cover } from "../../components/Cover.tsx"; -import { Meta } from "../../components/Meta.tsx"; - -const pageTitle = "Death. And Taxes."; - -export default function Taxes(): JSX.Element { - return ( - <> - - - - -

- Looking for information about tax rebates and incentives for green - energy? -
- Please keep in mind that, like death, taxes are a certainty, and thus - tax evasion is illegal. If you wish to avoid taxes, please consult a - registered accountant rather than willy-nilly skipping them based on - our advice. -

-
- - ); -} diff --git a/src/utils/site-organization.ts b/src/utils/site-organization.ts index 06691520..a3ef8431 100644 --- a/src/utils/site-organization.ts +++ b/src/utils/site-organization.ts @@ -1,30 +1,9 @@ -// TODO(lishaduck): generate from `solutions`. -export const menus = [ - { - title: "Going Green?", - url: "/green/", - items: [ - { name: "Getting Started", href: "getting-started/" }, - { name: "Programs", href: "programs/" }, - ], - }, - { - title: "Monies", - url: "/monies/", - items: [ - { name: "Taxes", href: "guarantees-in-life/" }, - { name: "Pricing", href: "pricing/" }, - ], - }, - { - title: "About", - url: "/about/", - }, -] as const satisfies Menu[]; +import { solutions } from "./solutions.ts"; +import { isKey } from "./type-helpers.ts"; export interface Menu { readonly title: string; - readonly url: `${string}/`; + readonly url: `/${string}/`; readonly items?: readonly MenuItem[]; } @@ -34,5 +13,66 @@ export interface MenuItem { } export interface MenuWithItems extends Menu { - readonly items: readonly [MenuItem, ...(readonly MenuItem[])]; + readonly items: readonly [MenuItem, ...MenuItem[]]; +} + +const extraMenus = [ + { + title: "About", + url: "/about/", + }, +] as const satisfies Menu[]; + +/** + * Convert the `solutions` into to `Menu`s based on the .category. + * Should also append the `extraMenus` to the end to add the about page and such. + * + * @returns The generated menus. + */ + +function generateMenus(): Menu[] { + const categories = new Map(); + + for (const solution of solutions) { + // If the category doesn't exist yet, create it + if (!categories.has(solution.data.category)) { + categories.set(solution.data.category, { + title: isKey(categoryMap, solution.data.category) + ? categoryMap[solution.data.category] + : solution.data.category, + url: "/solutions/", + items: [], + }); + } + + // Add the solution to the category's items + const category = categories.get(solution.data.category); + if (category !== undefined) { + categories.set(solution.data.category, { + ...category, + items: [ + ...(category.items ?? []), + { + name: solution.data.title, + href: `${solution.slug}/`, + }, + ], + }); + } + } + + for (const menu of extraMenus) { + categories.set(menu.title, menu); + } + + return Array.from(categories.values()); } + +const categoryMap = { + green: "Going Green?", + monies: "Monies", + about: "About", + solar: "Solar", +} as const; + +export const menus = generateMenus(); diff --git a/src/utils/solutions.ts b/src/utils/solutions.ts index f1b25d0c..c13bd527 100644 --- a/src/utils/solutions.ts +++ b/src/utils/solutions.ts @@ -10,13 +10,14 @@ const solutionDataSchema = z .object({ title: z.string(), description: z.string(), + category: z.string(), }) .passthrough() .readonly(); const solutionPageSchema = z .object({ - slug: z.string(), + slug: z.string(), // The slug of the solution without a trailing slash. markdown: z.string(), data: solutionDataSchema, }) @@ -38,6 +39,8 @@ const solutionPagesSchema = solutionPagesNullableSchema.transform( ); const dir = "src/content"; +const categorySort = ["green", "monies", "solar"]; + export const solutions = await getSolutions(); /** Get all solutions. */ @@ -48,11 +51,15 @@ export async function getSolutions(): Promise { const slug = file.name.replace(".md", ""); promises.push(getSolution(slug)); } - const solutions = await Promise.all(promises); + const unparsedSolutions = await Promise.all(promises); + const solutions = solutionPagesSchema.parse(unparsedSolutions); - return solutionPagesSchema.parse(solutions); + return solutions.toSorted( + (a, b) => + categorySort.indexOf(a.data.category) - + categorySort.indexOf(b.data.category), + ); } - /** Get a solution. */ export async function getSolution( slug: string, diff --git a/src/utils/type-helpers.ts b/src/utils/type-helpers.ts index fba360b1..076a1e45 100644 --- a/src/utils/type-helpers.ts +++ b/src/utils/type-helpers.ts @@ -3,3 +3,10 @@ import type { Menu, MenuWithItems } from "./site-organization.ts"; export function hasItems(menu: Menu): menu is MenuWithItems { return (menu.items?.length ?? 0) > 0; } + +export function isKey( + obj: T, + key: PropertyKey, +): key is keyof T { + return Object.hasOwn(obj, key); +}