mirror of
https://github.com/privacyguides/privacyguides.org.git
synced 2026-07-25 18:01:43 +00:00
Make sidebar sections open when clicked
This commit is contained in:
+16
-16
@@ -53,6 +53,22 @@ aliases:
|
|||||||
imageClass="hx:top-[40%] hx:left-[24px] hx:w-[180%] hx:sm:w-[110%] hx:dark:opacity-80"
|
imageClass="hx:top-[40%] hx:left-[24px] hx:w-[180%] hx:sm:w-[110%] hx:dark:opacity-80"
|
||||||
link="wiki"
|
link="wiki"
|
||||||
>}}
|
>}}
|
||||||
|
{{< hextra/feature-card
|
||||||
|
title="Privacy Tools"
|
||||||
|
subtitle="The essential tools you need to safeguard your digital privacy, chosen by community consensus."
|
||||||
|
class="hx:aspect-auto hx:md:aspect-[1.1/1] hx:max-md:min-h-[340px] pg:colored-card"
|
||||||
|
image="pg-home-privacy-tools.png"
|
||||||
|
imageClass="hx:top-[40%] hx:left-[24px] hx:w-[180%] hx:sm:w-[110%] hx:dark:opacity-80"
|
||||||
|
link="tools"
|
||||||
|
>}}
|
||||||
|
{{< hextra/feature-card
|
||||||
|
title="News Briefs"
|
||||||
|
subtitle="Stay updated with the latest news and developments in the world of cybersecurity, privacy, and digital rights."
|
||||||
|
class="hx:aspect-auto hx:md:aspect-[1.1/1] hx:max-md:min-h-[340px] pg:colored-card"
|
||||||
|
image="pg-home-privacy-news.png"
|
||||||
|
imageClass="hx:top-[40%] hx:left-[24px] hx:w-[180%] hx:sm:w-[110%] hx:dark:opacity-80"
|
||||||
|
link="https://www.privacyguides.org/news/"
|
||||||
|
>}}
|
||||||
{{< hextra/feature-card
|
{{< hextra/feature-card
|
||||||
title="Educational Videos"
|
title="Educational Videos"
|
||||||
subtitle="Watch our educational videos to learn more about digital privacy and how to protect yourself online."
|
subtitle="Watch our educational videos to learn more about digital privacy and how to protect yourself online."
|
||||||
@@ -69,14 +85,6 @@ aliases:
|
|||||||
imageClass="hx:top-[40%] hx:left-[24px] hx:w-[180%] hx:sm:w-[110%] hx:dark:opacity-80"
|
imageClass="hx:top-[40%] hx:left-[24px] hx:w-[180%] hx:sm:w-[110%] hx:dark:opacity-80"
|
||||||
link="activism"
|
link="activism"
|
||||||
>}}
|
>}}
|
||||||
{{< hextra/feature-card
|
|
||||||
title="Privacy Tools"
|
|
||||||
subtitle="The essential tools you need to safeguard your digital privacy, chosen by community consensus."
|
|
||||||
class="hx:aspect-auto hx:md:aspect-[1.1/1] hx:max-md:min-h-[340px] pg:colored-card"
|
|
||||||
image="pg-home-privacy-tools.png"
|
|
||||||
imageClass="hx:top-[40%] hx:left-[24px] hx:w-[180%] hx:sm:w-[110%] hx:dark:opacity-80"
|
|
||||||
link="tools"
|
|
||||||
>}}
|
|
||||||
{{< hextra/feature-card
|
{{< hextra/feature-card
|
||||||
title="Community Forum"
|
title="Community Forum"
|
||||||
subtitle="Join the conversation, get answers, and connect with others who share your commitment to digital privacy."
|
subtitle="Join the conversation, get answers, and connect with others who share your commitment to digital privacy."
|
||||||
@@ -85,14 +93,6 @@ aliases:
|
|||||||
imageClass="hx:top-[40%] hx:left-[24px] hx:w-[180%] hx:sm:w-[110%] hx:dark:opacity-80"
|
imageClass="hx:top-[40%] hx:left-[24px] hx:w-[180%] hx:sm:w-[110%] hx:dark:opacity-80"
|
||||||
link="https://discuss.privacyguides.net"
|
link="https://discuss.privacyguides.net"
|
||||||
>}}
|
>}}
|
||||||
{{< hextra/feature-card
|
|
||||||
title="News Briefs"
|
|
||||||
subtitle="Stay updated with the latest news and developments in the world of cybersecurity, privacy, and digital rights."
|
|
||||||
class="hx:aspect-auto hx:md:aspect-[1.1/1] hx:max-md:min-h-[340px] pg:colored-card"
|
|
||||||
image="pg-home-privacy-news.png"
|
|
||||||
imageClass="hx:top-[40%] hx:left-[24px] hx:w-[180%] hx:sm:w-[110%] hx:dark:opacity-80"
|
|
||||||
link="https://www.privacyguides.org/news/"
|
|
||||||
>}}
|
|
||||||
{{< /hextra/feature-grid >}}
|
{{< /hextra/feature-grid >}}
|
||||||
|
|
||||||
<div class="hx:mt-12"></div>
|
<div class="hx:mt-12"></div>
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
# Hugo configuration file
|
# Hugo configuration file
|
||||||
title: Privacy Guides
|
title: Privacy Guides
|
||||||
relativeURLs: true
|
baseURL: https://wiki.privacyguides.org
|
||||||
|
locale: en-US
|
||||||
|
|
||||||
# temporarily ignore blog content
|
# temporarily ignore blog content
|
||||||
ignoreFiles:
|
ignoreFiles:
|
||||||
@@ -101,17 +102,3 @@ outputs:
|
|||||||
home: [HTML, RSS, llms]
|
home: [HTML, RSS, llms]
|
||||||
page: [HTML, markdown, RSS]
|
page: [HTML, markdown, RSS]
|
||||||
section: [HTML, RSS]
|
section: [HTML, RSS]
|
||||||
|
|
||||||
defaultContentLanguage: en
|
|
||||||
defaultContentLanguageInSubdir: false
|
|
||||||
languages:
|
|
||||||
en:
|
|
||||||
languageName: English
|
|
||||||
weight: 1
|
|
||||||
# baseURL: https://en.privacyguides.org
|
|
||||||
contentDir: 'content'
|
|
||||||
# fr:
|
|
||||||
# languageName: Français
|
|
||||||
# weight: 2
|
|
||||||
# baseURL: https://fr.privacyguides.org
|
|
||||||
# contentDir: 'translations/fr'
|
|
||||||
|
|||||||
@@ -0,0 +1,199 @@
|
|||||||
|
<script>
|
||||||
|
(() => {
|
||||||
|
const redirectCache = new Map();
|
||||||
|
|
||||||
|
const forceNavigatePaths = new Set([]);
|
||||||
|
|
||||||
|
function normalizePathname(pathname) {
|
||||||
|
const normalized = pathname.replace(/\/+$/, '');
|
||||||
|
return normalized || '/';
|
||||||
|
}
|
||||||
|
|
||||||
|
function urlsReferToSamePage(firstUrl, secondUrl) {
|
||||||
|
const first = new URL(firstUrl, location.href);
|
||||||
|
const second = new URL(secondUrl, location.href);
|
||||||
|
|
||||||
|
return (
|
||||||
|
first.origin === second.origin &&
|
||||||
|
normalizePathname(first.pathname) ===
|
||||||
|
normalizePathname(second.pathname) &&
|
||||||
|
first.search === second.search
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function getMetaRefreshDestination(documentCopy, sourceUrl) {
|
||||||
|
const refresh = documentCopy.querySelector(
|
||||||
|
'meta[http-equiv="refresh" i]'
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!refresh) return null;
|
||||||
|
|
||||||
|
const content = refresh.getAttribute('content') || '';
|
||||||
|
const match = content.match(
|
||||||
|
/^\s*\d+(?:\.\d+)?\s*;\s*url\s*=\s*(.+?)\s*$/i
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!match) return null;
|
||||||
|
|
||||||
|
const destination = match[1]
|
||||||
|
.trim()
|
||||||
|
.replace(/^(['"])(.*)\1$/, '$2');
|
||||||
|
|
||||||
|
try {
|
||||||
|
return new URL(destination, sourceUrl).href;
|
||||||
|
} catch {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function redirectsToAnotherPage(href) {
|
||||||
|
const requestedUrl = new URL(href, location.href);
|
||||||
|
const cacheKey = requestedUrl.href;
|
||||||
|
|
||||||
|
if (redirectCache.has(cacheKey)) {
|
||||||
|
return redirectCache.get(cacheKey);
|
||||||
|
}
|
||||||
|
|
||||||
|
const checkPromise = (async () => {
|
||||||
|
try {
|
||||||
|
const response = await fetch(requestedUrl.href, {
|
||||||
|
method: 'GET',
|
||||||
|
redirect: 'follow',
|
||||||
|
credentials: 'same-origin',
|
||||||
|
cache: 'force-cache'
|
||||||
|
});
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Detect ordinary HTTP redirects while ignoring redirects that
|
||||||
|
* only add or remove a trailing slash.
|
||||||
|
*/
|
||||||
|
if (
|
||||||
|
response.redirected &&
|
||||||
|
!urlsReferToSamePage(requestedUrl.href, response.url)
|
||||||
|
) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Some static-site generators implement redirects using an HTML
|
||||||
|
* meta-refresh page rather than an HTTP redirect.
|
||||||
|
*/
|
||||||
|
const contentType =
|
||||||
|
response.headers.get('content-type') || '';
|
||||||
|
|
||||||
|
if (!contentType.includes('text/html')) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const html = await response.text();
|
||||||
|
const documentCopy = new DOMParser().parseFromString(
|
||||||
|
html,
|
||||||
|
'text/html'
|
||||||
|
);
|
||||||
|
|
||||||
|
const destination = getMetaRefreshDestination(
|
||||||
|
documentCopy,
|
||||||
|
requestedUrl.href
|
||||||
|
);
|
||||||
|
|
||||||
|
return (
|
||||||
|
destination !== null &&
|
||||||
|
!urlsReferToSamePage(requestedUrl.href, destination)
|
||||||
|
);
|
||||||
|
} catch (error) {
|
||||||
|
console.warn(
|
||||||
|
`Could not check whether ${requestedUrl.href} redirects:`,
|
||||||
|
error
|
||||||
|
);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Preserve normal navigation when detection fails.
|
||||||
|
*/
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
})();
|
||||||
|
|
||||||
|
redirectCache.set(cacheKey, checkPromise);
|
||||||
|
return checkPromise;
|
||||||
|
}
|
||||||
|
|
||||||
|
document.addEventListener(
|
||||||
|
'click',
|
||||||
|
async (event) => {
|
||||||
|
if (!(event.target instanceof Element)) return;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Preserve middle-clicks and modifier-clicks so users can still
|
||||||
|
* open links in new tabs or windows.
|
||||||
|
*/
|
||||||
|
if (
|
||||||
|
event.button !== 0 ||
|
||||||
|
event.ctrlKey ||
|
||||||
|
event.metaKey ||
|
||||||
|
event.shiftKey ||
|
||||||
|
event.altKey
|
||||||
|
) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const link = event.target.closest(
|
||||||
|
'.hextra-sidebar-container a[href]'
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!link) return;
|
||||||
|
|
||||||
|
const linkUrl = new URL(link.href, location.href);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Do not alter external links.
|
||||||
|
*/
|
||||||
|
if (linkUrl.origin !== location.origin) return;
|
||||||
|
|
||||||
|
const row = link.parentElement;
|
||||||
|
|
||||||
|
const toggleButton = row?.querySelector(
|
||||||
|
'.hextra-sidebar-collapsible-button'
|
||||||
|
);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Links without a collapsible arrow are ordinary page links.
|
||||||
|
*/
|
||||||
|
if (!toggleButton) return;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Explicitly allow known section pages to navigate normally.
|
||||||
|
*/
|
||||||
|
if (
|
||||||
|
forceNavigatePaths.has(
|
||||||
|
normalizePathname(linkUrl.pathname)
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Temporarily prevent navigation while checking whether this is a
|
||||||
|
* redirect-only section link or a real page.
|
||||||
|
*/
|
||||||
|
event.preventDefault();
|
||||||
|
event.stopPropagation();
|
||||||
|
event.stopImmediatePropagation();
|
||||||
|
|
||||||
|
const isRedirect = await redirectsToAnotherPage(linkUrl.href);
|
||||||
|
|
||||||
|
if (isRedirect) {
|
||||||
|
/*
|
||||||
|
* Reuse Hextra's existing collapsible-sidebar behavior.
|
||||||
|
*/
|
||||||
|
toggleButton.click();
|
||||||
|
} else {
|
||||||
|
/*
|
||||||
|
* This section has its own page, so navigate to it normally.
|
||||||
|
*/
|
||||||
|
location.assign(linkUrl.href);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
true
|
||||||
|
);
|
||||||
|
})();
|
||||||
|
</script>
|
||||||
Reference in New Issue
Block a user