Starts web app

This commit is contained in:
Alicia Sykes 2024-02-15 22:05:45 +00:00
parent 475aa2b812
commit 5def0fe53f
22 changed files with 11026 additions and 0 deletions

21
web/.gitignore vendored Normal file
View file

@ -0,0 +1,21 @@
# build output
dist/
# generated types
.astro/
# dependencies
node_modules/
# logs
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
# environment variables
.env
.env.production
# macOS-specific files
.DS_Store

4
web/.vscode/extensions.json vendored Normal file
View file

@ -0,0 +1,4 @@
{
"recommendations": ["astro-build.astro-vscode"],
"unwantedRecommendations": []
}

11
web/.vscode/launch.json vendored Normal file
View file

@ -0,0 +1,11 @@
{
"version": "0.2.0",
"configurations": [
{
"command": "./node_modules/.bin/astro dev",
"name": "Development server",
"request": "launch",
"type": "node-terminal"
}
]
}

54
web/README.md Normal file
View file

@ -0,0 +1,54 @@
# Astro Starter Kit: Basics
```sh
npm create astro@latest -- --template basics
```
[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/withastro/astro/tree/latest/examples/basics)
[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/withastro/astro/tree/latest/examples/basics)
[![Open in GitHub Codespaces](https://github.com/codespaces/badge.svg)](https://codespaces.new/withastro/astro?devcontainer_path=.devcontainer/basics/devcontainer.json)
> 🧑‍🚀 **Seasoned astronaut?** Delete this file. Have fun!
![just-the-basics](https://github.com/withastro/astro/assets/2244813/a0a5533c-a856-4198-8470-2d67b1d7c554)
## 🚀 Project Structure
Inside of your Astro project, you'll see the following folders and files:
```text
/
├── public/
│ └── favicon.svg
├── src/
│ ├── components/
│ │ └── Card.astro
│ ├── layouts/
│ │ └── Layout.astro
│ └── pages/
│ └── index.astro
└── package.json
```
Astro looks for `.astro` or `.md` files in the `src/pages/` directory. Each page is exposed as a route based on its file name.
There's nothing special about `src/components/`, but that's where we like to put any Astro/React/Vue/Svelte/Preact components.
Any static assets, like images, can be placed in the `public/` directory.
## 🧞 Commands
All commands are run from the root of the project, from a terminal:
| Command | Action |
| :------------------------ | :----------------------------------------------- |
| `npm install` | Installs dependencies |
| `npm run dev` | Starts local dev server at `localhost:4321` |
| `npm run build` | Build your production site to `./dist/` |
| `npm run preview` | Preview your build locally, before deploying |
| `npm run astro ...` | Run CLI commands like `astro add`, `astro check` |
| `npm run astro -- --help` | Get help using the Astro CLI |
## 👀 Want to learn more?
Feel free to check [our documentation](https://docs.astro.build) or jump into our [Discord server](https://astro.build/chat).

4
web/astro.config.mjs Normal file
View file

@ -0,0 +1,4 @@
import { defineConfig } from 'astro/config';
// https://astro.build/config
export default defineConfig({});

6534
web/package-lock.json generated Normal file

File diff suppressed because it is too large Load diff

23
web/package.json Normal file
View file

@ -0,0 +1,23 @@
{
"name": "web",
"type": "module",
"version": "0.0.1",
"scripts": {
"dev": "astro dev",
"start": "astro dev",
"build": "astro check && astro build",
"preview": "astro preview",
"astro": "astro"
},
"dependencies": {
"@astrojs/check": "^0.5.4",
"astro": "^4.3.6",
"js-yaml": "^4.1.0",
"typescript": "^5.3.3"
},
"devDependencies": {
"@types/js-yaml": "^4.0.9",
"@types/node": "^20.11.19",
"sass": "^1.70.0"
}
}

View file

@ -0,0 +1,161 @@
categories:
- name: Essentials
sections:
- name: Password Managers
services:
- name: 2-Factor Authentication
services:
- name: File Encryption
services:
- name: Browsers
services:
- name: Search Engines
services:
- name: Communication
sections:
- name: Encrypted Messaging
services:
- name: P2P Messaging
services:
- name: Encrypted Email
services:
- name: Email Clients
services:
- name: Mail Forwarding
services:
- name: Email Security Tools
services:
- name: VOIP Clients
services:
- name: Virtual Phone Numbers
services:
- name: Team Collaboration Platforms
services:
- name: Security Tools
sections:
- name: Browser Extensions
services:
- name: Mobile Apps
services:
- name: Online Tools
services:
- name: Networking
sections:
- name: Virtual Private Networks
services:
- name: Self-Hosted Network Security
services:
- name: Mix Networks
services:
- name: Proxies
services:
- name: DNS Providers
services:
- name: DNS Clients
services:
- name: Firewalls
services:
- name: Ad Blockers
services:
- name: Host Block Lists
services:
- name: Router Firmware
services:
- name: Network Analysis
services:
- name: Cloud Hosting
services:
- name: Domain Registrars
services:
- name: DNS Hosting
services:
- name: Pre-Configured Mail-Servers
services:
- name: Productivity
sections:
- name: Digital Notes
services:
- name: Cloud Productivity Suites
services:
- name: Backup and Sync
services:
- name: Encrypted Cloud Storage
services:
- name: File Drop
services:
- name: Browser Sync
services:
- name: Secure Conference Calls
services:
- name: Utilities
sections:
- name: Virtual Machines
services:
- name: PGP Managers
services:
- name: Metadata Removal
services:
- name: Data Erasers
services:
- name: Social
sections:
- name: Social Networks
services:
- name: Video Platforms
services:
- name: Blogging Platforms
services:
- name: News Readers
services:
- name: Proxy Sites
services:
- name: Operating Systems
sections:
- name: Mobile Operating Systems
services:
- name: Desktop Operating Systems
services:
- name: Linux Defences
services:
- name: Windows Defences
services:
- name: Mac OS Defences
services:
- name: Anti-Malware
services:
- name: Development
sections:
- name: Code Hosting
services:
- name: Home Automation
sections:
- name: Home Automation
services:
- name: Voice Assistants
services:
- name: Finance
sections:
- name: Cryptocurrencies
services:
- name: Crypto Wallets
services:
- name: Crypto Exchanges
services:
- name: Virtual Credit Cards
services:
- name: Other Payment Methods
services:
- name: Secure Budgeting
services:

9
web/public/favicon.svg Normal file
View file

@ -0,0 +1,9 @@
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 128 128">
<path d="M50.4 78.5a75.1 75.1 0 0 0-28.5 6.9l24.2-65.7c.7-2 1.9-3.2 3.4-3.2h29c1.5 0 2.7 1.2 3.4 3.2l24.2 65.7s-11.6-7-28.5-7L67 45.5c-.4-1.7-1.6-2.8-2.9-2.8-1.3 0-2.5 1.1-2.9 2.7L50.4 78.5Zm-1.1 28.2Zm-4.2-20.2c-2 6.6-.6 15.8 4.2 20.2a17.5 17.5 0 0 1 .2-.7 5.5 5.5 0 0 1 5.7-4.5c2.8.1 4.3 1.5 4.7 4.7.2 1.1.2 2.3.2 3.5v.4c0 2.7.7 5.2 2.2 7.4a13 13 0 0 0 5.7 4.9v-.3l-.2-.3c-1.8-5.6-.5-9.5 4.4-12.8l1.5-1a73 73 0 0 0 3.2-2.2 16 16 0 0 0 6.8-11.4c.3-2 .1-4-.6-6l-.8.6-1.6 1a37 37 0 0 1-22.4 2.7c-5-.7-9.7-2-13.2-6.2Z" />
<style>
path { fill: #000; }
@media (prefers-color-scheme: dark) {
path { fill: #FFF; }
}
</style>
</svg>

After

Width:  |  Height:  |  Size: 749 B

View file

@ -0,0 +1,49 @@
---
interface Props {
title: string;
body: string;
href: string;
}
const { href, title, body } = Astro.props;
---
<li class="link-card">
<a href={href}>
<h2>
{title}
<span>&rarr;</span>
</h2>
<p>
{body}
</p>
</a>
</li>
<style lang="scss">
.link-card {
color: var(--foreground);
background: var(--background);
border: 2px solid var(--foreground);
box-shadow: 6px 6px 0 var(--foreground);
font-family: "Lekton", sans-serif;
font-weight: 700;
transition: all ease-in-out 0.1s;
list-style: none;
&:hover {
box-shadow: 8px 8px 0 var(--foreground);
background: var(--accent);
color: var(--background);
}
a {
box-sizing: border-box;
color: currentColor;
text-decoration: none;
transition: all ease-in-out 0.1s;
}
h2 {
margin: 0;
}
}
</style>

View file

@ -0,0 +1,99 @@
<div class="hero">
<svg version="1.0" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 300 260">
<g transform="translate(0,260) scale(0.1,-0.1)"
fill="var(--accent-fg)" stroke="none">
<path d="M1380 2464 c-543 -69 -956 -465 -1036 -994 -43 -288 25 -581 192
-830 25 -37 56 -78 71 -91 l25 -24 -7 25 c-4 14 -11 27 -15 30 -11 9 -89 127
-120 184 -54 97 -107 262 -126 386 -10 70 -7 272 6 337 48 240 145 434 302
599 372 391 974 471 1423 189 204 -128 341 -282 442 -495 71 -149 102 -291
104 -470 1 -148 -11 -227 -60 -390 -13 -43 -85 -184 -134 -264 -61 -99 -38
-100 27 -1 158 237 224 534 182 815 -73 481 -430 864 -906 971 -83 19 -298 32
-370 23z"/>
<path d="M1675 2215 c-33 -7 -126 -17 -208 -22 -124 -8 -151 -12 -175 -30 -15
-11 -74 -101 -130 -199 -86 -148 -103 -173 -100 -141 2 20 3 37 3 37 -16 0
-161 -58 -223 -89 -142 -71 -204 -155 -172 -231 23 -56 124 -135 216 -170 46
-18 9 25 -55 64 -180 110 -172 205 25 305 119 59 174 75 189 51 11 -17 34 -11
58 15 12 14 60 92 107 173 56 97 94 151 110 159 14 6 95 17 180 22 85 6 173
16 195 21 58 14 132 12 163 -4 42 -21 59 -46 72 -101 27 -113 51 -183 68 -198
10 -9 71 -30 136 -46 204 -52 296 -107 296 -180 0 -30 -8 -43 -58 -91 -32 -30
-97 -77 -144 -103 -47 -26 -96 -59 -109 -73 l-24 -26 53 20 c119 46 274 158
308 224 36 70 3 134 -102 190 -66 35 -270 98 -320 98 -19 0 -25 13 -48 113
-36 149 -48 171 -109 202 -57 28 -107 31 -202 10z"/>
<path d="M588 1283 c32 -43 114 -153 181 -246 l122 -167 -57 -63 c-65 -72
-107 -133 -157 -234 l-37 -72 67 -61 c170 -156 392 -261 623 -296 288 -43 579
24 832 193 91 60 228 190 228 215 0 50 -107 279 -165 352 -15 19 -16 19 -75
-9 -91 -43 -79 -54 31 -29 24 5 30 0 63 -54 37 -62 87 -174 100 -226 7 -27 1
-35 -66 -101 -415 -406 -1108 -415 -1535 -22 -25 23 -43 48 -43 61 0 34 75
162 139 236 81 93 85 103 66 139 -8 17 -76 113 -150 214 -74 102 -135 189
-135 195 0 6 49 11 123 14 67 2 128 7 135 11 31 20 -11 27 -174 27 l-175 0 59
-77z"/>
<path d="M2125 1351 c-11 -18 21 -26 128 -29 59 -3 107 -8 107 -12 0 -5 -46
-70 -102 -147 -178 -242 -209 -293 -180 -293 5 0 68 82 142 183 74 100 155
210 182 245 l48 62 -159 0 c-88 0 -162 -4 -166 -9z"/>
<path d="M967 1323 c-23 -26 -22 -46 9 -107 63 -126 163 -172 286 -130 l46 15
47 -33 c43 -31 53 -33 140 -36 75 -3 101 0 136 15 59 27 106 68 129 114 25 48
25 81 1 103 -16 15 -34 16 -142 10 -142 -8 -318 7 -460 37 -152 33 -171 34
-192 12z m309 -68 c127 -18 313 -22 412 -11 59 8 62 7 62 -14 0 -47 -53 -111
-118 -144 -45 -23 -147 -31 -201 -16 -26 7 -59 26 -78 45 l-34 34 -42 -19
c-50 -23 -137 -26 -175 -6 -40 21 -78 65 -101 116 -35 78 -34 79 69 53 50 -12
143 -30 206 -38z"/>
</g>
</svg>
<h1>Awesome Privacy</h1>
<p class="intro">
Your guide to finding privacy-respecting alternatives to popular software and services.
</p>
</div>
<style lang="scss">
.hero {
background: var(--accent-fg);
color: var(--accent-fg);
border-radius: var(--curve-sm);
padding: 2rem 4rem;
display: flex;
flex-direction: column;
gap: 2rem;
}
svg {
position: absolute;
top: -32px;
left: 50%;
transform: translatex(-50%);
width: 220px;
height: auto;
opacity: 0.6;
display: none;
}
h1 {
margin: 0;
font-size: 5rem;
font-weight: 700;
line-height: 1;
text-align: center;
font-family: 'Libre Franklin', sans-serif;
color: var(--accent-3);
-webkit-text-fill-color: var(--accent-3);
-webkit-text-stroke-width: 2px;
-webkit-text-stroke-color: var(--foreground);
text-shadow: 3px 3px 0 var(--foreground);
}
.intro {
text-align: center;
font-size: 1.6rem;
padding: 0.5rem 1rem;
color: var(--accent-fg);
background: var(--accent-3);
border: 2px solid var(--foreground);
box-shadow: 6px 6px 0 var(--foreground);
font-family: "Lekton", sans-serif;
font-weight: 700;
max-width: 735px;
margin: 0 auto;
}
</style>

1
web/src/env.d.ts vendored Normal file
View file

@ -0,0 +1 @@
/// <reference types="astro/client" />

View file

@ -0,0 +1,48 @@
---
interface Props {
title: string;
}
const { title } = Astro.props;
---
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="description" content="Astro description" />
<meta name="viewport" content="width=device-width" />
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
<meta name="generator" content={Astro.generator} />
<title>{title}</title>
</head>
<body>
<slot />
</body>
</html>
<style is:global>
@import '../styles/values.css';
@import '../styles/typography.css';
</style>
<style is:global>
:root {
--accent: 136, 58, 234;
--accent-light: 224, 204, 250;
--accent-dark: 49, 10, 101;
--accent-gradient: linear-gradient(
45deg,
rgb(var(--accent)),
rgb(var(--accent-light)) 30%,
white 60%
);
}
html {
background: var(--background);
background-size: 224px;
}
</style>

View file

@ -0,0 +1,68 @@
---
import yaml from 'js-yaml';
import Layout from '../layouts/Layout.astro';
import Card from '../components/Card.astro';
import Hero from '../components/Hero.astro';
import { AwesomePrivacy, Section, Service } from '../types/Service';
const { title, otherSections, services } = Astro.props;
export async function getStaticPaths() {
const fetchData = async (): Promise<AwesomePrivacy> => {
return await fetch('http://localhost:4321/awesome-privacy.yml')
.then((res) => res.text())
.then((data) => yaml.load(data))
.catch((err) => console.error(err));
};
const slugify = (title: string) => {
return title.toLowerCase().replace(/\s/g, '-');
};
const pages = await fetchData().then((data) => {
const results: { slug: string, title: string, otherSections: Section[], services: Service[] }[] = [];
data.categories.forEach((service) => {
const sections = service.sections.map((section) => ({
slug: `${slugify(service.name)}/${slugify(section.name)}`,
title: section.name,
services: section.services,
otherSections: service.sections,
}));
results.push(...sections);
});
return results;
});
return pages.map(({ slug, title, otherSections, services }) => {
return {
params: { section: slug },
props: { title, otherSections, services },
};
});
}
---
<Layout title="Awesome Privacy">
<h1>{title}</h1>
</Layout>
<style lang="scss">
main {
margin: auto;
padding: 1rem;
width: 1000px;
max-width: calc(100% - 2rem);
font-size: 20px;
line-height: 1.6;
}
</style>

View file

@ -0,0 +1,73 @@
---
import Layout from '../layouts/Layout.astro';
import Card from '../components/Card.astro';
import Hero from '../components/Hero.astro';
import yaml from 'js-yaml';
import type { AwesomePrivacy, Section, Service } from '../types/Service';
interface Props {
title: string;
sections: Section[];
}
const { title, sections } = Astro.props;
export async function getStaticPaths() {
const fetchData = async (): Promise<AwesomePrivacy> => {
return await fetch('http://localhost:4321/awesome-privacy.yml')
.then((res) => res.text())
.then((data) => yaml.load(data))
.catch((err) => console.error(err));
};
const slugify = (title: string) => {
return title.toLowerCase().replace(/\s/g, '-');
};
const pages = await fetchData().then((data) => {
return data.categories.map((category) => {
return {
category: slugify(category.name),
title: category.name,
sections: category.sections,
};
});
});
return pages.map(({ category, title, sections }) => {
return {
params: { category },
props: { title, sections },
};
});
}
---
<Layout title="Awesome Privacy">
<!-- <Hero /> -->
<main>
<h1>Title: {title}</h1>
<!-- {sections.map((section) => (
<section>
<h2>{section.name}</h2>
</section>
))} -->
</main>
</Layout>
<style lang="scss">
main {
margin: auto;
padding: 1rem;
width: 1000px;
max-width: calc(100% - 2rem);
color: red;
font-size: 20px;
line-height: 1.6;
}
</style>

View file

@ -0,0 +1,67 @@
---
import yaml from 'js-yaml';
import Layout from '../../layouts/Layout.astro';
import Card from '../../components/Card.astro';
import Hero from '../../components/Hero.astro';
import { AwesomePrivacy, Section, Service } from '../../types/Service';
export async function getStaticPaths() {
const fetchData = async (): Promise<AwesomePrivacy> => {
return await fetch('http://localhost:4321/awesome-privacy.yml')
.then((res) => res.text())
.then((data) => yaml.load(data))
.catch((err) => console.error(err));
};
const slugify = (title: string) => {
return title.toLowerCase().replace(/\s/g, '-');
};
const pages = await fetchData().then((data) => {
const results: { slug: string, title: string, otherSections: Section[], services: Service[] }[] = [];
data.categories.forEach((service) => {
const sections = service.sections.map((section) => ({
slug: `${slugify(service.name)}/${slugify(section.name)}`,
title: section.name,
services: section.services,
otherSections: service.sections,
}));
results.push(...sections);
});
return results;
});
return pages.map(({ slug, title, otherSections, services }) => {
return {
params: { slug },
props: { title, otherSections, services },
};
});
}
---
<Layout title="Awesome Privacy">
</Layout>
<style lang="scss">
main {
margin: auto;
padding: 1rem;
width: 1000px;
max-width: calc(100% - 2rem);
color: white;
font-size: 20px;
line-height: 1.6;
}
</style>

26
web/src/pages/index.astro Normal file
View file

@ -0,0 +1,26 @@
---
import Layout from '../layouts/Layout.astro';
import Card from '../components/Card.astro';
import Hero from '../components/Hero.astro';
---
<Layout title="Awesome Privacy">
<Hero />
<main>
<Card title="Email" body="" href="/" />
</main>
</Layout>
<style lang="scss">
main {
margin: auto;
padding: 1rem;
width: 1000px;
max-width: calc(100% - 2rem);
color: white;
font-size: 20px;
line-height: 1.6;
}
</style>

View file

@ -0,0 +1,30 @@
@import url('https://fonts.googleapis.com/css2?family=Lekton:ital,wght@0,400;0,700;1,400&family=Libre+Franklin:ital,wght@0,100..900;1,100..900&family=Rubik:ital,wght@0,300..900;1,300..900&display=swap');
html {
font-family: system-ui, sans-serif;
}
code {
font-family:
Menlo,
Monaco,
Lucida Console,
Liberation Mono,
DejaVu Sans Mono,
Bitstream Vera Sans Mono,
Courier New,
monospace;
}
.heading, h1, h2, h3, h4, h5, h6 {
font-family: "Libre Franklin", sans-serif;
font-optical-sizing: auto;
font-weight: 800;
font-style: normal;
}
.subtitle {
font-family: "Lekton", sans-serif;
font-weight: 700;
font-style: normal;
}

13
web/src/styles/values.css Normal file
View file

@ -0,0 +1,13 @@
:root {
--accent: #f72b77;
--accent-fg: #fff;
--accent-2: #ffdf60;
--accent-3: #5f53f4;
--foreground: #13151a;
--curve-sm: 4px;
--curve-md: 6px;
--curve-lg: 12px;
}

35
web/src/types/Service.ts Normal file
View file

@ -0,0 +1,35 @@
export interface ShortService {
name: string;
description: string;
url: string;
}
export interface Service {
name: string;
description: string;
url: string;
github: string;
followWith?: string;
}
export interface Section {
name: string;
services: Service[];
notableMentions: ShortService[];
furtherInfo: string;
}
export interface ServiceStats {
isOpenSource: boolean;
author: string;
authorUrl: string;
}
export interface AwesomePrivacy {
categories: Array<{
name: string;
sections: Array<Section>;
}>;
}

3
web/tsconfig.json Normal file
View file

@ -0,0 +1,3 @@
{
"extends": "astro/tsconfigs/strict"
}

3693
web/yarn.lock Normal file

File diff suppressed because it is too large Load diff