Compare commits

...

18 Commits

Author SHA1 Message Date
Michael DiLeo
3b8f90a2b7 add hastag suggestion 2025-08-21 13:11:52 -05:00
Michael DiLeo
7b9b926fcd I was using my personal picsur instead of KV, which is cached with cloudflare! 2025-08-20 16:37:48 -05:00
Michael DiLeo
421cd8a00a add target _blank to rest of hyperlinks 2025-08-20 16:28:39 -05:00
Michael DiLeo
44d8ca6887 add back caching, but for 10 minutes 2025-08-20 16:25:46 -05:00
Michael DiLeo
316675bd64 remove theme toggle 2 script reference 2025-08-20 09:47:24 -05:00
Michael DiLeo
59df2555ce text updates, added code of conduct reference 2025-08-20 09:40:00 -05:00
Michael DiLeo
89c110e0c8 fix contact 2025-08-18 15:44:11 -05:00
Michael DiLeo
48ab0691b5 fleshing out 2025-08-18 15:11:44 -05:00
Michael DiLeo
f9011f5ef4 fix dark/light theme toggle, adjust text, change images to png screenshots 2025-08-17 12:29:26 -05:00
Michael DiLeo
fc0c2f5a1c fix it for real 2025-08-16 09:53:41 -05:00
Michael DiLeo
9447305dea don't set theme on init 2025-08-16 09:46:59 -05:00
Michael DiLeo
18abe47f5c fix toggling of theme 2025-08-16 09:43:25 -05:00
Michael DiLeo
f316a049a6 collapse nav items on smaller screens 2025-08-14 14:41:40 -05:00
Michael DiLeo
77b43080a0 about page gets the stylesheets 2025-08-14 10:47:48 -05:00
Michael DiLeo
29de615702 Merge remote-tracking branch 'refs/remotes/origin/main' into dev
# Conflicts:
#	minify-build.js
2025-08-14 09:54:27 -05:00
Michael DiLeo
b8d1c81620 switch to single bundle file 2025-08-14 09:53:09 -05:00
Michael DiLeo
4e22a6c687 disable caching - should lower cached value later 2025-08-14 09:45:19 -05:00
e1a8d089a9 first-version (#11)
#8 switch to green theme, fix anchor tags not having correct version

Co-authored-by: Michael DiLeo <michael.dileo@oakstreethealth.com>
Reviewed-on: #11
2025-08-14 14:14:01 +00:00
6 changed files with 259 additions and 99 deletions

View File

@@ -51,7 +51,14 @@ async function createOptimizedBuild() {
'video-container', 'video-container',
'photo-gallery', 'photo-gallery',
'photo-item', 'photo-item',
'dark' 'dark',
// Responsive navigation classes
'desktop-nav',
'mobile-nav',
'dropdown',
// Button classes
'secondary',
'outline'
], ],
deep: [ deep: [
/^--pico-/, /^--pico-/,
@@ -60,7 +67,12 @@ async function createOptimizedBuild() {
/:hover/, /:hover/,
/:focus/, /:focus/,
/:active/, /:active/,
/:visited/ /:visited/,
// Dropdown and interactive states
/\[open\]/,
/\[role=/,
/details/,
/summary/
], ],
// Keep base typography selectors that are essential for proper font rendering // Keep base typography selectors that are essential for proper font rendering
greedy: [ greedy: [
@@ -78,7 +90,14 @@ async function createOptimizedBuild() {
/^a$/, /^a$/,
/^a:/, // Add anchor pseudo-classes like a:hover, a:focus /^a:/, // Add anchor pseudo-classes like a:hover, a:focus
/^a\./, // Add anchor with classes like a.secondary /^a\./, // Add anchor with classes like a.secondary
/^a\[/ // Add anchor with attributes like a[role=button] /^a\[/, // Add anchor with attributes like a[role=button]
// Dropdown and button elements
/^details$/,
/^summary$/,
/^button$/,
/^button:/,
/^button\./,
/^button\[/
] ]
}, },
variables: true, variables: true,
@@ -109,20 +128,21 @@ async function createOptimizedBuild() {
}) })
]).process(combinedCSS, { from: undefined }); ]).process(combinedCSS, { from: undefined });
await fs.writeFile('dist/css/styles.css', minifiedCSS.css); // Combine with custom site styles
// Also minify custom site styles
const customCSS = await fs.readFile('public/site-styles/style.css', 'utf8'); const customCSS = await fs.readFile('public/site-styles/style.css', 'utf8');
const minifiedCustomCSS = await postcss([ const combinedWithCustomCSS = minifiedCSS.css + '\n' + customCSS;
// Minify the combined CSS bundle
const finalMinifiedCSS = await postcss([
cssnano({ cssnano({
preset: ['default', { preset: ['default', {
discardComments: { removeAll: true }, discardComments: { removeAll: true },
normalizeWhitespace: true normalizeWhitespace: true
}] }]
}) })
]).process(customCSS, { from: undefined }); ]).process(combinedWithCustomCSS, { from: undefined });
await fs.writeFile('dist/site-styles/style.css', minifiedCustomCSS.css); await fs.writeFile('dist/css/bundle.css', finalMinifiedCSS.css);
// Step 3: JavaScript Bundling and Minification // Step 3: JavaScript Bundling and Minification
console.log('📦 Step 3: Bundling and minifying JavaScript...'); console.log('📦 Step 3: Bundling and minifying JavaScript...');
@@ -148,9 +168,9 @@ async function createOptimizedBuild() {
} }
// Calculate compression results // Calculate compression results
const originalCSSSize = (await fs.stat('public/css/pico.green.min.css')).size + const originalCSSSize = (await fs.stat('public/css/pico.jade.min.css')).size +
(await fs.stat('public/css/pico.colors.min.css')).size; (await fs.stat('public/css/pico.min.css')).size;
const optimizedCSSSize = (await fs.stat('dist/css/styles.css')).size; const optimizedCSSSize = (await fs.stat('dist/css/bundle.css')).size;
const cssReduction = ((originalCSSSize - optimizedCSSSize) / originalCSSSize * 100).toFixed(1); const cssReduction = ((originalCSSSize - optimizedCSSSize) / originalCSSSize * 100).toFixed(1);
const originalHTMLSize = (await fs.stat('public/index.html')).size + const originalHTMLSize = (await fs.stat('public/index.html')).size +
@@ -238,7 +258,7 @@ async function bundleAndMinifyJS() {
hoist_vars: false, hoist_vars: false,
if_return: true, if_return: true,
join_vars: true, join_vars: true,
cascade: true,
side_effects: true side_effects: true
}, },
mangle: { mangle: {
@@ -269,13 +289,12 @@ async function bundleAndMinifyJS() {
async function minifyHTMLFile(inputPath, outputPath) { async function minifyHTMLFile(inputPath, outputPath) {
const html = await fs.readFile(inputPath, 'utf8'); const html = await fs.readFile(inputPath, 'utf8');
// Update CSS references for production and add script reference // Update CSS references for production and update script reference
let updatedHTML = html let updatedHTML = html
.replace(/<link rel="stylesheet" href="css\/pico\.green\.min\.css">/g, '') .replace(/<link rel="stylesheet" href="css\/pico\.jade\.min\.css">/g, '')
.replace(/<link rel="stylesheet" href="css\/pico\.colors\.min\.css">/g, '')
.replace(/<link rel="stylesheet" href="site-styles\/style\.css">/g, .replace(/<link rel="stylesheet" href="site-styles\/style\.css">/g,
'<link rel="stylesheet" href="css/styles.css"><link rel="stylesheet" href="site-styles/style.css">') '<link rel="stylesheet" href="css/bundle.css">')
.replace(/<\/body>/g, '<script src="scripts/bundle.js"></script></body>'); .replace(/<script src="site-scripts\/theme-toggle\.js"><\/script>/g, ''); // Remove individual script references
const minified = await htmlMinify(updatedHTML, { const minified = await htmlMinify(updatedHTML, {
collapseWhitespace: true, collapseWhitespace: true,

View File

@@ -40,14 +40,21 @@ http {
add_header X-XSS-Protection "1; mode=block" always; add_header X-XSS-Protection "1; mode=block" always;
add_header Referrer-Policy "strict-origin-when-cross-origin" always; add_header Referrer-Policy "strict-origin-when-cross-origin" always;
# Temporary: Disable caching during development
location ~* \.(css|js|png|jpg|jpeg|gif|ico|svg|woff|woff2|ttf|eot)$ { location ~* \.(css|js|png|jpg|jpeg|gif|ico|svg|woff|woff2|ttf|eot)$ {
expires 1w; expires 10m;
add_header Cache-Control "public, immutable"; add_header Cache-Control "public, immutable";
# add_header Cache-Control "no-cache, no-store, must-revalidate";
# add_header Pragma "no-cache";
# add_header Expires "0";
} }
location ~* \.html$ { location ~* \.html$ {
expires 1h; expires 10m;
add_header Cache-Control "public"; add_header Cache-Control "public";
# add_header Cache-Control "no-cache, no-store, must-revalidate";
# add_header Pragma "no-cache";
# add_header Expires "0";
} }
location /health { location /health {

View File

@@ -4,22 +4,39 @@
<meta charset="utf-8"> <meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1"> <meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="color-scheme" content="light dark"> <meta name="color-scheme" content="light dark">
<link rel="stylesheet" href="css/pico.green.min.css"> <link rel="stylesheet" href="css/pico.jade.min.css">
<link rel="stylesheet" href="css/pico.colors.min.css">
<link rel="stylesheet" href="site-styles/style.css"> <link rel="stylesheet" href="site-styles/style.css">
<title>Keyboard Vagabond - About</title> <title>Keyboard Vagabond - About</title>
</head> </head>
<body> <body>
<header class="container"> <header class="container">
<nav> <nav>
<ul> <!-- Desktop Navigation -->
<li><a target="_blank"href="https://mastodon.keyboardvagabond.com/public">Mastodon</a></li> <ul class="desktop-nav">
<li><a target="_blank" href="https://mastodon.keyboardvagabond.com/public">Mastodon</a></li>
<li><a target="_blank" href="https://piefed.keyboardvagabond.com">Piefed</a></li> <li><a target="_blank" href="https://piefed.keyboardvagabond.com">Piefed</a></li>
<li><a target="_blank" href="https://pixelfed.keyboardvagabond.com">Pixelfed</a></li> <li><a target="_blank" href="https://pixelfed.keyboardvagabond.com">Pixelfed</a></li>
<li><a target="_blank" href="https://bookwyrm.keyboardvagabond.com">Bookwyrm</a></li> <li><a target="_blank" href="https://bookwyrm.keyboardvagabond.com">Bookwyrm</a></li>
<li><a target="_blank" href="https://blog.keyboardvagabond.com">Write Freely</a></li> <li><a target="_blank" href="https://blog.keyboardvagabond.com">Write Freely</a></li>
<li><a target="_blank" href="https://picsur.keyboardvagabond.com">Picsur</a></li> <li><a target="_blank" href="https://picsur.keyboardvagabond.com">Picsur</a></li>
</ul> </ul>
<!-- Mobile Navigation -->
<ul class="mobile-nav">
<li>
<details class="dropdown">
<summary role="button" class="secondary">Sites</summary>
<ul>
<li><a target="_blank" href="https://mastodon.keyboardvagabond.com/public">Mastodon</a></li>
<li><a target="_blank" href="https://piefed.keyboardvagabond.com">Piefed</a></li>
<li><a target="_blank" href="https://pixelfed.keyboardvagabond.com">Pixelfed</a></li>
<li><a target="_blank" href="https://bookwyrm.keyboardvagabond.com">Bookwyrm</a></li>
<li><a target="_blank" href="https://blog.keyboardvagabond.com">Write Freely</a></li>
<li><a target="_blank" href="https://picsur.keyboardvagabond.com">Picsur</a></li>
</ul>
</details>
</li>
</ul>
<ul> <ul>
<li><a href="index.html">Home</a></li> <li><a href="index.html">Home</a></li>
<li> <li>
@@ -34,10 +51,10 @@
<main class="container"> <main class="container">
<h1>About Keyboard Vagabond</h1> <h1>About Keyboard Vagabond</h1>
<p>Keyboard Vagabond is a place where nomads, travelers, backpacker, whoever, can come together in a digital space that is free of advertising and the attention economy to share information and experiences. It is a place of mutual respect, courtesy, and understanding not just for the members who join, but also for those people and places we encounter on our journeys.</p> <p>Keyboard Vagabond is a place where nomads, travelers, backpackers, whoever, can come together in a digital space that is free of advertising and the attention economy to share information and experiences. It is a place of mutual respect, courtesy, and understanding not just for the members who join, but also for those people and places we encounter on our journeys.</p>
<h4>Why Keyboard Vagabond</h4> <h4>Why Keyboard Vagabond</h4>
<p>Keyboard Vagabond was made because I saw multiple instances of people saying that, while there are travel communities on different instances, there was a space specifically for nomads, so I thought I would make it.</p> <p>Keyboard Vagabond was made because I saw multiple instances of people saying that, while there are travel communities on different instances, there was not a space specifically for nomads, so I thought I would make it.</p>
<h2>What to expect and commitments</h2> <h2>What to expect and commitments</h2>
<p><strong>Moderation style</strong> - <p><strong>Moderation style</strong> -
@@ -48,7 +65,7 @@
Your data is yours and you can download it at any time through the apps. Your data is yours and you can download it at any time through the apps.
The servers are run in a cluster with data redundancy across nodes + nightly and weekly backups to offline storage.</p> The servers are run in a cluster with data redundancy across nodes + nightly and weekly backups to offline storage.</p>
<p><strong>Should shutdown happen</strong> - <p><strong>Should shutdown happen</strong> -
There will be a 3 month announcement in advance, in accordance with the <a href="https://joinmastodon.org/covenant">Mastodon Server Covenant</a>.</p> There will be a 3 month announcement in advance, in accordance with the <a href="https://joinmastodon.org/covenant" target="_blank">Mastodon Server Covenant</a>.</p>
<p><strong>Funding</strong> - <p><strong>Funding</strong> -
Keyboard Mastodon is currently funded by the admin, for a cost of ~$40 - $45 per month. Donations may be opened in the future, but have not been set up at this time.</p> Keyboard Mastodon is currently funded by the admin, for a cost of ~$40 - $45 per month. Donations may be opened in the future, but have not been set up at this time.</p>
<h1>The Dirty Technicals</h1> <h1>The Dirty Technicals</h1>
@@ -56,7 +73,7 @@
<p>I warned you.</p> <p>I warned you.</p>
<p>Keyboard Vagabond is run on a 3 node Kubernetes cluster running on 3x Arm VPSs hosted by NetCup in Amsterdam. I chose Amsterdam because I thought that Europe would be more centrally located for people who are traveling the world.</p> <p>Keyboard Vagabond is run on a 3 node Kubernetes cluster running on 3x Arm VPSs hosted by NetCup in Amsterdam. I chose Amsterdam because I thought that Europe would be more centrally located for people who are traveling the world.</p>
<h4>The Specs</h4> <h4>The Specs</h4>
<p><strong>Servers</strong> - 3x 10 ARM vCPUs, 16GB Ram, 500GB (~50GB for Talos and the rest for Longhorn) storage running <a href="https://www.talos.dev">Talos</a> and Kubernetes. <p><strong>Servers</strong> - 3x 10 ARM vCPUs, 16GB Ram, 500GB (~50GB for Talos and the rest for Longhorn) storage running <a href="https://www.talos.dev" target="_blank">Talos</a> and Kubernetes.
<p><strong>Storage</strong> - Longhorn ensures that there are at least 2 copies across the nodes.</p> <p><strong>Storage</strong> - Longhorn ensures that there are at least 2 copies across the nodes.</p>
<p><strong>Backups and Content</strong> - Backups and content are stored in S3 storage hosted by BackBlaze with CloudFlare providing CDN. I've already run through disaster recovery and restored database backups from S3.</p> <p><strong>Backups and Content</strong> - Backups and content are stored in S3 storage hosted by BackBlaze with CloudFlare providing CDN. I've already run through disaster recovery and restored database backups from S3.</p>
<p><strong>CDN</strong> - CloudFlare provides CDN and special rules have been set up to be sure that as much as possible is cached.</p> <p><strong>CDN</strong> - CloudFlare provides CDN and special rules have been set up to be sure that as much as possible is cached.</p>
@@ -73,8 +90,7 @@
</main> </main>
<footer class="container"> <footer class="container">
<p>Contact: <a href="mailto:admin@keyboardvagabond.com">admin@keyboardvagabond.com</a>, any of the @sysadmin accounts on the instances</p> <p>Contact: <a href="mailto:sysadmin@mailkeyboardvagabond.com">sysadmin@mail.keyboardvagabond.com</a>, any of the @sysadmin accounts on the instances</p>
<p></p>
<p>Copyright 2025 Keyboard Vagabond</p> <p>Copyright 2025 Keyboard Vagabond</p>
</footer> </footer>

View File

@@ -5,8 +5,7 @@
<meta charset="utf-8"> <meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1"> <meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="color-scheme" content="light dark"> <meta name="color-scheme" content="light dark">
<link rel="stylesheet" href="css/pico.green.min.css"> <link rel="stylesheet" href="css/pico.jade.min.css">
<link rel="stylesheet" href="css/pico.colors.min.css">
<link rel="stylesheet" href="site-styles/style.css"> <link rel="stylesheet" href="site-styles/style.css">
<title>Keyboard Vagabond</title> <title>Keyboard Vagabond</title>
</head> </head>
@@ -15,14 +14,33 @@
<!-- Header --> <!-- Header -->
<header class="container"> <header class="container">
<nav> <nav>
<ul> <!-- Desktop Navigation -->
<li><a target="_blank"href="https://mastodon.keyboardvagabond.com/public">Mastodon</a></li> <ul class="desktop-nav">
<li><a target="_blank" href="https://mastodon.keyboardvagabond.com/public">Mastodon</a></li>
<li><a target="_blank" href="https://piefed.keyboardvagabond.com">Piefed</a></li> <li><a target="_blank" href="https://piefed.keyboardvagabond.com">Piefed</a></li>
<li><a target="_blank" href="https://pixelfed.keyboardvagabond.com">Pixelfed</a></li> <li><a target="_blank" href="https://pixelfed.keyboardvagabond.com">Pixelfed</a></li>
<li><a target="_blank" href="https://bookwyrm.keyboardvagabond.com">Bookwyrm</a></li> <li><a target="_blank" href="https://bookwyrm.keyboardvagabond.com">Bookwyrm</a></li>
<li><a target="_blank" href="https://blog.keyboardvagabond.com">Write Freely</a></li> <li><a target="_blank" href="https://blog.keyboardvagabond.com">Write Freely</a></li>
<li><a target="_blank" href="https://picsur.keyboardvagabond.com">Picsur</a></li> <li><a target="_blank" href="https://picsur.keyboardvagabond.com">Picsur</a></li>
</ul> </ul>
<!-- Mobile Navigation -->
<ul class="mobile-nav">
<li>
<details class="dropdown">
<summary role="button" class="secondary">Sites</summary>
<ul>
<li><a target="_blank" href="https://mastodon.keyboardvagabond.com/public">Mastodon</a></li>
<li><a target="_blank" href="https://piefed.keyboardvagabond.com">Piefed</a></li>
<li><a target="_blank" href="https://pixelfed.keyboardvagabond.com">Pixelfed</a></li>
<li><a target="_blank" href="https://bookwyrm.keyboardvagabond.com">Bookwyrm</a></li>
<li><a target="_blank" href="https://blog.keyboardvagabond.com">Write Freely</a></li>
<li><a target="_blank" href="https://picsur.keyboardvagabond.com">Picsur</a></li>
</ul>
</details>
</li>
</ul>
<ul> <ul>
<li><a href="about.html">About</a></li> <li><a href="about.html">About</a></li>
<li> <li>
@@ -35,7 +53,7 @@
</header> </header>
<div class="banner-container"> <div class="banner-container">
<img src="https://picsur.michaeldileo.org/i/36516edf-1a67-4565-aa8e-c10dbe743fd6.jpg?width=2048" alt="Scenic mountain road with snow-capped peaks" class="banner"> <img src="https://picsur.keyboardvagabond.com/i/076a5b88-20d3-426e-ad7f-f24a68d3fa70.jpg?width=2048" alt="Scenic mountain road with snow-capped peaks" class="banner">
<h1 class="banner-title">Welcome to Keyboard Vagabond</h1> <h1 class="banner-title">Welcome to Keyboard Vagabond</h1>
<p class="banner-subtitle">A space in the fediverse for travelers, nomads, and vagabonds of all kinds</p> <p class="banner-subtitle">A space in the fediverse for travelers, nomads, and vagabonds of all kinds</p>
</div> </div>
@@ -75,6 +93,23 @@
hosting, to use for images in your blogs. You can also use Pixelfed. Contact the admin for Picsur hosting, to use for images in your blogs. You can also use Pixelfed. Contact the admin for Picsur
signup, as there's no automated signup process.</li> signup, as there's no automated signup process.</li>
</ul> </ul>
<strong>Mobile Apps</strong>
<p>
<ul>
<li>
<strong>Piefed</strong> - Piefed has support in <a href="https://www.lemmyapps.com/Interstellar" target="_blank">Interstellar (cross platform)</a> and experimental support in
<a href="https://vger.app/settings/install">Voyager (Android)</a>, though features like topics and communities are best served on the website.
</li>
<li>
<strong><a href="https://pixelfed.org/mobile-apps" target="_blank">Pixelfed</a></strong>, <strong><a href="https://joinmastodon.org/apps" target="_blank">Mastodon</a></strong> - have native mobile apps
</li>
<li>
<strong>Lemmy</strong> - many of your favorite reddit apps can be used with Lemmy
</li>
</ul>
<span>The rest of the applications are accessible on the websites and can be added to your homescreen.</span><br/>
<span><strong>Signing in</strong> - you'll search the server that you want to join, such as mastodon.social or mastodon.keyboardvagabond.com, or use the provided default instances.</span>
</p>
<h1>What is the Fediverse</h1> <h1>What is the Fediverse</h1>
<p>The fediverse is a collection of big-tech alternative social media that all communicate with each other using <p>The fediverse is a collection of big-tech alternative social media that all communicate with each other using
the same protocol, called ActivityPub. This means that not only can different “instances,” such as this the same protocol, called ActivityPub. This means that not only can different “instances,” such as this
@@ -85,57 +120,71 @@
make a video on PeerTube (Youtube alternative) and discuss on Mastodon. Your Write Freely blog posts will, make a video on PeerTube (Youtube alternative) and discuss on Mastodon. Your Write Freely blog posts will,
if you enable it, be visible on Mastodon and people can follow your blog account.</p> if you enable it, be visible on Mastodon and people can follow your blog account.</p>
<p>Check out this amazing four minute video by <a href="https://news.elenarossini.com">Elena Rossini</a>. You can follow her <p>Check out this amazing four minute video by <a href="https://news.elenarossini.com">Elena Rossini</a>. You can follow her
on Mastodon by searching @elena@aseachange.com.</p> on Mastodon by searching @_elena@mastodon.social.</p>
<div class="video-container"> <div class="video-container">
<iframe title="Introducing the Fediverse: a New Era of Social Media" <iframe title="Introducing the Fediverse: a New Era of Social Media"
src="https://videos.elenarossini.com/videos/embed/64VuNCccZNrP4u9MfgbhkN" frameborder="0" allowfullscreen="" src="https://videos.elenarossini.com/videos/embed/64VuNCccZNrP4u9MfgbhkN" frameborder="0" allowfullscreen=""
sandbox="allow-same-origin allow-scripts allow-popups allow-forms" sandbox="allow-same-origin allow-scripts allow-popups allow-forms"
loading="lazy"></iframe> loading="lazy"></iframe>
</div> </div>
<h2>How to get started in the Fediverse</h2> <h2>Getting started in the Fediverse</h2>
<p>The best way to see what's available in the fediverse is to start off on a larger instance, which will be <p>The best way to see what's available in the fediverse is to start off on a larger instance, which will be
following the most content. From there you can follow communities and members on Keyboard Vagabond, or following the most content. From there you can follow communities and members on Keyboard Vagabond, or
export your profiles, follows, etc over to Keyboard Vagabond. You can, of course, have multiple profiles export your profiles, follows, etc over to Keyboard Vagabond. You can, of course, have multiple profiles
across instances.</p> across instances.</p>
<p>Once you choose and place and sign up, wait for your admin approval. Many instances require manual account <p>Once you choose and place and sign up, wait for your admin approval. Many instances require manual account
approval to prevent spam.</p> approval to prevent spam.</p>
<p><strong>Popular places to get started are</strong>:</p> <strong>Popular places to get started are</strong>:<br/>
<strong><a href="https://lemmy.zip">Lemmy.zip</a></strong> for Lemmy or <strong><a <ul>
href="https://piefed.social">Piefed.social</a></strong> for PieFed, which is the software that this <li>
<strong><a href="https://lemmy.zip" target="_blank">Lemmy.zip</a></strong> for Lemmy or <strong><a
href="https://piefed.social" target="_blank">Piefed.social</a></strong> for PieFed, which is the software that this
community runs. community runs.
</li>
<li><strong><a href="https://mastodon.social" target="_blank">Mastodon.social</a></strong> - the largest mastodon instance.
Search for hashtags or check out whats trending and follow them to create your timeline.
</li>
<li><strong><a href="https://pixelfed.social" target="_blank">Pixelfed.social</a></strong> - the largest Pixelfed instance. Also
search for timelines and hashtags of things that you're interested in or what may be trending.
</li>
</ul>
<strong>Codes of Conduct</strong><br />
<span>
While corporate media is primarily interested in the Terms of Service, the Fediverse cares about the
Code of Conduct, the agreement of how we treat each other and what behavior is and is not tolerated.
Each instance should have one, including those of Keyboard Vagabond. These agreements help us to
create welcoming spaces that are free of harassment and bigotry.
</span>
</p> </p>
<p><strong><a href="https://mastodon.social">Mastodon.social</a></strong> - the largest mastodon instance.
Search for hashtags or check out whats trending and follow them to create your timeline.</p>
<p><strong><a href="https://pixelfed.social">Pixelfed.social</a></strong> - the largest Pixelfed instance. Also
search for timelines and hashtags of things that you're interested in or what may be trending.</p>
<h2>Creating your experience</h2> <h2>Creating your experience</h2>
<p> <p>
In the fediverse, there are no algorithms. No one is trying to harvest your data or monetize your attention. In the fediverse, there are no algorithms. No one is trying to harvest your data or monetize your attention.
No one is trying to push anything in front of you. Try searching for hashtags like <a No one is trying to push anything in front of you. Try searching for hashtags like <a
href="https://mastodon.keyboardvagabond.com/tags/travel">#travel</a> or <a href="https://mastodon.keyboardvagabond.com/tags/travel" target="_blank">#travel</a>, <a
href="https://mastodon.keyboardvagabond.com/tags/travelphotography">#travelphotography</a>.</p> href="https://mastodon.keyboardvagabond.com/tags/travelphotography" target="_blank">#travelphotography</a>, or <a
href="https://mastodon.keyboardvagabond.com/tags/EscapeFlights" target="_blank">#EscapeFlights</a>.</p>
<div class="photo-gallery"> <div class="photo-gallery">
<div class="photo-item"> <div class="photo-item">
<small>Check out that Explore button on the main page.</small> <small>Check out that Explore button on the main page.</small>
<img src="https://picsur.keyboardvagabond.com/i/48624639-e731-4e50-a166-f88cf9eccded.jpg?width=400" <img src="https://picsur.keyboardvagabond.com/i/e8ab899f-5bb4-4cf1-b531-8621ac93670e.png?width=400"
alt="Explore button on main page" loading="lazy" /> alt="Explore button on main page" loading="lazy" />
</div> </div>
<div class="photo-item"> <div class="photo-item">
<small>Visit the Posts, Hashtags, and News tabs to see what's on the server</small> <small>Visit the Posts, Hashtags, and News tabs to see what's on the server</small>
<img src="https://picsur.keyboardvagabond.com/i/d05996c7-5c23-450e-9ca0-b7e532d1c700.jpg?width=700" <img src="https://picsur.keyboardvagabond.com/i/aea3c3c5-b011-4680-be4c-96fc1fdb009a.png?width=700"
alt="Posts, Hashtags, and News tabs" loading="lazy" /> alt="Posts, Hashtags, and News tabs" loading="lazy" />
</div> </div>
<div class="photo-item"> <div class="photo-item">
<small>Look at the local communities to see what communities have been created on this server specifically. The rest of the communities are ones that this server is following. <small>Look at the local communities to see what communities have been created on this server specifically. The rest of the communities are ones that this server is following.
Following communities on other instances will result in them being shown here. Following communities on other instances will result in them being shown here.
</small> </small>
<img src="https://picsur.michaeldileo.org/i/e07dddbc-d264-4f12-8877-17eed896026a.jpg?width=700" <img src="https://picsur.keyboardvagabond.com/i/b5d316d9-8958-47bf-ba74-fb853e2d2be8.png?width=700"
alt="Communities, Local Communities" loading="lazy" /> alt="Communities, Local Communities" loading="lazy" />
</div> </div>
<div class="photo-item"> <div class="photo-item">
<small>Scroll all the way to the bottom to find local topics. Topics are groups of communities. You can suggest more in the Meta community.</small> <small>Scroll all the way to the bottom to find local topics. Topics are groups of communities. You can suggest more in the Meta community.</small>
<img src="https://picsur.michaeldileo.org/i/5a977aa0-b9bb-4376-a348-f879c7162f63.jpg?width=700" <img src="https://picsur.keyboardvagabond.com/i/e5909364-3c4f-4bca-8631-5b1225781177.png?width=700"
alt="Local topics" loading="lazy" /> alt="Local topics" loading="lazy" />
</div> </div>
</div> </div>

View File

@@ -1,32 +1,25 @@
(function() { (function() {
const themeToggle = document.getElementById('theme-toggle'); const themeToggle = document.getElementById('theme-toggle');
const themeIcon = document.getElementById('theme-icon'); const themeIcon = document.getElementById('theme-icon');
function getStoredTheme() {
return localStorage.getItem('picoPreferredColorScheme') || 'auto';
}
function storeTheme(theme) { function storeTheme(theme) {
localStorage.setItem('picoPreferredColorScheme', theme); localStorage.setItem('picoPreferredColorScheme', theme);
} }
function getSystemTheme() { function getStoredTheme() {
return window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light'; return localStorage.getItem('picoPreferredColorScheme');
} }
function applyTheme() { function getCurrentTheme() {
const storedTheme = getStoredTheme(); return document.documentElement.getAttribute('data-theme') ||
let actualTheme; (window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light');
}
if (storedTheme === 'auto') {
actualTheme = getSystemTheme(); function applyTheme(currentTheme) {
} else { const newTheme = currentTheme === 'dark' ? 'light' : 'dark';
actualTheme = storedTheme; document.documentElement.setAttribute('data-theme', newTheme);
} if (newTheme === 'dark') {
document.documentElement.setAttribute('data-theme', actualTheme);
if (actualTheme === 'dark') {
themeIcon.textContent = '☀️'; themeIcon.textContent = '☀️';
themeToggle.setAttribute('aria-pressed', 'true'); themeToggle.setAttribute('aria-pressed', 'true');
} else { } else {
@@ -34,35 +27,28 @@
themeToggle.setAttribute('aria-pressed', 'false'); themeToggle.setAttribute('aria-pressed', 'false');
} }
} }
function toggleTheme() { themeToggle.addEventListener('click', () => {
const currentStored = getStoredTheme(); const currentTheme = getCurrentTheme();
let nextTheme;
if (currentStored === 'auto') { applyTheme(currentTheme);
nextTheme = 'light'; storeTheme(currentTheme);
} else if (currentStored === 'light') { });
nextTheme = 'dark';
} else {
nextTheme = 'auto';
}
storeTheme(nextTheme);
applyTheme();
}
function init() { function init() {
if (themeToggle) { let storedTheme = getStoredTheme() || getCurrentTheme();
applyTheme();
applyTheme(storedTheme);
themeToggle.addEventListener('click', toggleTheme);
themeToggle.addEventListener('click', toggleTheme);
window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', () => {
if (getStoredTheme() === 'auto') { window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', () => {
applyTheme(); // Only apply theme if user hasn't made an explicit choice
} const storedTheme = getStoredTheme();
}); if (storedTheme === 'auto') {
} applyTheme();
}
})
} }
if (document.readyState !== 'loading') { if (document.readyState !== 'loading') {

View File

@@ -244,4 +244,87 @@
#theme-toggle #theme-icon { #theme-toggle #theme-icon {
display: block; display: block;
line-height: 1; line-height: 1;
}
/* Responsive Navigation Styles */
/* Hide mobile nav by default (desktop first) */
.mobile-nav {
display: none;
}
/* Show desktop nav by default */
.desktop-nav {
display: flex;
}
/* Mobile breakpoint - hide desktop nav and show mobile nav */
@media (max-width: 768px) {
.desktop-nav {
display: none;
}
.mobile-nav {
display: flex;
}
/* Style the dropdown for mobile */
.mobile-nav .dropdown {
width: 100%;
}
.mobile-nav .dropdown summary {
margin: 0;
padding: calc(var(--pico-spacing) * 0.5) var(--pico-spacing);
border-radius: var(--pico-border-radius);
cursor: pointer;
user-select: none;
}
.mobile-nav .dropdown[open] summary {
border-bottom-left-radius: 0;
border-bottom-right-radius: 0;
}
.mobile-nav .dropdown ul {
position: absolute;
top: 100%;
left: 0;
right: 0;
background: var(--pico-background-color);
border: 1px solid var(--pico-muted-border-color);
border-top: none;
border-radius: 0 0 var(--pico-border-radius) var(--pico-border-radius);
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
z-index: 1000;
margin: 0;
padding: 0;
list-style: none;
}
.mobile-nav .dropdown ul li {
margin: 0;
border-bottom: 1px solid var(--pico-muted-border-color);
}
.mobile-nav .dropdown ul li:last-child {
border-bottom: none;
}
.mobile-nav .dropdown ul li a {
display: block;
padding: calc(var(--pico-spacing) * 0.75) var(--pico-spacing);
text-decoration: none;
color: var(--pico-color);
transition: background-color 0.2s ease;
}
.mobile-nav .dropdown ul li a:hover {
background-color: var(--pico-muted-color);
opacity: 0.1;
}
/* Ensure proper positioning context */
.mobile-nav li {
position: relative;
}
} }