Skip to content

Commit

Permalink
Merge pull request #6 from PHS-TSA/dyamic-pages
Browse files Browse the repository at this point in the history
Add solar page
  • Loading branch information
lishaduck authored Jan 9, 2024
2 parents 7da18e2 + 0061bb1 commit 103eae2
Show file tree
Hide file tree
Showing 7 changed files with 127 additions and 4 deletions.
3 changes: 3 additions & 0 deletions biome.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,9 @@
"style": {
"noImplicitBoolean": "off",
"noDefaultExport": "off"
},
"complexity": {
"useLiteralKeys": "off"
}
}
},
Expand Down
3 changes: 2 additions & 1 deletion deno.json
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,8 @@
"@tailwindcss/typography": "npm:@tailwindcss/typography@0.5.10",
"tailwindcss": "npm:tailwindcss@3.4.1",
"tailwindcss/": "npm:tailwindcss@3.4.1/",
"tailwindcss/plugin": "npm:tailwindcss@3.4.1/plugin.js"
"tailwindcss/plugin": "npm:tailwindcss@3.4.1/plugin.js",
"$gfm": "https://deno.land/x/gfm@0.3.0/mod.ts"
},
"compilerOptions": {
"jsx": "react-jsx",
Expand Down
11 changes: 8 additions & 3 deletions src/components/Cover.tsx
Original file line number Diff line number Diff line change
@@ -1,15 +1,20 @@
import type { FunctionalComponent, VNode } from "preact";
import type { ComponentFactory, FunctionalComponent, VNode } from "preact";
import Logo from "./Logo.tsx";

interface Props {
title: string;
children: VNode;
icon?: ComponentFactory;
}

const Cover: FunctionalComponent<Props> = ({ title, children }) => (
const Cover: FunctionalComponent<Props> = ({
title,
children,
icon: Icon = Logo,
}) => (
<div class="mx-0 bg-green-500 px-4 py-8 dark:bg-green-700">
<div class="mx-auto flex max-w-screen-md flex-col items-center justify-center">
<Logo />
<Icon />
<h1 class="text-4xl font-bold dark:text-white">{title}</h1>
{children}
</div>
Expand Down
10 changes: 10 additions & 0 deletions src/content/solar.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
---
title: Solar Energy Solutions
description: Solar Energy is an undertapped energy resource.
---

<!-- The website should provide basic information, cost, tax rebate information, and clean/green energy practices. -->

## What is it?

Solar panels are useful. They collect energy from the sun, and can be placed on roofs discreetly.
2 changes: 2 additions & 0 deletions src/fresh.gen.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ 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";

Expand All @@ -21,6 +22,7 @@ const manifest = {
"./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: {
"./islands/HeaderMenu.tsx": $HeaderMenu,
Expand Down
61 changes: 61 additions & 0 deletions src/routes/solutions/[slug].tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
import { Head } from "$fresh/runtime.ts";
import type { Handlers, PageProps } from "$fresh/server.ts";
import { render } from "$gfm";
import type { FunctionalComponent } from "preact";
import IconSolarPanel from "tabler_icons_tsx/solar-panel.tsx";
import Cover from "../../components/Cover.tsx";
import Meta from "../../components/Meta.tsx";
import { type SolutionPage, solutions } from "../../utils/posts.ts";

interface SolutionProps {
page: SolutionPage;
}

const handler: Handlers<SolutionProps> = {
GET(_req, ctx) {
const solution = solutions.find(({ slug }) => slug === ctx.params["slug"]);

if (solution === undefined) {
return ctx.renderNotFound();
}

return ctx.render({ page: solution });
},
};

const Solution: FunctionalComponent<PageProps<SolutionProps>> = ({ data }) => {
const _pageTitle = data.page.data["title"];
const pageTitle = typeof _pageTitle === "string" ? _pageTitle : "";
const _description = data.page.data["description"];
const description = typeof _description === "string" ? _description : "";

return (
<>
<Head>
<Meta title={pageTitle} />
</Head>
<main>
<Cover
title={pageTitle}
icon={() => (
<IconSolarPanel
class="size-52 text-yellow-200 dark:text-yellow-400"
aria-hidden="true"
/>
)}
>
<p class="my-4 dark:text-white">{description}</p>
</Cover>
<article
class="p-10 prose prose-lg dark:prose-invert max-w-none prose-headings:flex prose-headings:flex-row prose-headings:items-center bg-slate-200"
// biome-ignore lint/security/noDangerouslySetInnerHtml: required for markdown w/out a custom renderer
dangerouslySetInnerHTML={{
__html: render(data?.page.markdown ?? ""),
}}
/>
</main>
</>
);
};

export { Solution as default, handler };
41 changes: 41 additions & 0 deletions src/utils/posts.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import type { Extract } from "$std/front_matter/create_extractor.ts";
import { extract } from "$std/front_matter/yaml.ts";
import { join } from "$std/path/posix/join.ts";

interface SolutionPage {
slug: string;
markdown: string;
data: Record<string, unknown>;
}

const dir = "src/content";

const solutions = await getPosts();

/** Get all solutions. */
export async function getPosts(): Promise<SolutionPage[]> {
const files = Deno.readDir(dir);
const promises = [];
for await (const file of files) {
const slug = file.name.replace(".md", "");
promises.push(getPost(slug));
}

const solutions = await Promise.all(promises); // TODO: validate w/Zod.

return solutions as SolutionPage[];
}

/** Get a solution. */
export async function getPost(slug: string): Promise<SolutionPage | null> {
let extracted: Extract<Record<string, unknown>>;
try {
const markdown = await Deno.readTextFile(join(dir, `${slug}.md`));
extracted = extract(markdown);
} catch (_) {
return null;
}
return { markdown: extracted.body, data: extracted.attrs, slug };
}

export { solutions, type SolutionPage };

0 comments on commit 103eae2

Please sign in to comment.