Loads of updates

This commit is contained in:
Alicia Sykes 2024-02-22 10:53:19 +00:00
parent 5181632fde
commit 3a7427b00f
11 changed files with 201 additions and 89 deletions

View file

@ -6,6 +6,9 @@
export const iconMap: Record<string, IconDefinition> = {
// Branding
logo: solidIcons.faEyeSlash,
// GitHub Stat Icons
github: brands.faGithubAlt,
stars: solidIcons.faStar,

View file

@ -1,8 +1,13 @@
---
import FontAwesome from "@components/form/FontAwesome.svelte"
---
<div class="nav">
<a href="/"><h1>Awesome Privacy</h1></a>
<a href="/" class="homepage">
<FontAwesome iconName="logo" />
<h1>Awesome Privacy</h1>
</a>
<nav>
<a href="/browse">Browse</a>
<a href="/search">Search</a>
@ -20,8 +25,11 @@
gap: 1rem;
border-bottom: 2px solid var(--foreground);
a {
.homepage {
text-decoration: none;
display: flex;
align-items: center;
padding: 0 0.5rem;
h1 {
margin: 0;
font-size: 2.4rem;
@ -29,6 +37,18 @@
color: var(--foreground);
font-family: "Lekton", sans-serif;
}
:global(svg) {
width: 2.5rem;
height: 2.5rem;
color: var(--accent-3);
transition: all 0.2s ease-in-out;
}
&:hover {
:global(svg) {
color: var(--accent);
transform: scale(1.05);
}
}
}
nav {

View file

@ -4,23 +4,61 @@ import NavBar from '@components/scafold/NavBar.astro';
import Footer from '@components/scafold/Footer.astro';
interface Props {
title: string;
hideNav?: boolean;
title?: string; // Page title
description?: string; // Overide description tag
keywords?: string; // Overide keywords tag
hideNav?: boolean; // Don't show the navbar (just homepage)
author?: string; // Author of the content
}
const { title, hideNav } = Astro.props;
const {
title='Awesome Privacy | The Ultimate List of Private Apps',
description='Your guide to finding privacy-respecting alternatives to popular software and services.',
keywords='security, privacy, awesome privacy, data collection, free software, open source, privacy tools, privacy respecting software',
hideNav=false,
author='Alicia Sykes'
} = 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} />
<!-- Core info -->
<title>{title}</title>
<meta name="description" content={description}>
<meta name="keywords" content={keywords}>
<meta name="author" content={author}>
<!-- Page info, viewport, Astro credit -->
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="viewport" content="width=device-width" />
<meta name="generator" content={Astro.generator} />
<!-- Icons and colors -->
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
<link rel="icon" type="image/png" sizes="64x64" href="/favicon.png">
<link rel="apple-touch-icon" sizes="180x180" href="/apple-touch-icon.png">
<!-- Social media meta tags (Open Graphh + Twitter) -->
<meta property="og:type" content="website">
<meta property="og:url" content="https://awesome-privacy.xyz">
<meta property="og:title" content={title}>
<meta property="og:description" content={description}>
<meta property="og:image" content="/banner.png">
<meta name="twitter:card" content="summary_large_image">
<meta name="twitter:url" content="https://awesome-privacy.xyz">
<meta name="twitter:title" content={title}>
<meta name="twitter:description" content={description}>
<meta name="twitter:image" content="/banner.png">
<!-- Non-tracking hit counter -->
<script defer
type="text/partytown"
data-domain="awesome-privacy.xyz"
src="https://no-track.as93.net/js/script.js">
</script>
</head>
<body>
{!hideNav && <NavBar /> }

View file

@ -17,11 +17,58 @@ interface Props {
notableMentions?: ShortService[] | string,
furtherInfo?: string,
wordOfWarning?: string,
alternativeTo?: string[];
categoryName: string,
otherSections: Section[],
}
const { slug, title, otherSections, services, notableMentions, furtherInfo, wordOfWarning, categoryName, intro } = Astro.props;
const {
title, otherSections, services, notableMentions, furtherInfo, wordOfWarning,
alternativeTo, categoryName, intro,
} = Astro.props;
/**
* Make a list of keywords, for the <meta keywords> tag
*/
const makeKeyWordTag = () => {
const keywords = [];
keywords.push(`free and open source ${title} software`);
keywords.push(`private ${title} comparison`);
alternativeTo?.forEach((alt: string) => {
keywords.push(`privacy-respecting ${alt} alternative`);
keywords.push(`free open source ${alt} alternative`);
});
services.forEach((serv: Service) => {
keywords.push(serv.name);
});
keywords.push('ad free');
keywords.push('open source software');
keywords.push('privacy respecting apps');
return keywords.join(', ');
};
/**
* Make a page title
*/
const makePageTitle = () => {
return `${title} | Awesome Privacy`;
};
/**
* Make a string page intro, for the description tag
*/
const makeDescriptionTag = () => {
let description = `A list of privacy respecting ${title}. `;
if (services.length > 0) {
const serviceList = services.map((serv: Service) => serv.name);
description += `Compare ${serviceList.join(', ')} and more private apps and services. `
} else {
description += `Find private apps and services. This section is still a work in progress. `;
}
description += 'All this, and much more at Awesome Privacy, '
description += 'the free and open source list of private software alternatives.';
return description;
};
export async function getStaticPaths() {
@ -37,6 +84,7 @@ const pages = await fetchData().then((data) => {
notableMentions: section.notableMentions,
furtherInfo: section.furtherInfo,
wordOfWarning: section.wordOfWarning,
alternativeTo: section.alternativeTo,
categoryName: category.name,
otherSections: category.sections,
}));
@ -45,11 +93,8 @@ const pages = await fetchData().then((data) => {
return results;
});
return pages.map(({ slug, title, otherSections, services, notableMentions, furtherInfo, wordOfWarning, categoryName, intro }) => {
return {
params: { section: slug },
props: { title, otherSections, services, notableMentions, furtherInfo, wordOfWarning, categoryName, intro },
};
return pages.map((props: Props) => {
return {params: { section: props.slug }, props };
});
}
@ -64,7 +109,7 @@ const { previous, next } = makePaginationLinks();
---
<Layout title="Awesome Privacy">
<Layout title={makePageTitle()} keywords={makeKeyWordTag()} description={makeDescriptionTag()} >
<Main>
<h2>{title}</h2>

View file

@ -37,7 +37,7 @@ export async function getStaticPaths() {
---
<Layout title="Awesome Privacy">
<Layout title={`${title} | Awesome Privacy`}>
<Main>
<SectionList title={title} sections={sections} bigTitle={true} />
</Main>

View file

@ -101,10 +101,15 @@ export const socials = [
},
];
const description = 'Privacy is a fundamental human right; '
+ 'without it, we\'re just open books in a world where everyone\'s '
+ 'watching. Let\'s take control back.\n'
+ 'Migrating open-source applications which do not collect, sell or log your data is a great first step.'
+ 'Awesome Privacy is a directory of alternative privacy-respecting software and services.';
---
<Layout title="Awesome Privacy">
<Layout title="About | Awesome Privacy" description={description}>
<div class="about-page">
<Main>
<h2>Objective</h2>
@ -307,7 +312,7 @@ h3 {
font-weight: 300;
color: var(--accent-3);
text-align: center;
max-width: 500px;
max-width: 550px;
margin: 0 auto;
}
small {

View file

@ -6,6 +6,7 @@ import SectionList from '@components/things/SectionList.astro';
import { fetchData } from '@utils/fetch-data';
const categories = (await fetchData())?.categories;
---
<Layout title="Browse">

View file

@ -1,67 +0,0 @@
---
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>

View file

@ -11,9 +11,16 @@ import Button from '@components/form/Button.astro';
const categories = (await fetchData())?.categories || [];
const description = 'Privacy is a fundamental human right; '
+ 'without it, we\'re just open books in a world where everyone\'s '
+ 'watching. Let\'s take control back.\n'
+ 'Migrating open-source applications which do not collect, sell or log your data is a great first step.'
+ 'Awesome Privacy is a directory of alternative privacy-respecting software and services.';
---
<Layout title="Awesome Privacy" hideNav={true}>
<Layout title="Home | Awesome Privacy" hideNav={true} description={description}>
<Hero />
<main>
<h2>
@ -40,6 +47,10 @@ const categories = (await fetchData())?.categories || [];
Awesome Privacy is a collection of privacy-respecting services and tools.
The aim is to help you escape big tech, and choose software that respects your privacy.
</p>
<p>
Why? Because privacy is a fundamental human right; without it, we're just open books
in a world where everyone's watching. Let's take control back.
</p>
<p>
Noticed something that should be added / removed / ammended?
We're a community-driven resource, so welcome contributions of any nature.

View file

@ -1,4 +1,59 @@
@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');
/* Fallback to Google Fonts for specific weights and styles */
@import url('https://fonts.googleapis.com/css2?family=Lekton:wght@700&family=Libre+Franklin:wght@800&family=Rubik:ital,wght@0,400;0,500;0,600;1,400;1,500;1,600&display=swap');
/* Rubik Font Faces */
@font-face {
font-family: 'Rubik';
font-style: normal;
font-weight: 400;
src: local('Rubik'), url('/fonts/Rubik/Rubik-Regular.ttf') format('truetype');
}
@font-face {
font-family: 'Rubik';
font-style: italic;
font-weight: 400;
src: local('Rubik Italic'), url('/fonts/Rubik/Rubik-Italic.ttf') format('truetype');
}
@font-face {
font-family: 'Rubik';
font-style: normal;
font-weight: 500;
src: local('Rubik Medium'), url('/fonts/Rubik/Rubik-Medium.ttf') format('truetype');
}
@font-face {
font-family: 'Rubik';
font-style: italic;
font-weight: 500;
src: local('Rubik Medium Italic'), url('/fonts/Rubik/Rubik-MediumItalic.ttf') format('truetype');
}
@font-face {
font-family: 'Rubik';
font-style: normal;
font-weight: 600;
src: local('Rubik SemiBold'), url('/fonts/Rubik/Rubik-SemiBold.ttf') format('truetype');
}
@font-face {
font-family: 'Rubik';
font-style: italic;
font-weight: 600;
src: local('Rubik SemiBold Italic'), url('/fonts/Rubik/Rubik-SemiBoldItalic.ttf') format('truetype');
}
/* Libre Franklin Font Faces */
@font-face {
font-family: 'Libre Franklin';
font-style: normal;
font-weight: 500;
src: local('Libre Franklin Bold'), url('/fonts/Libre_Franklin/LibreFranklin-Bold.ttf') format('truetype');
}
/* Lekton Font Faces */
@font-face {
font-family: 'Lekton';
font-style: normal;
font-weight: 700;
src: local('Lekton Bold'), url('/fonts/Lekton/Lekton-Bold.ttf') format('truetype');
}
html {
font-family: system-ui, sans-serif;

View file

@ -25,6 +25,7 @@ export interface Section {
notableMentions?: ShortService[] | string;
furtherInfo?: string;
wordOfWarning?: string;
alternativeTo?: string[];
}
export interface ServiceStats {