mirror of
https://github.com/Lissy93/personal-security-checklist.git
synced 2024-10-01 01:35:37 -04:00
Adds reccomended software functionality to sections
This commit is contained in:
parent
9439d7f490
commit
81e77ed22d
@ -119,21 +119,52 @@ 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)) && (
|
||||||
<button class="btn btn-sm hover:btn-primary" onClick$={resetFilters}>
|
<button class="btn btn-sm hover:btn-primary" onClick$={resetFilters}>
|
||||||
<Icon width={18} height={16} icon="clear"/>
|
<Icon width={18} height={16} icon="clear"/>
|
||||||
Reset Filters
|
Reset Filters
|
||||||
|
</button>
|
||||||
|
)}
|
||||||
|
<button class="btn btn-sm hover:btn-primary" onClick$={() => { showFilters.value = !showFilters.value; }}>
|
||||||
|
<Icon width={18} height={16} icon="filters"/>
|
||||||
|
{showFilters.value ? 'Hide' : 'Show'} Filters
|
||||||
</button>
|
</button>
|
||||||
)}
|
</div>
|
||||||
<button class="btn btn-sm hover:btn-primary" onClick$={() => { showFilters.value = !showFilters.value; }}>
|
|
||||||
<Icon width={18} height={16} icon="filters"/>
|
|
||||||
{showFilters.value ? 'Hide' : 'Show'} Filters
|
|
||||||
</button>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{showFilters.value && (
|
{showFilters.value && (
|
||||||
|
@ -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: "",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
|
@ -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>
|
||||||
);
|
);
|
||||||
|
@ -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())
|
||||||
|
@ -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,
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user