Built new View All page

This commit is contained in:
Alicia Sykes 2024-03-23 00:40:26 +00:00
parent 2d7fdcfc82
commit 653d2bc6db
5 changed files with 300 additions and 49 deletions

View file

@ -70,6 +70,11 @@
email: solidIcons.faEnvelope,
copy: solidIcons.faCopy,
print: solidIcons.faPrint,
// Service link types
website: solidIcons.faGlobe,
sourceCode: solidIcons.faCodeBranch,
viewReport: solidIcons.faShieldHalved,
};
export let iconName: string;

View file

@ -0,0 +1,187 @@
---
import Button from '@components/form/Button.astro';
import { parseMarkdown, formatLink } from '@utils/parse-markdown';
import type { Service } from 'src/types/Service';
import FontAwesome from '@components/form/FontAwesome.svelte';
import DeleteListing from '@components/things/DeleteListing.svelte';
import { slugify } from '@utils/fetch-data';
import GitHubMetrics from '@components/things/ItemGitHubMetrics.astro';
interface Props {
service: Service;
categoryName: string;
sectionName: string;
}
const {
service,
sectionName,
categoryName,
} = Astro.props;
---
<script>
document.addEventListener('DOMContentLoaded', () => {
const serviceIcons = document.querySelectorAll<HTMLImageElement>('.service-icon');
const broke = '/broken-image.png';
serviceIcons.forEach(function(icon) {
icon.onerror = function() {
const imgElement = this as HTMLImageElement;
const serviceUrl = imgElement.getAttribute('data-service-url');
const newSrcAttribute = (imgElement.src.includes('on.ho') ? broke : `https://icon.horse/icon/${serviceUrl}`);
imgElement.src = imgElement.src !== newSrcAttribute ? newSrcAttribute : broke;
imgElement.onerror = null;
};
});
});
</script>
<div class="service" id={slugify(service.name)}>
<!-- <DeleteListing client:load categoryName={categoryName} sectionName={sectionName} serviceName={service.name} /> -->
<div class="service-head">
<a class="service-title" href={`/${slugify(categoryName)}/${slugify(sectionName)}/${slugify(service.name)}`}>
<h4>{service.name}</h4>
</a>
{service.followWith && <p class="follow-with">({service.followWith})</p> }
</div>
<div class="service-body">
<img
width="40"
height="40"
loading="lazy"
decoding="async"
class="service-icon"
alt={`${service.name} Icon`}
data-service-url={formatLink(service.url)}
src={service.icon || `https://icon.horse/icon/${formatLink(service.url)}`}
/>
<div class="service-body">
<p set:html={service.description}></p>
</div>
</div>
<div class="service-links">
<a class="link" href={service.url}>
<FontAwesome iconName="website"/> <span>{formatLink(service.url)}</span>
</a>
{service.github &&
<a class="link" href={`https://github.com/${service.github}`}>
<FontAwesome iconName="sourceCode"/> GitHub
</a>
}
<a href={`/${slugify(categoryName)}/${slugify(sectionName)}/${slugify(service.name)}`}>
<FontAwesome iconName="viewReport" /> View Report
</a>
</div>
</div>
<style lang="scss">
.service {
display: flex;
flex-direction: column;
padding: 1rem;
border: 2px solid var(--foreground);
box-shadow: 6px 6px 0 var(--foreground);
background: var(--accent-fg);
border-radius: var(--curve-sm);
.service-head {
display: flex;
align-items: center;
gap: 0.5rem;
h4 {
margin: 0;
font-size: 1.4rem;
color: var(--foreground);
}
p {
margin: 0;
font-size: 1rem;
opacity: 0.7;
}
a {
text-decoration: none;
}
h4 {
text-decoration: none;
position: relative;
&:after {
background: none repeat scroll 0 0 transparent;
bottom: 0;
content: "";
display: block;
height: 3px;
left: 50%;
position: absolute;
background: var(--accent-3);
transition: width 0.2s ease 0s, left 0.2s ease 0s;
width: 0;
}
&:hover:after {
width: 100%;
left: 0;
}
}
}
.service-body {
display: flex;
align-items: center;
gap: 0.5rem;
img {
border-radius: var(--curve-sm);
}
:global(p) {
display: -webkit-box;
-webkit-line-clamp: 3;
-webkit-box-orient: vertical;
overflow: hidden;
margin: 0.5rem 0;
}
}
.service-links {
display: flex;
gap: 0.5rem;
justify-content: space-between;
a {
color: var(--accent-3);
font-size: 0.8rem;
display: inline-flex;
align-items: center;
gap: 0.25rem;
opacity: 0.7;
text-decoration: none;
max-width: 50%;
min-width: 25%;
&:not(:last-child) {
margin-right: 0.5rem;
}
&:hover {
text-decoration: underline;
opacity: 0.8;
}
:global(svg) {
width: 1rem;
height: 1rem;
}
span {
max-width: calc(100% - 1rem);
text-overflow: ellipsis;
white-space: nowrap;
overflow: hidden;
}
}
}
}
</style>

View file

@ -2,8 +2,8 @@
import Layout from '@layouts/Layout.astro';
import ServiceList from '@components/things/ServiceList.astro';
import type { AwesomePrivacy, Section } from '../types/Service';
import ServiceCard from '@components/things/ServiceCard.astro';
import type { AwesomePrivacy, Section, Service } from '../types/Service';
import { fetchData, slugify } from '@utils/fetch-data';
import FontAwesome from '@components/form/FontAwesome.svelte';
@ -14,10 +14,10 @@ const categories = (await fetchData() as AwesomePrivacy)?.categories || [];
<script>
const toggleSidebar = () => {
const mainContent = document.querySelector('#content');
mainContent && mainContent.classList.toggle('narrow');
const intro = document.querySelector('#welcome-to-all');
const sidebar = document.querySelector('.sidebar');
sidebar && sidebar.classList.toggle('hidden');
intro && intro.classList.toggle('hidden');
const button = document.querySelector('#toggle-sidebar');
if (button) {
button.textContent = (button.textContent === "Show Contents" ? "Hide Contents" : "Show Contents");
@ -34,31 +34,24 @@ const toggleSidebar = () => {
<main>
<div id="content">
<button id="toggle-sidebar">Show Contents</button>
{categories.map((category) => (
<h2 id={`${slugify(category.name)}`}>
<FontAwesome iconName={slugify(category.name)} />
<a href={`/${slugify(category.name)}`}>{category.name}</a>
</h2>
<article>
{category.sections.map((section: Section) => (
<section class="card">
<h3 id={`${slugify(category.name)}-${slugify(section.name)}`}>
<a href={`/${slugify(category.name)}/${slugify(section.name)}`}>{section.name}</a>
</h3>
<ServiceList
services={section.services}
subHeading={true}
buttonLink={`/${slugify(category.name)}/${slugify(section.name)}`}
noGitHubMetrics={true}
sectionName={section.name}
categoryName={category.name}
/>
</section>
))}
</article>
))}
<div id="welcome-to-all" class="hidden">
<p>
Welcome to <a href="/">Awesome Privacy</a>!
Here you'll find a summerized collection of all verified services we have listed.
<br /><br />
Click a section or category heading, to view more listings and privacy tips in that group,
or a service title to view it's complete privacy report
<br /><br />
Looking for something specific? Try the <a href="/search">Search</a> page, or take a
scroll through the <a href="/sitemap">Sitemap</a>
<br /><br />
If you want to make an edit, removal or submit an addition, then either click
the Edit button within any sub-page, or visit our <a href="/about">About</a> page
<br /><br />
This project, all it's data as well as source code is freely availible
on <a href="https://github.com/lissy93/awesome-privacy">GitHub</a>,
licensed under MIT, (C) <a href="https://aliciasykes.com">Alicia Sykes</a> 2024
</p>
</div>
<div class="sidebar hidden">
<p class="sidebar-title">Contents</p>
@ -79,6 +72,37 @@ const toggleSidebar = () => {
))}
</ul>
</div>
{categories.map((category) => (
<h2 id={`${slugify(category.name)}`}>
<FontAwesome iconName={slugify(category.name)} />
<a href={`/${slugify(category.name)}`}>{category.name}</a>
</h2>
<article>
{category.sections.map((section: Section) => (
<h3 id={`${slugify(category.name)}-${slugify(section.name)}`}>
<a href={`/${slugify(category.name)}/${slugify(section.name)}`}>{section.name}</a>
</h3>
<section class="section">
{ section.services.map((service: Service) => (
<ServiceCard service={service} sectionName={section.name} categoryName={category.name}/>
))}
</section>
<div>
{!section || !section.services || section.services.length === 0 ? (
<div class="nothing-yet">
<p>
<strong>⚠️ This section is still a work in progress ⚠️</strong><br />
Check back soon, or help us complete it by submiting a pull request on GitHub.
</p>
</div>
) : null}
</div>
))}
</article>
))}
</div>
</main>
</Layout>
@ -86,23 +110,36 @@ const toggleSidebar = () => {
<style lang="scss">
main {
margin: 2rem auto;
margin: 0 auto 2rem auto;
padding: 1rem;
width: 1000px;
width: 1200px;
max-width: calc(100% - 5rem);
display: flex;
justify-content: space-between;
}
.narrow {
width: 70%;
}
// .narrow {
// width: 70%;
// }
.hidden {
display: none;
}
#content {
margin: 0 auto;
}
#welcome-to-all {
text-align: justify;
width: 600px;
margin: 0 auto;
background: #ffffff4d;
padding: 1rem;
border-radius: var(--curve-sm);
}
#toggle-sidebar {
// float: right;
background: none;
@ -114,31 +151,26 @@ main {
}
}
.sidebar {
width: 25%;
height: 87vh;
overflow: scroll;
position: fixed;
right: 1rem;
border-radius: var(--curve-md);
.sidebar-title {
text-align: center;
font-size: 1.6rem;
margin: 0;
background: var(--accent-3);
color: var(--accent-fg);
border: 2px solid var(--foreground);
box-shadow: 6px 6px 0 var(--foreground);
border-radius: var(--curve-sm);
margin: 0 1rem;
margin: 1rem auto;
text-align: center;
}
ul {
list-style: none;
padding-left: 1.6rem;
column-width: 16rem;
a {
text-decoration: none;
color: var(--foreground);
opacity: 0.6;
transition: all 0.18s ease-in-out;
&:hover {
color: var(--accent);
@ -158,6 +190,13 @@ main {
}
}
.section {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
gap: 1rem;
width: 100%;
margin: 0 auto;
}
.card {
margin: 2rem auto 5rem auto;
@ -168,7 +207,7 @@ main {
}
h2 {
margin: 0;
margin: 2rem auto 0 auto;
font-size: 3rem;
text-align: center;
opacity: 0.6;
@ -189,7 +228,7 @@ h2 {
h3 {
font-size: 2rem;
margin: -2rem 0 2rem -4rem;
margin: 2rem 0 1rem 0;
box-shadow: 6px 6px 0 var(--foreground);
background: var(--accent);
color: var(--accent-fg);
@ -202,5 +241,25 @@ h3 {
}
}
.nothing-yet {
width: 80vw;
margin: 0 auto;
background: var(--accent-fg);
border: 2px solid var(--foreground);
box-shadow: 6px 6px 0 var(--foreground);
border-radius: var(--curve-sm);
display: flex;
width: 80vw;
max-width: 28rem;
p {
font-size: 1.2rem;
opacity: 0.8;
font-style: italic;
text-align: center;
margin-bottom: 3rem;
}
}
</style>

View file

@ -57,11 +57,11 @@ const convertJsonIntoYaml = (service: Service): string => {
*/
const makeResults = (yamlObject: AwesomePrivacy, yamlLines: string[]): LineNumberData => {
const organizedData: LineNumberData = {};
yamlObject.categories.forEach((category) => {
(yamlObject.categories || []).forEach((category) => {
organizedData[category.name] = {};
category.sections.forEach((section) => {
(category.sections || []).forEach((section) => {
organizedData[category.name][section.name] = {};
section.services.forEach((service) => {
(section.services || []).forEach((service) => {
organizedData[category.name][section.name][service.name] = {
lineNumbers: calculateServiceRange(service, category, yamlLines),
yaml: convertJsonIntoYaml(service),

View file

@ -19,7 +19,7 @@ const categories: Category[] = (await fetchData())?.categories;
<p id="press-enter-msg" class="press-enter">Press enter for deep search</p>
</span>
</div>
<p class="sitemap-link">Or, <a href="/sitemap">view all pages</a></p>
<p class="sitemap-link">You can also view <a href="/sitemap">all pages</a> or <a href="/all">all listings</a></p>
<ul class="categories">
{categories.map((category) => (