Adds reccomended software functionality to sections

This commit is contained in:
Alicia Sykes 2024-02-10 15:18:49 +00:00
parent 9439d7f490
commit 81e77ed22d
5 changed files with 87 additions and 18 deletions

View File

@ -119,9 +119,39 @@ export default component$((props: { section: Section }) => {
filterState.show = originalFilters.show; filterState.show = originalFilters.show;
}); });
const calculateProgress = (): { done: number, total: number, percent: number, disabled: number} => {
let done = 0;
let disabled = 0;
let total = 0;
props.section.checklist.forEach((item) => {
const itemId = generateId(item.point);
if (isIgnored(itemId)) {
disabled += 1;
} else if (isChecked(itemId)) {
done += 1;
total += 1;
} else {
total += 1;
}
});
const percent = Math.round((done / total) * 100);
return { done, total: props.section.checklist.length, percent, disabled };
};
const { done, total, percent, disabled } = calculateProgress();
return ( return (
<> <>
<div class="flex flex-wrap justify-between items-center">
<div>
<progress class="progress w-64" value={percent} max="100"></progress>
<p class="text-xs text-center">
{done} out of {total} ({percent}%)
complete, {disabled} ignored</p>
</div>
<div class="flex flex-wrap gap-2 justify-end my-4"> <div class="flex flex-wrap gap-2 justify-end my-4">
{(sortState.column || JSON.stringify(filterState) !== JSON.stringify(originalFilters)) && ( {(sortState.column || JSON.stringify(filterState) !== JSON.stringify(originalFilters)) && (
@ -135,6 +165,7 @@ export default component$((props: { section: Section }) => {
{showFilters.value ? 'Hide' : 'Show'} Filters {showFilters.value ? 'Hide' : 'Show'} Filters
</button> </button>
</div> </div>
</div>
{showFilters.value && ( {showFilters.value && (
<div class="flex flex-wrap justify-between bg-base-100 rounded px-4 py-1 transition-all" <div class="flex flex-wrap justify-between bg-base-100 rounded px-4 py-1 transition-all"

View File

@ -1,6 +1,6 @@
// src/routes/articles/[slug].tsx // src/routes/articles/[slug].tsx
import { component$, Resource, useResource$, useStore } from '@builder.io/qwik'; import { component$, Resource, useResource$, useStore } from '@builder.io/qwik';
import { useLocation } from '@builder.io/qwik-city'; import { type DocumentHead, useLocation, useDocumentHead } from '@builder.io/qwik-city';
import { marked } from "marked"; import { marked } from "marked";
import articles from '~/data/articles'; import articles from '~/data/articles';
@ -14,6 +14,20 @@ export default component$(() => {
const slug = location.params.slug; const slug = location.params.slug;
const article = articles.find(a => a.slug === slug); const article = articles.find(a => a.slug === slug);
// useDocumentHead(() => {
// if (!article) {
// return {
// title: '404 Not Found | Your Site Name',
// meta: [{ name: 'description', content: 'The requested article was not found.' }],
// };
// }
// return {
// title: `${article.title} | Your Site Name`,
// meta: [{ name: 'description', content: article.description }],
// };
// });
const parseMarkdown = (text: string | undefined): string => { const parseMarkdown = (text: string | undefined): string => {
if (!text) return ''; if (!text) return '';
@ -98,3 +112,13 @@ export default component$(() => {
); );
}); });
export const head: DocumentHead = {
title: "Article | Digital Defense",
meta: [
{
name: "description",
content: "",
},
],
};

View File

@ -4,19 +4,17 @@ import { marked } from 'marked';
import Icon from '~/components/core/icon'; import Icon from '~/components/core/icon';
import { ChecklistContext } from '~/store/checklist-context'; import { ChecklistContext } from '~/store/checklist-context';
import { useChecklist } from '~/store/local-checklist-store';
import type { Section } from "~/types/PSC"; import type { Section } from "~/types/PSC";
import Table from '~/components/psc/checklist-table'; import Table from '~/components/psc/checklist-table';
export default component$(() => { export default component$(() => {
const checklists = useContext(ChecklistContext); const checklists = useContext(ChecklistContext);
const localChecklist = useChecklist();
const loc = useLocation(); const loc = useLocation();
const slug = loc.params.title; const slug = loc.params.title;
const section: Section | undefined = (localChecklist.checklist.checklist || checklists.value) const section: Section | undefined = (checklists.value)
.find((item: Section) => item.slug === slug); .find((item: Section) => item.slug === slug);
const parseMarkdown = (text: string | undefined): string => { const parseMarkdown = (text: string | undefined): string => {
@ -36,6 +34,20 @@ export default component$(() => {
{section && (<Table section={section} />)} {section && (<Table section={section} />)}
</div> </div>
{section && section.softwareLinks && (
<>
<div class="divider my-4">Useful Links</div>
<h3 class="text-xl my-2">Recommended Software</h3>
<ul class="list-disc pl-4">
{section.softwareLinks.map((link, index) => (
<li key={index}>
<a class="link link-primary" href={link.url} title={link.description}>{link.title}</a>
</li>
))}
</ul>
</>
)}
</article> </article>
</div> </div>
); );

View File

@ -8,7 +8,7 @@ import { ChecklistContext } from "~/store/checklist-context";
import type { Sections } from "~/types/PSC"; import type { Sections } from "~/types/PSC";
export const useChecklists = routeLoader$(async () => { export const useChecklists = routeLoader$(async () => {
const remoteUrl = 'https://gist.githubusercontent.com/Lissy93/0c26e4255b6fabc2c027ac72a4428aeb/raw/4ccdbc71e0fffdef53472cf98acbe40b0acf982b/personal-security-checklist.yml'; const remoteUrl = 'https://gist.githubusercontent.com/Lissy93/0c26e4255b6fabc2c027ac72a4428aeb/raw/c36fc0430df223534eaf76c035943f4b343915e4/personal-security-checklist.yml';
// TODO: Update this URL to point to the Git repository // TODO: Update this URL to point to the Git repository
return fetch(remoteUrl) return fetch(remoteUrl)
.then((res) => res.text()) .then((res) => res.text())

View File

@ -13,7 +13,9 @@ export interface Section {
icon: string, icon: string,
color: string, color: string,
checklist: Checklist[], checklist: Checklist[],
furtherLinks?: FurtherLink[], softwareLinks?: Link[],
helpfulTools?: Link[],
furtherResources?: Link[],
} }
export type Priority = 'recommended' | 'optional' | 'advanced'; export type Priority = 'recommended' | 'optional' | 'advanced';
@ -24,8 +26,8 @@ export interface Checklist {
details: string, details: string,
} }
export interface FurtherLink { export interface Link {
title: string, title: string,
url: string, url: string,
description: string, description?: string,
} }