diff --git a/web/package.json b/web/package.json index a93605d..224c1f6 100644 --- a/web/package.json +++ b/web/package.json @@ -17,6 +17,7 @@ }, "devDependencies": { "@builder.io/qwik-city": "^1.1.4", + "@types/js-yaml": "^4.0.9", "@types/node": "^20.11.16", "@typescript-eslint/eslint-plugin": "^6.20.0", "@typescript-eslint/parser": "^6.20.0", diff --git a/web/public/manifest.json b/web/public/manifest.json index c18e75f..b9c60dc 100644 --- a/web/public/manifest.json +++ b/web/public/manifest.json @@ -1,9 +1,9 @@ { "$schema": "https://json.schemastore.org/web-manifest-combined.json", - "name": "qwik-project-name", - "short_name": "Welcome to Qwik", + "name": "digital-defense", + "short_name": "Digital Defense", "start_url": ".", "display": "standalone", - "background_color": "#fff", - "description": "A Qwik project app." + "background_color": "#5616c6", + "description": "The ultimate personal security checklist" } diff --git a/web/src/routes/_404.tsx b/web/src/routes/_404.tsx new file mode 100644 index 0000000..caed421 --- /dev/null +++ b/web/src/routes/_404.tsx @@ -0,0 +1,12 @@ +// src/routes/_404.tsx +import { component$ } from '@builder.io/qwik'; + +export default component$(() => { + return ( +
+

404 Not Found

+

The page you're looking for doesn't exist.

+ Go back to the homepage +
+ ); +}); diff --git a/web/src/routes/about/index.tsx b/web/src/routes/about/index.tsx index 1c98238..d905070 100644 --- a/web/src/routes/about/index.tsx +++ b/web/src/routes/about/index.tsx @@ -212,11 +212,11 @@ export default component$(() => { }); export const head: DocumentHead = { - title: "Welcome to Qwik", + title: "About | Digital Defense", meta: [ { name: "description", - content: "Qwik site description", + content: "This project aims to give you practical guidance on how to improve your digital security, and protect your privacy online", }, ], }; diff --git a/web/src/routes/checklist/[title]/index.tsx b/web/src/routes/checklist/[title]/index.tsx index 9eb9da5..125ce88 100644 --- a/web/src/routes/checklist/[title]/index.tsx +++ b/web/src/routes/checklist/[title]/index.tsx @@ -4,17 +4,20 @@ import { marked } from 'marked'; import Icon from '~/components/core/icon'; import { ChecklistContext } from '~/store/checklist-context'; +import { useChecklist } from '~/store/local-checklist-store'; import type { Section } from "~/types/PSC"; import Table from '~/components/psc/checklist-table'; export default component$(() => { const checklists = useContext(ChecklistContext); + const localChecklist = useChecklist(); const loc = useLocation(); const slug = loc.params.title; - const section: Section | undefined = checklists.value.find((item: Section) => item.slug === slug); + const section: Section | undefined = (localChecklist.checklist.checklist || checklists.value) + .find((item: Section) => item.slug === slug); const parseMarkdown = (text: string | undefined): string => { return marked.parse(text || '', { async: false }) as string || ''; diff --git a/web/src/routes/checklist/index.tsx b/web/src/routes/checklist/index.tsx index 89941de..dc3e561 100644 --- a/web/src/routes/checklist/index.tsx +++ b/web/src/routes/checklist/index.tsx @@ -2,17 +2,19 @@ import { component$, useContext } from "@builder.io/qwik"; import { ChecklistContext } from '~/store/checklist-context'; import { useLocalStorage } from "~/hooks/useLocalStorage"; +import { useChecklist } from '~/store/local-checklist-store'; import type { Section } from "~/types/PSC"; export default component$(() => { const checklists = useContext(ChecklistContext); + const localChecklist = useChecklist(); const [completed, setCompleted] = useLocalStorage('PSC_PROGRESS', {}); return (
- {checklists.value.map((section: Section, index: number) => ( + {(localChecklist.checklist.checklist || checklists.value).map((section: Section, index: number) => (
diff --git a/web/src/routes/index.tsx b/web/src/routes/index.tsx index 7cf4083..bf02565 100644 --- a/web/src/routes/index.tsx +++ b/web/src/routes/index.tsx @@ -7,14 +7,18 @@ import Progress from "~/components/psc/progress"; import { ChecklistContext } from '~/store/checklist-context'; +import { useChecklist } from '~/store/local-checklist-store'; + export default component$(() => { const checklists = useContext(ChecklistContext); - + + const localChecklist = useChecklist(); + return ( <> - + ); }); diff --git a/web/src/routes/layout.tsx b/web/src/routes/layout.tsx index a62c907..180d311 100644 --- a/web/src/routes/layout.tsx +++ b/web/src/routes/layout.tsx @@ -1,18 +1,16 @@ import { component$, useContextProvider, Slot } from "@builder.io/qwik"; import { routeLoader$, type RequestHandler } from "@builder.io/qwik-city"; - -import Navbar from "../components/furniture/nav"; -import Footer from "../components/furniture/footer"; - -import { ChecklistContext } from "../store/checklist-context"; - -import { type Sections } from "~/types/PSC"; import jsyaml from "js-yaml"; +import Navbar from "~/components/furniture/nav"; +import Footer from "~/components/furniture/footer"; +import { ChecklistContext } from "~/store/checklist-context"; +import type { Sections } from "~/types/PSC"; export const useChecklists = routeLoader$(async () => { - const url = import.meta.env.DEV ? `http://localhost:5173/personal-security-checklist.yml` : '/personal-security-checklist.yml'; - return await fetch(url) + const remoteUrl = 'https://gist.githubusercontent.com/Lissy93/0c26e4255b6fabc2c027ac72a4428aeb/raw/4ccdbc71e0fffdef53472cf98acbe40b0acf982b/personal-security-checklist.yml'; + // TODO: Update this URL to point to the Git repository + return fetch(remoteUrl) .then((res) => res.text()) .then((res) => jsyaml.load(res) as Sections) .catch(() => []); @@ -26,13 +24,11 @@ export const onGet: RequestHandler = async ({ cacheControl }) => { }; export default component$(() => { - const checklists = useChecklists(); - useContextProvider(ChecklistContext, checklists) + useContextProvider(ChecklistContext, checklists); return ( <> - {/*
*/}
diff --git a/web/src/store/local-checklist-store.ts b/web/src/store/local-checklist-store.ts new file mode 100644 index 0000000..0aa8fd1 --- /dev/null +++ b/web/src/store/local-checklist-store.ts @@ -0,0 +1,29 @@ + +import { $, useStore, useOnWindow } from '@builder.io/qwik'; +import jsyaml from 'js-yaml'; +import type { Sections } from '~/types/PSC'; + +export const useChecklist = () => { + const state = useStore<{ checklist: Sections | null }>({ checklist: null }); + + const fetchChecklist = $(async () => { + const localUrl = '/personal-security-checklist.yml'; + return fetch(localUrl) + .then((res) => res.text()) + .then((yamlText) => { + return jsyaml.load(yamlText); + }); + }); + + useOnWindow('load', $(() => { + fetchChecklist().then((checklist) => { + state.checklist = checklist as Sections; + }); + })); + + const setChecklist = $((newChecklist: Sections) => { + state.checklist = newChecklist; + }); + + return { checklist: state, setChecklist }; +}; diff --git a/web/yarn.lock b/web/yarn.lock index 24150c0..2bfda65 100644 --- a/web/yarn.lock +++ b/web/yarn.lock @@ -656,6 +656,11 @@ dependencies: "@types/unist" "^2" +"@types/js-yaml@^4.0.9": + version "4.0.9" + resolved "https://registry.yarnpkg.com/@types/js-yaml/-/js-yaml-4.0.9.tgz#cd82382c4f902fed9691a2ed79ec68c5898af4c2" + integrity sha512-k4MGaQl5TGo/iipqb2UDG2UwjXziSWkh0uysQelTlJpX1qGlpUZYm8PnO4DxG1qBomtJUdYJ6qR6xdIah10JLg== + "@types/json-schema@^7.0.12": version "7.0.15" resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.15.tgz#596a1747233694d50f6ad8a7869fcb6f56cf5841"