Bincio design system: auth wall, login page, Grand Tours palette, PageEditor, _docs reorg
This commit is contained in:
+48
-1
@@ -4,6 +4,8 @@ import tailwind from '@astrojs/tailwind';
|
||||
import svelte from '@astrojs/svelte';
|
||||
import { remarkWikiRefs } from 'remark-wikirefs';
|
||||
import { remarkCaml } from 'remark-caml';
|
||||
import { unlinkSync } from 'fs';
|
||||
import { fileURLToPath } from 'url';
|
||||
import {
|
||||
resolveHtmlHref,
|
||||
resolveHtmlText,
|
||||
@@ -27,8 +29,53 @@ const remarkPlugins = [
|
||||
const resolveEmbedContent = createResolveEmbedContent(remarkPlugins);
|
||||
remarkPlugins[1][1].resolveEmbedContent = resolveEmbedContent;
|
||||
|
||||
// Astro's glob loader doesn't trigger a full re-scan on unlink events, and
|
||||
// its persisted data-store.json survives server.restart() — so deleted entries
|
||||
// linger. Fix: on unlink, clear data-store.json then restart so Astro does a
|
||||
// full re-scan from scratch instead of loading the stale persisted store.
|
||||
// Vite reuses the same FSWatcher instance across restarts, so we keep a
|
||||
// module-level handler reference and remove it before re-adding to avoid
|
||||
// listener accumulation.
|
||||
let _unlinkHandler = null;
|
||||
function contentDeleteWatcher() {
|
||||
return {
|
||||
name: 'content-delete-watcher',
|
||||
hooks: {
|
||||
'astro:server:setup': ({ server }) => {
|
||||
const siteRoot = new URL('.', import.meta.url).pathname;
|
||||
const dataStore = fileURLToPath(new URL('.astro/data-store.json', import.meta.url));
|
||||
const watched = [
|
||||
siteRoot + 'src/content/entries/',
|
||||
siteRoot + 'src/content/blog/',
|
||||
];
|
||||
if (_unlinkHandler) server.watcher.off('unlink', _unlinkHandler);
|
||||
let restarting = false;
|
||||
_unlinkHandler = (filePath) => {
|
||||
if (restarting || !filePath.endsWith('.md')) return;
|
||||
if (watched.some(dir => filePath.startsWith(dir))) {
|
||||
restarting = true;
|
||||
try { unlinkSync(dataStore); } catch {}
|
||||
server.restart();
|
||||
}
|
||||
};
|
||||
server.watcher.on('unlink', _unlinkHandler);
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
export default defineConfig({
|
||||
site: 'https://wiki.bincio.com',
|
||||
integrations: [sitemap(), tailwind(), svelte()],
|
||||
integrations: [sitemap(), tailwind(), svelte(), contentDeleteWatcher()],
|
||||
markdown: { remarkPlugins },
|
||||
vite: {
|
||||
server: {
|
||||
proxy: {
|
||||
'/api': 'http://localhost:8001',
|
||||
'/pages': 'http://localhost:8001',
|
||||
'/stories': 'http://localhost:8001',
|
||||
'/rebuild': 'http://localhost:8001',
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
@@ -0,0 +1,172 @@
|
||||
<script lang="ts">
|
||||
let open = false;
|
||||
let isNew = false;
|
||||
let slug = '';
|
||||
let content = '';
|
||||
let apiBase = '/pages';
|
||||
let saving = false;
|
||||
let deleting = false;
|
||||
let saveStatus = '';
|
||||
let savedUrl = '';
|
||||
let errorMsg = '';
|
||||
|
||||
function reset(detail: { slug?: string; apiBase?: string }) {
|
||||
apiBase = detail.apiBase ?? '/pages';
|
||||
slug = detail.slug ?? '';
|
||||
content = '';
|
||||
isNew = !slug;
|
||||
saving = false;
|
||||
deleting = false;
|
||||
saveStatus = '';
|
||||
savedUrl = '';
|
||||
errorMsg = '';
|
||||
}
|
||||
|
||||
async function loadContent() {
|
||||
if (!slug) return;
|
||||
try {
|
||||
const r = await fetch(`${apiBase}/${slug}`, { credentials: 'include' });
|
||||
if (r.status === 404) { errorMsg = 'File non trovato — potrebbe essere già stato eliminato'; return; }
|
||||
if (!r.ok) throw new Error(`HTTP ${r.status}`);
|
||||
const data = await r.json();
|
||||
content = data.content;
|
||||
} catch (e) {
|
||||
errorMsg = `Errore nel caricamento: ${e}`;
|
||||
}
|
||||
}
|
||||
|
||||
async function save() {
|
||||
const s = slug.trim().toLowerCase().replace(/\s+/g, '-');
|
||||
if (!s) { errorMsg = 'Nome richiesto'; return; }
|
||||
slug = s;
|
||||
saving = true;
|
||||
errorMsg = '';
|
||||
try {
|
||||
const r = await fetch(`${apiBase}/${s}`, {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
credentials: 'include',
|
||||
body: JSON.stringify({ content }),
|
||||
});
|
||||
if (!r.ok) throw new Error(await r.text());
|
||||
saveStatus = 'Salvato';
|
||||
if (isNew) {
|
||||
savedUrl = apiBase === '/stories' ? `/blog/${s}/` : `/entries/${s}/`;
|
||||
} else {
|
||||
setTimeout(() => window.location.reload(), 400);
|
||||
}
|
||||
} catch (e) {
|
||||
errorMsg = `Errore: ${e}`;
|
||||
} finally {
|
||||
saving = false;
|
||||
}
|
||||
}
|
||||
|
||||
async function deletePage() {
|
||||
if (!confirm('Eliminare questa pagina?')) return;
|
||||
deleting = true;
|
||||
errorMsg = '';
|
||||
try {
|
||||
const r = await fetch(`${apiBase}/${slug}`, { method: 'DELETE', credentials: 'include' });
|
||||
if (!r.ok) throw new Error(await r.text());
|
||||
window.location.href = apiBase === '/stories' ? '/blog/' : '/entries/';
|
||||
} catch (e) {
|
||||
errorMsg = `Errore: ${e}`;
|
||||
deleting = false;
|
||||
}
|
||||
}
|
||||
|
||||
function handleKeydown(e: KeyboardEvent) {
|
||||
if (e.key === 'Escape') open = false;
|
||||
if ((e.metaKey || e.ctrlKey) && e.key === 's') { e.preventDefault(); save(); }
|
||||
}
|
||||
|
||||
if (typeof window !== 'undefined') {
|
||||
window.addEventListener('open-editor', (e: Event) => {
|
||||
const detail = (e as CustomEvent).detail ?? {};
|
||||
reset(detail);
|
||||
open = true;
|
||||
if (!isNew) loadContent();
|
||||
});
|
||||
}
|
||||
|
||||
function newContentTemplate() {
|
||||
if (apiBase === '/stories') {
|
||||
const today = new Date().toISOString().split('T')[0];
|
||||
return `---\ntitle: Senza titolo\ndescription: ...\npubDate: ${today}\n---\n\n`;
|
||||
}
|
||||
return `---\ntitle: Senza titolo\n---\n\n`;
|
||||
}
|
||||
|
||||
$: if (open && isNew && !content) content = newContentTemplate();
|
||||
</script>
|
||||
|
||||
{#if open}
|
||||
<!-- svelte-ignore a11y-no-noninteractive-element-interactions -->
|
||||
<div
|
||||
role="dialog"
|
||||
class="fixed inset-0 z-50 flex flex-col"
|
||||
style="background: var(--bg-base)"
|
||||
on:keydown={handleKeydown}
|
||||
tabindex="-1"
|
||||
>
|
||||
<!-- Header bar -->
|
||||
<div class="flex items-center gap-3 px-4 h-12 border-b shrink-0" style="border-color: var(--border)">
|
||||
{#if isNew}
|
||||
<input
|
||||
type="text"
|
||||
bind:value={slug}
|
||||
placeholder="nome-pagina"
|
||||
class="bg-transparent text-sm font-mono outline-none flex-1 min-w-0"
|
||||
style="color: var(--text-2)"
|
||||
autofocus
|
||||
/>
|
||||
{:else}
|
||||
<span class="text-sm font-mono truncate flex-1 min-w-0" style="color: var(--text-4)">{slug}</span>
|
||||
{/if}
|
||||
|
||||
<div class="ml-auto shrink-0 flex items-center gap-2">
|
||||
{#if saveStatus}
|
||||
<span class="text-xs" style="color: var(--accent)">{saveStatus}</span>
|
||||
{/if}
|
||||
{#if savedUrl}
|
||||
<a
|
||||
href={savedUrl}
|
||||
class="text-xs px-2 py-1 rounded border transition-colors"
|
||||
style="color: var(--accent); border-color: var(--accent)"
|
||||
>Visualizza →</a>
|
||||
{/if}
|
||||
{#if !isNew}
|
||||
<button
|
||||
on:click={deletePage}
|
||||
disabled={deleting}
|
||||
class="text-xs text-zinc-500 hover:text-red-400 transition-colors px-2 py-1 rounded border border-zinc-700 hover:border-red-800 disabled:opacity-50"
|
||||
>{deleting ? '…' : 'Elimina'}</button>
|
||||
{/if}
|
||||
<button
|
||||
on:click={save}
|
||||
disabled={saving}
|
||||
class="text-xs px-3 py-1 rounded border transition-colors disabled:opacity-50"
|
||||
style="color: var(--accent); border-color: var(--accent)"
|
||||
>{saving ? '…' : 'Salva'}</button>
|
||||
<button
|
||||
on:click={() => open = false}
|
||||
class="text-zinc-500 hover:text-white transition-colors w-8 h-8 flex items-center justify-center text-lg"
|
||||
title="Chiudi (Esc)"
|
||||
>✕</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{#if errorMsg}
|
||||
<div class="px-4 py-2 text-xs shrink-0" style="color: #f87171">{errorMsg}</div>
|
||||
{/if}
|
||||
|
||||
<textarea
|
||||
bind:value={content}
|
||||
class="flex-1 w-full p-4 bg-transparent font-mono text-sm resize-none outline-none"
|
||||
style="color: var(--text-2)"
|
||||
placeholder="Scrivi in markdown…"
|
||||
spellcheck="false"
|
||||
></textarea>
|
||||
</div>
|
||||
{/if}
|
||||
@@ -16,7 +16,7 @@ const entries = defineCollection({
|
||||
loader: glob({
|
||||
pattern: '**/*.md',
|
||||
base: './src/content/entries',
|
||||
generateId: ({ entry }) => entry.replace(/^_wiki\//, '').replace(/\.mdx?$/, ''),
|
||||
generateId: ({ entry }) => entry.replace(/\.mdx?$/, ''),
|
||||
}),
|
||||
schema: z.object({
|
||||
title: z.string(),
|
||||
|
||||
@@ -1,21 +0,0 @@
|
||||
---
|
||||
title: 'First post'
|
||||
description: 'Lorem ipsum dolor sit amet'
|
||||
pubDate: 'Jul 08 2022'
|
||||
heroImage: '/blog-placeholder-3.jpg'
|
||||
---
|
||||
|
||||
:attrtype::string
|
||||
:attr::[[wikirefs]]
|
||||
|
||||
👉 [[wikirefs]]
|
||||
|
||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Vitae ultricies leo integer malesuada nunc vel risus commodo viverra. Adipiscing enim eu turpis egestas pretium. Euismod elementum nisi quis eleifend quam adipiscing. In hac habitasse platea dictumst vestibulum. Sagittis purus sit amet volutpat. Netus et malesuada fames ac turpis egestas. Eget magna fermentum iaculis eu non diam phasellus vestibulum lorem. Varius sit amet mattis vulputate enim. Habitasse platea dictumst quisque sagittis. Integer quis auctor elit sed vulputate mi. Dictumst quisque sagittis purus sit amet.
|
||||
|
||||
Morbi tristique senectus et netus. Id semper risus in hendrerit gravida rutrum quisque non tellus. Habitasse platea dictumst quisque sagittis purus sit amet. Tellus molestie nunc non blandit massa. Cursus vitae congue mauris rhoncus. Accumsan tortor posuere ac ut. Fringilla urna porttitor rhoncus dolor. Elit ullamcorper dignissim cras tincidunt lobortis. In cursus turpis massa tincidunt dui ut ornare lectus. Integer feugiat scelerisque varius morbi enim nunc. Bibendum neque egestas congue quisque egestas diam. Cras ornare arcu dui vivamus arcu felis bibendum. Dignissim suspendisse in est ante in nibh mauris. Sed tempus urna et pharetra pharetra massa massa ultricies mi.
|
||||
|
||||
Mollis nunc sed id semper risus in. Convallis a cras semper auctor neque. Diam sit amet nisl suscipit. Lacus viverra vitae congue eu consequat ac felis donec. Egestas integer eget aliquet nibh praesent tristique magna sit amet. Eget magna fermentum iaculis eu non diam. In vitae turpis massa sed elementum. Tristique et egestas quis ipsum suspendisse ultrices. Eget lorem dolor sed viverra ipsum. Vel turpis nunc eget lorem dolor sed viverra. Posuere ac ut consequat semper viverra nam. Laoreet suspendisse interdum consectetur libero id faucibus. Diam phasellus vestibulum lorem sed risus ultricies tristique. Rhoncus dolor purus non enim praesent elementum facilisis. Ultrices tincidunt arcu non sodales neque. Tempus egestas sed sed risus pretium quam vulputate. Viverra suspendisse potenti nullam ac tortor vitae purus faucibus ornare. Fringilla urna porttitor rhoncus dolor purus non. Amet dictum sit amet justo donec enim.
|
||||
|
||||
Mattis ullamcorper velit sed ullamcorper morbi tincidunt. Tortor posuere ac ut consequat semper viverra. Tellus mauris a diam maecenas sed enim ut sem viverra. Venenatis urna cursus eget nunc scelerisque viverra mauris in. Arcu ac tortor dignissim convallis aenean et tortor at. Curabitur gravida arcu ac tortor dignissim convallis aenean et tortor. Egestas tellus rutrum tellus pellentesque eu. Fusce ut placerat orci nulla pellentesque dignissim enim sit amet. Ut enim blandit volutpat maecenas volutpat blandit aliquam etiam. Id donec ultrices tincidunt arcu. Id cursus metus aliquam eleifend mi.
|
||||
|
||||
Tempus quam pellentesque nec nam aliquam sem. Risus at ultrices mi tempus imperdiet. Id porta nibh venenatis cras sed felis eget velit. Ipsum a arcu cursus vitae. Facilisis magna etiam tempor orci eu lobortis elementum. Tincidunt dui ut ornare lectus sit. Quisque non tellus orci ac. Blandit libero volutpat sed cras. Nec tincidunt praesent semper feugiat nibh sed pulvinar proin gravida. Egestas integer eget aliquet nibh praesent tristique magna.
|
||||
@@ -2,7 +2,7 @@
|
||||
title: 'Markdown Style Guide'
|
||||
description: 'Here is a sample of some basic Markdown syntax that can be used when writing Markdown content in Astro.'
|
||||
pubDate: 'Jul 01 2022'
|
||||
heroImage: '/blog-placeholder-1.jpg'
|
||||
heroImage: '/blog-placeholder-3.jpg'
|
||||
---
|
||||
|
||||
Here is a sample of some basic Markdown syntax that can be used when writing Markdown content in Astro.
|
||||
|
||||
@@ -1,16 +0,0 @@
|
||||
---
|
||||
title: 'Second post'
|
||||
description: 'Lorem ipsum dolor sit amet'
|
||||
pubDate: 'Jul 22 2022'
|
||||
heroImage: '/blog-placeholder-4.jpg'
|
||||
---
|
||||
|
||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Vitae ultricies leo integer malesuada nunc vel risus commodo viverra. Adipiscing enim eu turpis egestas pretium. Euismod elementum nisi quis eleifend quam adipiscing. In hac habitasse platea dictumst vestibulum. Sagittis purus sit amet volutpat. Netus et malesuada fames ac turpis egestas. Eget magna fermentum iaculis eu non diam phasellus vestibulum lorem. Varius sit amet mattis vulputate enim. Habitasse platea dictumst quisque sagittis. Integer quis auctor elit sed vulputate mi. Dictumst quisque sagittis purus sit amet.
|
||||
|
||||
Morbi tristique senectus et netus. Id semper risus in hendrerit gravida rutrum quisque non tellus. Habitasse platea dictumst quisque sagittis purus sit amet. Tellus molestie nunc non blandit massa. Cursus vitae congue mauris rhoncus. Accumsan tortor posuere ac ut. Fringilla urna porttitor rhoncus dolor. Elit ullamcorper dignissim cras tincidunt lobortis. In cursus turpis massa tincidunt dui ut ornare lectus. Integer feugiat scelerisque varius morbi enim nunc. Bibendum neque egestas congue quisque egestas diam. Cras ornare arcu dui vivamus arcu felis bibendum. Dignissim suspendisse in est ante in nibh mauris. Sed tempus urna et pharetra pharetra massa massa ultricies mi.
|
||||
|
||||
Mollis nunc sed id semper risus in. Convallis a cras semper auctor neque. Diam sit amet nisl suscipit. Lacus viverra vitae congue eu consequat ac felis donec. Egestas integer eget aliquet nibh praesent tristique magna sit amet. Eget magna fermentum iaculis eu non diam. In vitae turpis massa sed elementum. Tristique et egestas quis ipsum suspendisse ultrices. Eget lorem dolor sed viverra ipsum. Vel turpis nunc eget lorem dolor sed viverra. Posuere ac ut consequat semper viverra nam. Laoreet suspendisse interdum consectetur libero id faucibus. Diam phasellus vestibulum lorem sed risus ultricies tristique. Rhoncus dolor purus non enim praesent elementum facilisis. Ultrices tincidunt arcu non sodales neque. Tempus egestas sed sed risus pretium quam vulputate. Viverra suspendisse potenti nullam ac tortor vitae purus faucibus ornare. Fringilla urna porttitor rhoncus dolor purus non. Amet dictum sit amet justo donec enim.
|
||||
|
||||
Mattis ullamcorper velit sed ullamcorper morbi tincidunt. Tortor posuere ac ut consequat semper viverra. Tellus mauris a diam maecenas sed enim ut sem viverra. Venenatis urna cursus eget nunc scelerisque viverra mauris in. Arcu ac tortor dignissim convallis aenean et tortor at. Curabitur gravida arcu ac tortor dignissim convallis aenean et tortor. Egestas tellus rutrum tellus pellentesque eu. Fusce ut placerat orci nulla pellentesque dignissim enim sit amet. Ut enim blandit volutpat maecenas volutpat blandit aliquam etiam. Id donec ultrices tincidunt arcu. Id cursus metus aliquam eleifend mi.
|
||||
|
||||
Tempus quam pellentesque nec nam aliquam sem. Risus at ultrices mi tempus imperdiet. Id porta nibh venenatis cras sed felis eget velit. Ipsum a arcu cursus vitae. Facilisis magna etiam tempor orci eu lobortis elementum. Tincidunt dui ut ornare lectus sit. Quisque non tellus orci ac. Blandit libero volutpat sed cras. Nec tincidunt praesent semper feugiat nibh sed pulvinar proin gravida. Egestas integer eget aliquet nibh praesent tristique magna.
|
||||
@@ -1,16 +0,0 @@
|
||||
---
|
||||
title: 'Third post'
|
||||
description: 'Lorem ipsum dolor sit amet'
|
||||
pubDate: 'Jul 15 2022'
|
||||
heroImage: '/blog-placeholder-2.jpg'
|
||||
---
|
||||
|
||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Vitae ultricies leo integer malesuada nunc vel risus commodo viverra. Adipiscing enim eu turpis egestas pretium. Euismod elementum nisi quis eleifend quam adipiscing. In hac habitasse platea dictumst vestibulum. Sagittis purus sit amet volutpat. Netus et malesuada fames ac turpis egestas. Eget magna fermentum iaculis eu non diam phasellus vestibulum lorem. Varius sit amet mattis vulputate enim. Habitasse platea dictumst quisque sagittis. Integer quis auctor elit sed vulputate mi. Dictumst quisque sagittis purus sit amet.
|
||||
|
||||
Morbi tristique senectus et netus. Id semper risus in hendrerit gravida rutrum quisque non tellus. Habitasse platea dictumst quisque sagittis purus sit amet. Tellus molestie nunc non blandit massa. Cursus vitae congue mauris rhoncus. Accumsan tortor posuere ac ut. Fringilla urna porttitor rhoncus dolor. Elit ullamcorper dignissim cras tincidunt lobortis. In cursus turpis massa tincidunt dui ut ornare lectus. Integer feugiat scelerisque varius morbi enim nunc. Bibendum neque egestas congue quisque egestas diam. Cras ornare arcu dui vivamus arcu felis bibendum. Dignissim suspendisse in est ante in nibh mauris. Sed tempus urna et pharetra pharetra massa massa ultricies mi.
|
||||
|
||||
Mollis nunc sed id semper risus in. Convallis a cras semper auctor neque. Diam sit amet nisl suscipit. Lacus viverra vitae congue eu consequat ac felis donec. Egestas integer eget aliquet nibh praesent tristique magna sit amet. Eget magna fermentum iaculis eu non diam. In vitae turpis massa sed elementum. Tristique et egestas quis ipsum suspendisse ultrices. Eget lorem dolor sed viverra ipsum. Vel turpis nunc eget lorem dolor sed viverra. Posuere ac ut consequat semper viverra nam. Laoreet suspendisse interdum consectetur libero id faucibus. Diam phasellus vestibulum lorem sed risus ultricies tristique. Rhoncus dolor purus non enim praesent elementum facilisis. Ultrices tincidunt arcu non sodales neque. Tempus egestas sed sed risus pretium quam vulputate. Viverra suspendisse potenti nullam ac tortor vitae purus faucibus ornare. Fringilla urna porttitor rhoncus dolor purus non. Amet dictum sit amet justo donec enim.
|
||||
|
||||
Mattis ullamcorper velit sed ullamcorper morbi tincidunt. Tortor posuere ac ut consequat semper viverra. Tellus mauris a diam maecenas sed enim ut sem viverra. Venenatis urna cursus eget nunc scelerisque viverra mauris in. Arcu ac tortor dignissim convallis aenean et tortor at. Curabitur gravida arcu ac tortor dignissim convallis aenean et tortor. Egestas tellus rutrum tellus pellentesque eu. Fusce ut placerat orci nulla pellentesque dignissim enim sit amet. Ut enim blandit volutpat maecenas volutpat blandit aliquam etiam. Id donec ultrices tincidunt arcu. Id cursus metus aliquam eleifend mi.
|
||||
|
||||
Tempus quam pellentesque nec nam aliquam sem. Risus at ultrices mi tempus imperdiet. Id porta nibh venenatis cras sed felis eget velit. Ipsum a arcu cursus vitae. Facilisis magna etiam tempor orci eu lobortis elementum. Tincidunt dui ut ornare lectus sit. Quisque non tellus orci ac. Blandit libero volutpat sed cras. Nec tincidunt praesent semper feugiat nibh sed pulvinar proin gravida. Egestas integer eget aliquet nibh praesent tristique magna.
|
||||
@@ -1,31 +0,0 @@
|
||||
---
|
||||
title: 'Using MDX'
|
||||
description: 'Lorem ipsum dolor sit amet'
|
||||
pubDate: 'Jul 02 2022'
|
||||
heroImage: '/blog-placeholder-5.jpg'
|
||||
---
|
||||
|
||||
This theme comes with the [@astrojs/mdx](https://docs.astro.build/en/guides/integrations-guide/mdx/) integration installed and configured in your `astro.config.mjs` config file. If you prefer not to use MDX, you can disable support by removing the integration from your config file.
|
||||
|
||||
## Why MDX?
|
||||
|
||||
MDX is a special flavor of Markdown that supports embedded JavaScript & JSX syntax. This unlocks the ability to [mix JavaScript and UI Components into your Markdown content](https://docs.astro.build/en/guides/markdown-content/#mdx-features) for things like interactive charts or alerts.
|
||||
|
||||
If you have existing content authored in MDX, this integration will hopefully make migrating to Astro a breeze.
|
||||
|
||||
## Example
|
||||
|
||||
Here is how you import and use a UI component inside of MDX.
|
||||
When you open this page in the browser, you should see the clickable button below.
|
||||
|
||||
import HeaderLink from '../../components/HeaderLink.astro';
|
||||
|
||||
<HeaderLink href="#" onclick="alert('clicked!')">
|
||||
Embedded component in MDX
|
||||
</HeaderLink>
|
||||
|
||||
## More Links
|
||||
|
||||
- [MDX Syntax Documentation](https://mdxjs.com/docs/what-is-mdx)
|
||||
- [Astro Usage Documentation](https://docs.astro.build/en/guides/markdown-content/#markdown-and-mdx-pages)
|
||||
- **Note:** [Client Directives](https://docs.astro.build/en/reference/directives-reference/#client-directives) are still required to create interactive components. Otherwise, all components in your MDX will render as static HTML (no JavaScript) by default.
|
||||
@@ -0,0 +1,12 @@
|
||||
---
|
||||
title: Astro-Bloomz
|
||||
date: '2023-10-04'
|
||||
---
|
||||
|
||||
Astro-Bloomz è un [[digital-garden]], la cui caratteristica principale sono i [[wikirefs]] (detti anche "link bidirezionali"). Si tratta di link che usano la sintassi `[[doppia-parentesi-quadra]]` per collegare file all'interno di una collezione di documenti markdown. Possono essere usati in qualsiasi file markdown del sito, a patto che i nomi dei file siano univoci.
|
||||
|
||||
I "Bloomz" sono le parti di un giardino digitale in stile [[wikibonsai]] pensate per essere condivise, mostrate e incrociate — ma attento a non farti pungere! 🐝
|
||||
|
||||
I giardini in stile [[wikibonsai]] aggiungono in particolare un [[semantic-tree]], visualizzabile come una sorta di albero di #tag chiamato [mappa](/map). È costruito a partire dai [[index-type|file indice]], il cui contenuto ne definisce la struttura tramite liste markdown e `[[wikirefs]]`. I file collegati nell'albero semantico sono principalmente [[entry-type|entry]], che fungono da riepiloghi concettuali, in modo simile a una pagina di Wikipedia. Ogni entry mostra anche i riferimenti a ritroso, ovvero quali altri post la citano.
|
||||
|
||||
Queste sintassi e questo modo di lavorare mirano a rendere grandi quantità di contenuti più facilmente navigabili, senza dover ricorrere ad algoritmi e meccanismi di ricerca opachi (anche se questi sono generalmente disponibili).
|
||||
@@ -0,0 +1,12 @@
|
||||
---
|
||||
title: 🪴 Digital Garden
|
||||
date: '2021-08-04'
|
||||
---
|
||||
|
||||
La caratteristica distintiva di un [digital garden](https://twitter.com/wibomd/status/1703946098589548622) è il `[[wikiref]]` (o "[[wikirefs|link bidirezionale]]"). Aggiungendo una fitta rete di link interni, le pagine di un sito diventano descrittive di una topografia di concetti che le descrivono o ne vengono utilizzati.
|
||||
|
||||
Le tecniche osservate in natura sono tipicamente un mix derivato da [personal knowledge management](https://en.wikipedia.org/wiki/Personal_knowledge_management), [personal wiki](https://en.wikipedia.org/wiki/Personal_wiki), [tools for thought](https://numinous.productions/ttft/), [zettelkasten](https://en.wikipedia.org/wiki/Zettelkasten) ed [evergreen notes](https://entries.andymatuschak.org/z4SDCZQeRo4xFEQ8H4qrSqd68ucpgE6LU155C), tra gli altri.
|
||||
|
||||
_[[wikibonsai|WikiBonsai]]_ è la sintesi e la cura di ciò che questo particolare giardiniere ha imparato e costruito.
|
||||
|
||||
Curiosità: "giardinaggio" è una metafora sorprendentemente comune che [spunta](https://twitter.com/wibomd/status/1704147337738654189) nei posti più inaspettati.
|
||||
@@ -0,0 +1,9 @@
|
||||
---
|
||||
title: Tipo di Documento
|
||||
---
|
||||
|
||||
I tipi di documento, o "doctype", sono sinonimi delle [content collection di Astro](https://docs.astro.build/en/guides/content-collections/). Sono tipi di documenti markdown usati per renderizzare i contenuti in modi specifici. I seguenti sono i doctype previsti in un [[digital-garden]] stile [[wikibonsai]]:
|
||||
|
||||
- [`posts`](https://docs.astro.build/en/guides/cms/keystatic/#creating-a-new-post)
|
||||
- [[index-type]]
|
||||
- [[entry-type]]
|
||||
@@ -0,0 +1,22 @@
|
||||
---
|
||||
title: DocType Entry
|
||||
---
|
||||
|
||||
Come in un dizionario, un'enciclopedia o Wikipedia, le entry sono uno dei tipi di documento centrali di questo template (insieme agli [[index-type]] e ai [[post-type]]). Sono concetti e idee atomici, significativamente [[wikirefs|collegati]] tra loro in modo da rendere comprensibile come quei concetti si relazionano.
|
||||
|
||||
Il percorso breadcrumb è formato dalla posizione dell'entry corrente nell'[[semantic-tree]]. I link nel footer sono costruiti sia dalla sua posizione nell'albero sia dai [[wikirefs]] in avanti e a ritroso.
|
||||
|
||||
### Markdown
|
||||
|
||||
Le entry conterranno tipicamente frontmatter e/o wikiattr, seguiti dal testo markdown:
|
||||
|
||||
```markdown
|
||||
---
|
||||
frontmatter: attributi
|
||||
---
|
||||
|
||||
:tipo::[[wikiattr]]
|
||||
|
||||
Segue il resto del testo del documento,
|
||||
che potrà contenere altri [[wikilink]].
|
||||
```
|
||||
@@ -0,0 +1,62 @@
|
||||
---
|
||||
title: DocType Index
|
||||
---
|
||||
|
||||
I documenti indice sono il metodo principale per strutturare l'[[semantic-tree]]. Sono uno dei tipi di documento centrali di questo template (insieme agli [[entry-type]] e ai [[post-type]]).
|
||||
|
||||
### Navigazione
|
||||
|
||||
- Tramite la [[map-page]].
|
||||
- Tramite i [[wikirefs]].
|
||||
|
||||
### Markdown
|
||||
|
||||
I file indice costruiscono l'[[semantic-tree]], visualizzabile nella [[map-page]]. Vanno collocati nella directory `./content/index/` e ciascuno deve contenere un elenco markdown con [[wikirefs]] che puntano tipicamente a [[entry-type|entry]] (ma possono puntare a qualsiasi [[doctype]]). Possono contenere o meno frontmatter yaml.
|
||||
|
||||
I documenti devono avere questa forma (senza i commenti):
|
||||
|
||||
(i caratteri di escape `\\` sono aggiunti per mostrare il testo grezzo)
|
||||
|
||||
```markdown
|
||||
// file: i.bonsai.md
|
||||
|
||||
- [[bk.how-to-read-a-book]]
|
||||
- [[read]]
|
||||
- [[4-levels-of-reading]]
|
||||
- [[elementary-reading]]
|
||||
- [[inspectional-reading]]
|
||||
- [[analytical-reading]]
|
||||
- [[syntopical-reading]]
|
||||
```
|
||||
|
||||
L'albero può essere suddiviso in più file indice:
|
||||
|
||||
```markdown
|
||||
// file: i.bonsai.md
|
||||
|
||||
- [[bk.how-to-read-a-book]]
|
||||
- [[i.read]]
|
||||
```
|
||||
|
||||
```markdown
|
||||
// file: i.read.md
|
||||
|
||||
- [[4-levels-of-reading]]
|
||||
- [[elementary-reading]]
|
||||
- [[inspectional-reading]]
|
||||
- [[analytical-reading]]
|
||||
- [[syntopical-reading]]
|
||||
```
|
||||
|
||||
Entrambi gli esempi genereranno un albero con questa struttura:
|
||||
|
||||
```markdown
|
||||
i.bonsai
|
||||
└── bk.how-to-read-a-book
|
||||
└── i.read
|
||||
└── 4-levels-of-reading
|
||||
├── elementary-reading
|
||||
├── inspectional-reading
|
||||
├── analytical-reading
|
||||
└── syntopical-reading
|
||||
```
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
title: Pagina Mappa
|
||||
---
|
||||
|
||||
Questa pagina mostra l'[[semantic-tree]] completo generato dai documenti [[index-type]].
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
title: Remark-WikiRefs
|
||||
---
|
||||
|
||||
Il pacchetto `remark-wikirefs` è responsabile della gestione della sintassi markdown dei [[wikirefs]]. È disponibile su [GitHub](https://github.com/wikibonsai/remark-wikirefs).
|
||||
@@ -0,0 +1,13 @@
|
||||
---
|
||||
title: Albero Semantico
|
||||
---
|
||||
|
||||
:plugin::[[semtree]]
|
||||
|
||||
L'albero semantico è costruito con il plugin [[semtree]] (vedi la documentazione per i dettagli). È definito dai documenti [[index-type]] in formato markdown. Forma una gerarchia concettuale con lo scopo di orientare il lettore all'interno dei concetti del sito.
|
||||
|
||||
Vale la pena ripeterlo:
|
||||
|
||||
> "È importante considerare la conoscenza come una sorta di albero semantico. Assicurati di comprendere i principi fondamentali — ovvero il tronco e i rami principali — prima di addentrarsi nelle foglie e nei dettagli, altrimenti non avranno nulla a cui aggrapparsi."
|
||||
>
|
||||
> ~ [Elon Musk](https://www.reddit.com/r/IAmA/comments/2rgsan/comment/cnfre0a/?utm_source=share&utm_medium=web2x&context=3)
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
title: SemTree
|
||||
---
|
||||
|
||||
Il pacchetto `semtree` è responsabile della costruzione dell'[[semantic-tree]]. È disponibile su [GitHub](https://github.com/wikibonsai/semtree).
|
||||
@@ -0,0 +1,6 @@
|
||||
---
|
||||
title: Test Render
|
||||
date: '2023-10-05'
|
||||
---
|
||||
|
||||
Questo file serve specificamente a testare il rendering dei [[wikirefs]] come wikiembed.
|
||||
@@ -0,0 +1,244 @@
|
||||
---
|
||||
title: Test
|
||||
date: '2021-08-04'
|
||||
---
|
||||
|
||||
Questa pagina serve a testare e mostrare gli stili markdown disponibili in questo template.
|
||||
|
||||
## Markdown
|
||||
|
||||
(alcuni caratteri di escape `\` sono aggiunti per mostrare il testo grezzo)
|
||||
|
||||
### WikiRefs
|
||||
|
||||
#### WikiAttr con prefisso (vedi attrbox per l'output)
|
||||
|
||||
```markdown
|
||||
:prefixed-wikiattr::[[wikirefs]]
|
||||
```
|
||||
|
||||
:prefixed-wikiattr::[[wikirefs]]
|
||||
|
||||
#### Lista WikiAttr con prefisso (vedi attrbox per l'output)
|
||||
|
||||
```markdown
|
||||
: prefixed-wikiattr-list ::
|
||||
- [[wikirefs]]
|
||||
- [[feedback]]
|
||||
```
|
||||
|
||||
: prefixed-wikiattr-list ::
|
||||
- [[wikirefs]]
|
||||
- [[feedback]]
|
||||
|
||||
#### WikiAttr senza prefisso (vedi attrbox per il rendering)
|
||||
|
||||
```markdown
|
||||
unprefixed-wikiattr::[[wikirefs]]
|
||||
```
|
||||
|
||||
unprefixed-wikiattr::[[wikirefs]]
|
||||
|
||||
#### Lista WikiAttr senza prefisso (vedi attrbox per il rendering)
|
||||
|
||||
```markdown
|
||||
unprefixed-wikiattr-list ::
|
||||
- [[wikirefs]]
|
||||
- [[feedback]]
|
||||
```
|
||||
|
||||
unprefixed-wikiattr-list ::
|
||||
- [[wikirefs]]
|
||||
- [[feedback]]
|
||||
|
||||
#### Un WikiLink
|
||||
|
||||
```markdown
|
||||
[[digital-garden]]
|
||||
```
|
||||
|
||||
[[digital-garden]]
|
||||
|
||||
#### Un WikiLink tipizzato (controlla l'HTML per la classe CSS linktype)
|
||||
|
||||
```markdown
|
||||
:typed-wikilink::[[digital-garden]].
|
||||
```
|
||||
|
||||
:typed-wikilink::[[digital-garden]].
|
||||
|
||||
#### Un WikiEmbed (Markdown)
|
||||
|
||||
```markdown
|
||||
![[test-render]]
|
||||
```
|
||||
|
||||
![[test-render]]
|
||||
|
||||
#### Un WikiEmbed (Immagine)
|
||||
|
||||
```markdown
|
||||
![[wikibonsai-way.png]]
|
||||
```
|
||||
|
||||
![[wikibonsai-way.png]]
|
||||
|
||||
#### Zombie (link a pagine inesistenti)
|
||||
|
||||
#### WikiAttr con prefisso zombie (vedi attrbox per il rendering)
|
||||
|
||||
```markdown
|
||||
:zombie-wikiattr::[[zombie]]
|
||||
```
|
||||
|
||||
:zombie-wikiattr::[[zombie]]
|
||||
|
||||
#### Lista WikiAttr con prefisso zombie (vedi attrbox per il rendering)
|
||||
|
||||
```markdown
|
||||
: zombie-wikiattr-list ::
|
||||
- [[zombie-1]]
|
||||
- [[zombie-2]]
|
||||
```
|
||||
|
||||
: zombie-wikiattr-list ::
|
||||
- [[zombie-1]]
|
||||
- [[zombie-2]]
|
||||
|
||||
#### WikiAttr senza prefisso zombie (vedi attrbox per il rendering)
|
||||
|
||||
```markdown
|
||||
zombie-wikiattr::[[zombie]]
|
||||
```
|
||||
|
||||
zombie-wikiattr::[[zombie]]
|
||||
|
||||
#### Lista WikiAttr senza prefisso zombie (vedi attrbox per il rendering)
|
||||
|
||||
```markdown
|
||||
zombie-wikiattr-list ::
|
||||
- [[zombie-1]]
|
||||
- [[zombie-2]]
|
||||
```
|
||||
|
||||
zombie-wikiattr-list ::
|
||||
- [[zombie-1]]
|
||||
- [[zombie-2]]
|
||||
|
||||
#### WikiLink zombie
|
||||
|
||||
```markdown
|
||||
[[zombie]]
|
||||
```
|
||||
|
||||
[[zombie]]
|
||||
|
||||
#### WikiLink tipizzato zombie
|
||||
|
||||
```markdown
|
||||
:zombie-typed-wikilink::[[zombie]].
|
||||
```
|
||||
|
||||
:zombie-typed-wikilink::[[zombie]].
|
||||
|
||||
#### WikiEmbed zombie
|
||||
|
||||
```markdown
|
||||
![[zombie]]
|
||||
```
|
||||
|
||||
![[zombie]]
|
||||
|
||||
#### Intestazioni
|
||||
|
||||
```markdown
|
||||
# Intestazione 1
|
||||
## Intestazione 2
|
||||
### Intestazione 3
|
||||
#### Intestazione 4
|
||||
##### Intestazione 5
|
||||
###### Intestazione 6
|
||||
```
|
||||
|
||||
# Intestazione 1
|
||||
## Intestazione 2
|
||||
### Intestazione 3
|
||||
#### Intestazione 4
|
||||
##### Intestazione 5
|
||||
###### Intestazione 6
|
||||
|
||||
#### Liste
|
||||
|
||||
```markdown
|
||||
- Uno
|
||||
- Due
|
||||
- Tre
|
||||
```
|
||||
|
||||
- Uno
|
||||
- Due
|
||||
- Tre
|
||||
|
||||
#### Citazione
|
||||
|
||||
```markdown
|
||||
> Citazione.
|
||||
```
|
||||
|
||||
> Citazione.
|
||||
|
||||
#### Link web
|
||||
|
||||
```markdown
|
||||
[Link web](https://astro-bloomz.netlify.app)
|
||||
```
|
||||
|
||||
[Link web](https://astro-bloomz.netlify.app)
|
||||
|
||||
#### Blocco di codice
|
||||
|
||||
```javascript
|
||||
// javascript
|
||||
for (var i=1; i < 101; i++){
|
||||
if (i % 15 == 0) console.log("FizzBuzz");
|
||||
else if (i % 3 == 0) console.log("Fizz");
|
||||
else if (i % 5 == 0) console.log("Buzz");
|
||||
else console.log(i);
|
||||
}
|
||||
```
|
||||
|
||||
```ruby
|
||||
# ruby
|
||||
1.upto 100 do |i|
|
||||
string = ""
|
||||
string += "Fizz" if i % 3 == 0
|
||||
string += "Buzz" if i % 5 == 0
|
||||
puts "#{i} = #{string}"
|
||||
end
|
||||
```
|
||||
|
||||
#### Codice inline
|
||||
|
||||
```markdown
|
||||
Va bene, `va bene`, va bene.
|
||||
```
|
||||
|
||||
Va bene, `va bene`, va bene.
|
||||
|
||||
#### Tabelle
|
||||
|
||||
```markdown
|
||||
| Conigli | Volpi | Ricci |
|
||||
|:------- |:-----:| -----:|
|
||||
| 25 | 3 | 12 |
|
||||
| 100 | 10 | 20 |
|
||||
```
|
||||
|
||||
| Conigli | Volpi | Ricci |
|
||||
|:------- |:-----:| -----:|
|
||||
| 25 | 3 | 12 |
|
||||
| 100 | 10 | 20 |
|
||||
|
||||
#### Testo lungo
|
||||
|
||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla imperdiet, eros in aliquet eleifend, felis tellus laoreet velit, a feugiat purus mi at arcu. Sed tempor congue gravida. Suspendisse sodales ultricies lacus, nec consequat mauris dictum in. Aliquam at lacus sodales, porta velit in, consequat mauris. Maecenas consequat fermentum tortor, vitae tincidunt sem porta vel. Sed elementum dui libero, vitae bibendum est imperdiet non. Curabitur sit amet libero quis nulla faucibus euismod. Cras condimentum ante tortor, a sollicitudin elit accumsan eget.
|
||||
@@ -0,0 +1,12 @@
|
||||
---
|
||||
title: WikiBonsai
|
||||
---
|
||||
|
||||
![[wikibonsai-way.png]][^twt]
|
||||
|
||||
Astro-Bloomz è un progetto [WikiBonsai](https://github.com/wikibonsai/wikibonsai).
|
||||
|
||||
![[astro-bloomz]]
|
||||
|
||||
|
||||
[^twt]: [spiegazione](https://twitter.com/wibomd/status/1703930973371412699)
|
||||
@@ -0,0 +1,19 @@
|
||||
---
|
||||
title: WikiRefs
|
||||
---
|
||||
|
||||
plugin::[[remark-wikirefs]]
|
||||
|
||||
|
||||
I `[[WikiRefs]]`[^nomi] sono una parte fondamentale del mondo del [[digital-garden|digital gardening]]. Sono il mattone di base dell'interconnessione realizzata in molti giardini digitali, incluso questo. Vengono renderizzati con il plugin [[remark-wikirefs]], appaiono in un colore diverso rispetto ai link web esterni, e puoi consultare quella documentazione per ulteriori dettagli.
|
||||
|
||||
In breve, questo particolare tipo di `[[wikirefs]]` comprende tre costrutti wiki: wikiattr, wikilink e wikimbed.
|
||||
|
||||
I _WikiAttr_ sono attributi formalizzati di un file. Includono un tipo di attributo descrittivo e un wikilink a un altro file. Si scrivono `:così::[[wikilink]]` (con un'a capo dopo) e vengono renderizzati nell'attributebox (attrbox).
|
||||
|
||||
I _WikiLink_ sono i tradizionali link bidirezionali con la sintassi a parentesi quadre e possono comparire ovunque in un file. Esistono `:tipizzati::[[wikilink]]` e normali `[[wikilink]]` non tipizzati. Sono evidenziati in un colore diverso rispetto ai link web esterni.
|
||||
|
||||
I _WikiEmbed_ incorporano il contenuto del file collegato direttamente nella pagina corrente. È possibile incorporare file markdown, immagini, audio o video. I WikiEmbed si scrivono `![[così]]`.
|
||||
|
||||
|
||||
[^nomi]: "wikiref" porta in realtà molti nomi: "[wikilink](https://en.wikipedia.org/wiki/Help:Link)", "[link bidirezionale](https://maggieappleton.com/bidirectionals)", "[wikitext linking](https://tiddlywiki.com/#Linking%20in%20WikiText)", "backlink", "[link interno](https://help.obsidian.md/How+to/Internal+link)", per citarne solo alcuni...
|
||||
@@ -1,12 +0,0 @@
|
||||
---
|
||||
title: Astro-Bloomz
|
||||
date: '2023-10-04'
|
||||
---
|
||||
|
||||
Astro-Bloomz is a [[digital-garden]], whose defining feature are [[wikirefs]] (aka "bidirectional link"). These are links using the `[[double-square-bracket]]` syntax that link between files within a collection of markdown files. They can be used in any and all markdown files across the site, though unique filenames are required.
|
||||
|
||||
"Bloomz" are the parts of a [[wikibonsai]] style digital garden meant to be shared, shown off, and cross-pollinatated -- but be careful not to get stung! 🐝
|
||||
|
||||
[[wikibonsai]] style gardens in particular add a [[semantic-tree]], which is viewable as a sort of #tag tree called the [map-page](/map). It is built from [[index-type|index files]] whose content defines its structure using markdown lists and `[[wikirefs]]`. The files linked in the semantic tree are primarily [[entry-type|entries]] which act as concept summaries, much like a Wikipedia page. Each entry also displays back references, such as which posts link to those entries.
|
||||
|
||||
These syntaxes and workflows aim to make large amounts of content more easily navigable without the need for algorithms and opaque search mechanisms (though those are also generally readily accessible).
|
||||
@@ -1,13 +0,0 @@
|
||||
---
|
||||
title: 🪴 Digital Garden
|
||||
date: '2021-08-04'
|
||||
---
|
||||
|
||||
The defining feature of a [digital garden](https://twitter.com/wibomd/status/1703946098589548622) is the `[[wikiref]]` (or "[[wikirefs|bidirectional link]]"). By adding dense internal links, the pages of a site become descriptive of a topography of concepts which describe or are used in said site.
|
||||
|
||||
Techniques found in the wild are typically a mix derived from [personal knowledge management](https://en.wikipedia.org/wiki/Personal_knowledge_management), [personal wikis](https://en.wikipedia.org/wiki/Personal_wiki), [tools for thought](https://numinous.productions/ttft/), [zettelkasten](https://en.wikipedia.org/wiki/Zettelkasten), and [evergreen notes](https://entries.andymatuschak.org/z4SDCZQeRo4xFEQ8H4qrSqd68ucpgE6LU155C) among others.
|
||||
|
||||
_[[wikibonsai|WikiBonsai]]_ is the culmination and curation of what this particular gardener has learned and built.
|
||||
|
||||
Also, "gardening" is a surprisingly common metaphor that [pops up](https://twitter.com/wibomd/status/1704147337738654189) in many unexpected places.
|
||||
|
||||
@@ -1,9 +0,0 @@
|
||||
---
|
||||
title: Document Type
|
||||
---
|
||||
|
||||
Document types, or 'doctypes', are synonymous with [Astro content collections](https://docs.astro.build/en/guides/content-collections/). They are types of markdown documents that are used to render content in specific ways. The following are the doctypes expected to exist in a [[wikibonsai]] [[digital-garden]]:
|
||||
|
||||
- [`posts`](https://docs.astro.build/en/guides/cms/keystatic/#creating-a-new-post)
|
||||
- [[index-type]]
|
||||
- [[entry-type]]
|
||||
@@ -1,22 +0,0 @@
|
||||
---
|
||||
title: Entry DocType
|
||||
---
|
||||
|
||||
Like in a dictionary, encylopedia, or wikipedia, entries are one of the central document types to this template (besides [[index-type]]s and [[post-type]]s). They are atomic concepts and ideas that are meaningfully [[wikirefs|linked]] so as to understand how those concepts relate to one another.
|
||||
|
||||
The breadcrumb trail is formed by the current entry's position in the [[semantic-tree]]. And footer links are built from both its position in the tree as well as the fore and back [[wikirefs]].
|
||||
|
||||
### Markdown
|
||||
|
||||
Entries will typically contain frontmatter and/or wikiattrs, and markdown text respectively:
|
||||
|
||||
```markdown
|
||||
---
|
||||
frontmatter: attributes
|
||||
---
|
||||
|
||||
:type::[[wikiattr]]
|
||||
|
||||
Then follows the rest of the text for the document,
|
||||
some of which might contain some more [[wikilinks]].
|
||||
```
|
||||
@@ -1,62 +0,0 @@
|
||||
---
|
||||
title: Index DocType
|
||||
---
|
||||
|
||||
Index documents are the primary method of structuring the [[semantic-tree]]. They are one of the central document types to this template (besides [[entry-type]]s and [[post-type]]s).
|
||||
|
||||
### Navigate
|
||||
|
||||
- Via the [[map-page]].
|
||||
- Via [[wikirefs]].
|
||||
|
||||
### Markdown
|
||||
|
||||
Index files build the [[semantic-tree]], which can be viewed on the [[map-page]]. They are placed in the `./content/index/` directory and each file should contain a markdown outline with [[wikirefs]] that typically point to [[entry-type]]s (but can point to any [[doctype]]). They may or may not contain yaml [[frontmatter]].
|
||||
|
||||
Documents should look like this (minus comments):
|
||||
|
||||
(escape chars '\\' added to ensure raw text display)
|
||||
|
||||
```markdown
|
||||
// file: i.bonsai.md
|
||||
|
||||
- [[bk.how-to-read-a-book]]
|
||||
- [[read]]
|
||||
- [[4-levels-of-reading]]
|
||||
- [[elementary-reading]]
|
||||
- [[inspectional-reading]]
|
||||
- [[analytical-reading]]
|
||||
- [[syntopical-reading]]
|
||||
```
|
||||
|
||||
The tree may also be broken up into multiple index files:
|
||||
|
||||
```markdown
|
||||
// file: i.bonsai.md
|
||||
|
||||
- [[bk.how-to-read-a-book]]
|
||||
- [[i.read]]
|
||||
```
|
||||
|
||||
```markdown
|
||||
// file: i.read.md
|
||||
|
||||
- [[4-levels-of-reading]]
|
||||
- [[elementary-reading]]
|
||||
- [[inspectional-reading]]
|
||||
- [[analytical-reading]]
|
||||
- [[syntopical-reading]]
|
||||
```
|
||||
|
||||
Both of the above examples will generate a tree that looks like this:
|
||||
|
||||
```markdown
|
||||
i.bonsai
|
||||
└── bk.how-to-read-a-book
|
||||
└── i.read
|
||||
└── 4-levels-of-reading
|
||||
├── elementary-reading
|
||||
├── inspectional-reading
|
||||
├── analytical-reading
|
||||
└── syntopical-reading
|
||||
```
|
||||
@@ -1,5 +0,0 @@
|
||||
---
|
||||
title: Tag Map Page
|
||||
---
|
||||
|
||||
This page displays the full [[semantic-tree]] generated from the [[index-type]] documents.
|
||||
@@ -1,5 +0,0 @@
|
||||
---
|
||||
title: Remark-WikiRefs
|
||||
---
|
||||
|
||||
The `remark-wikirefs` package is responsible for handling the [[wikirefs]] markdown syntax. It can be found on [GitHub](https://github.com/wikibonsai/remark-wikirefs).
|
||||
@@ -1,13 +0,0 @@
|
||||
---
|
||||
title: Semantic Tree
|
||||
---
|
||||
|
||||
:plugin::[[semtree]]
|
||||
|
||||
The semantic tree is built with the [[semtree]] plugin (see docs for details).It is defined by the documents in the [[index-type]] markdown files. It forms a conceptual hierarchy with the purpose of orienting one within the concepts of a site.
|
||||
|
||||
In case it needs repeating:
|
||||
|
||||
> “It is important to view knowledge as a sort of semantic tree. Make sure you understand the fundamental principles, i.e., the trunk and big branches before you get into the leaves/details or there is nothing for them to hang on to.”
|
||||
>
|
||||
> ~ [Elon Musk](https://www.reddit.com/r/IAmA/comments/2rgsan/comment/cnfre0a/?utm_source=share&utm_medium=web2x&context=3)
|
||||
@@ -1,5 +0,0 @@
|
||||
---
|
||||
title: SemTree
|
||||
---
|
||||
|
||||
The `semtree` package is responsible for building the [[semantic-tree]]. It can be found on [GitHub](https://github.com/wikibonsai/semtree).
|
||||
@@ -1,6 +0,0 @@
|
||||
---
|
||||
title: Test Render
|
||||
date: '2023-10-05'
|
||||
---
|
||||
|
||||
This file is specifically to test [[wikirefs]] rendering of wikiembeds.
|
||||
@@ -1,287 +0,0 @@
|
||||
---
|
||||
title: Test
|
||||
date: '2021-08-04'
|
||||
---
|
||||
|
||||
This is a page is for testing and showcasing the markdown styles in this template.
|
||||
|
||||
## Markdown
|
||||
|
||||
(some escape chars `\` are added to ensure raw display)
|
||||
|
||||
### WikiRefs
|
||||
|
||||
#### A Prefixed WikiAttr (see attrbox for output)
|
||||
|
||||
```markdown
|
||||
:prefixed-wikiattr::[[wikirefs]]
|
||||
```
|
||||
|
||||
:prefixed-wikiattr::[[wikirefs]]
|
||||
|
||||
#### A Prefixed WikiAttr List (see attrbox for output)
|
||||
|
||||
```markdown
|
||||
: prefixed-wikiattr-list ::
|
||||
- [[wikirefs]]
|
||||
- [[feedback]]
|
||||
```
|
||||
|
||||
: prefixed-wikiattr-list ::
|
||||
- [[wikirefs]]
|
||||
- [[feedback]]
|
||||
|
||||
#### An Unprefixed WikiAttr (see attrbox for render)
|
||||
|
||||
```markdown
|
||||
unprefixed-wikiattr::[[wikirefs]]
|
||||
```
|
||||
|
||||
unprefixed-wikiattr::[[wikirefs]]
|
||||
|
||||
#### An Unprefixed WikiAttr List (see attrbox for render)
|
||||
|
||||
```markdown
|
||||
unprefixed-wikiattr-list ::
|
||||
- [[wikirefs]]
|
||||
- [[feedback]]
|
||||
```
|
||||
|
||||
unprefixed-wikiattr-list ::
|
||||
- [[wikirefs]]
|
||||
- [[feedback]]
|
||||
|
||||
#### A WikiLink
|
||||
|
||||
```markdown
|
||||
[[digital-garden]]
|
||||
```
|
||||
|
||||
[[digital-garden]]
|
||||
|
||||
#### A Typed WikiLink (check html for linktype css class)
|
||||
|
||||
```markdown
|
||||
:typed-wikilink::[[digital-garden]].
|
||||
```
|
||||
|
||||
:typed-wikilink::[[digital-garden]].
|
||||
|
||||
#### A WikiEmbed (Markdown)
|
||||
|
||||
```markdown
|
||||
![[test-render]]
|
||||
```
|
||||
|
||||
![[test-render]]
|
||||
|
||||
#### A WikiEmbed (Image)
|
||||
|
||||
```markdown
|
||||
![[wikibonsai-way.png]]
|
||||
```
|
||||
|
||||
![[wikibonsai-way.png]]
|
||||
|
||||
#### Zombies
|
||||
|
||||
#### A Prefixed WikiAttr (see attrbox for render)
|
||||
|
||||
```markdown
|
||||
:zombie-wikiattr::[[zombie]]
|
||||
```
|
||||
|
||||
:zombie-wikiattr::[[zombie]]
|
||||
|
||||
#### A Prefixed WikiAttr List (see attrbox for render)
|
||||
|
||||
```markdown
|
||||
: zombie-wikiattr-list ::
|
||||
- [[zombie-1]]
|
||||
- [[zombie-2]]
|
||||
```
|
||||
|
||||
: zombie-wikiattr-list ::
|
||||
- [[zombie-1]]
|
||||
- [[zombie-2]]
|
||||
|
||||
#### An Unprefixed WikiAttr (see attrbox for render)
|
||||
|
||||
```markdown
|
||||
zombie-wikiattr::[[zombie]]
|
||||
```
|
||||
|
||||
zombie-wikiattr::[[zombie]]
|
||||
|
||||
#### An Unprefixed WikiAttr List (see attrbox for render)
|
||||
|
||||
```markdown
|
||||
zombie-wikiattr-list ::
|
||||
- [[zombie-1]]
|
||||
- [[zombie-2]]
|
||||
```
|
||||
|
||||
zombie-wikiattr-list ::
|
||||
- [[zombie-1]]
|
||||
- [[zombie-2]]
|
||||
|
||||
#### A WikiLink
|
||||
|
||||
```markdown
|
||||
[[zombie]]
|
||||
```
|
||||
|
||||
[[zombie]]
|
||||
|
||||
#### A Typed WikiLink
|
||||
|
||||
```markdown
|
||||
:zombie-typed-wikilink::[[zombie]].
|
||||
```
|
||||
|
||||
:zombie-typed-wikilink::[[zombie]].
|
||||
|
||||
#### A WikiEmbed
|
||||
|
||||
```markdown
|
||||
![[zombie]]
|
||||
```
|
||||
|
||||
![[zombie]]
|
||||
|
||||
#### Headers
|
||||
|
||||
```markdown
|
||||
# Header 1
|
||||
## Header 2
|
||||
### Header 3
|
||||
#### Header 4
|
||||
##### Header 5
|
||||
###### Header 6
|
||||
```
|
||||
|
||||
# Header 1
|
||||
## Header 2
|
||||
### Header 3
|
||||
#### Header 4
|
||||
##### Header 5
|
||||
###### Header 6
|
||||
|
||||
#### Lists
|
||||
|
||||
```markdown
|
||||
Lists:
|
||||
- One
|
||||
- Two
|
||||
- Three
|
||||
```
|
||||
|
||||
Lists:
|
||||
- One
|
||||
- Two
|
||||
- Three
|
||||
|
||||
#### Blockquote
|
||||
|
||||
```markdown
|
||||
> Blockquote.
|
||||
```
|
||||
|
||||
> Blockquote.
|
||||
|
||||
#### Weblink
|
||||
|
||||
```markdown
|
||||
[Weblink](https://astro-bloomz.netlify.app)
|
||||
```
|
||||
|
||||
[Weblink](https://astro-bloomz.netlify.app)
|
||||
|
||||
#### Code Block:
|
||||
|
||||
```markdown
|
||||
```javascript
|
||||
// javascript
|
||||
for (var i=1; i < 101; i++){
|
||||
if (i % 15 == 0) console.log("FizzBuzz");
|
||||
else if (i % 3 == 0) console.log("Fizz");
|
||||
else if (i % 5 == 0) console.log("Buzz");
|
||||
else console.log(i);
|
||||
}
|
||||
\```
|
||||
```ruby
|
||||
# ruby
|
||||
1.upto 100 do |i|
|
||||
string = ""
|
||||
string += "Fizz" if i % 3 == 0
|
||||
string += "Buzz" if i % 5 == 0
|
||||
puts "#{i} = #{string}"
|
||||
end
|
||||
\```
|
||||
```
|
||||
|
||||
```javascript
|
||||
// javascript
|
||||
for (var i=1; i < 101; i++){
|
||||
if (i % 15 == 0) console.log("FizzBuzz");
|
||||
else if (i % 3 == 0) console.log("Fizz");
|
||||
else if (i % 5 == 0) console.log("Buzz");
|
||||
else console.log(i);
|
||||
}
|
||||
```
|
||||
```ruby
|
||||
# ruby
|
||||
1.upto 100 do |i|
|
||||
string = ""
|
||||
string += "Fizz" if i % 3 == 0
|
||||
string += "Buzz" if i % 5 == 0
|
||||
puts "#{i} = #{string}"
|
||||
end
|
||||
```
|
||||
|
||||
#### Inline Code
|
||||
|
||||
```markdown
|
||||
Alright, `alright`, alright.
|
||||
```
|
||||
|
||||
Alright, `alright`, alright.
|
||||
|
||||
#### Tables
|
||||
|
||||
```markdown
|
||||
| Rabbits | Foxes | Hedgehogs |
|
||||
|:------- |:-----:| ---------:|
|
||||
| 25 | 3 | 12 |
|
||||
| 100 | 10 | 20 |
|
||||
```
|
||||
|
||||
| Rabbits | Foxes | Hedgehogs |
|
||||
|:------- |:-----:| ---------:|
|
||||
| 25 | 3 | 12 |
|
||||
| 100 | 10 | 20 |
|
||||
|
||||
#### Text
|
||||
|
||||
```markdown
|
||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla imperdiet, eros in aliquet eleifend, felis tellus laoreet velit, a feugiat purus mi at arcu. Sed tempor congue gravida. Suspendisse sodales ultricies lacus, nec consequat mauris dictum in. Aliquam at lacus sodales, porta velit in, consequat mauris. Maecenas consequat fermentum tortor, vitae tincidunt sem porta vel. Sed elementum dui libero, vitae bibendum est imperdiet non. Curabitur sit amet libero quis nulla faucibus euismod. Cras condimentum ante tortor, a sollicitudin elit accumsan eget. Phasellus scelerisque mi nunc, nec finibus tellus volutpat et. In et finibus dui, eget commodo massa. Pellentesque vitae dapibus quam, sed venenatis augue. Mauris semper a leo ut rutrum. Curabitur sed ante nisl.
|
||||
|
||||
Cras nec dictum turpis, ut tristique lectus. Duis posuere erat a dolor cursus interdum. Nulla sed turpis justo. Donec tempus turpis magna, in tempus dolor vulputate at. Nullam eget velit elementum, consequat lorem in, volutpat eros. Donec non dui sapien. Donec sed ultrices dui, eget interdum ipsum.
|
||||
|
||||
Nunc a sapien eros. Suspendisse sollicitudin semper ligula. Praesent ut laoreet ante, nec blandit nulla. Pellentesque ac venenatis nisi. Integer tincidunt nisi ut eros consequat condimentum. Duis a odio tristique, malesuada lorem eget, mollis leo. Quisque in neque nec mauris sodales mattis ac molestie risus.
|
||||
|
||||
Aenean et tortor lacinia lectus pulvinar tempus. Sed consequat nunc sed sagittis tempus. Integer consectetur turpis et suscipit posuere. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Etiam ultricies mi nec euismod ultrices. Aenean mollis tellus et magna semper, in gravida mi bibendum. In ex urna, fringilla sit amet viverra nec, euismod venenatis velit. Duis tincidunt erat semper est sollicitudin, a aliquet enim fermentum. Fusce in dui semper, suscipit dolor tincidunt, elementum nulla. In massa velit, finibus a felis ut, elementum bibendum nulla. Nunc malesuada consequat tellus, a auctor sem maximus eget. Donec eleifend enim sit amet libero finibus commodo. Vivamus at auctor eros, sed vulputate tortor. Nullam semper pellentesque eros, eu pretium leo pharetra et.
|
||||
|
||||
Nunc luctus turpis sed leo scelerisque mattis. Aliquam pellentesque non risus a placerat. Vivamus congue ipsum eget vestibulum tincidunt. Sed vitae urna dolor. Suspendisse ac fermentum magna, ut iaculis ligula. Nam fermentum ante egestas, porta justo pharetra, euismod sapien. Integer eu feugiat lorem. Aenean vestibulum, justo in pretium facilisis, magna elit aliquam risus, a vestibulum orci enim vel turpis. Suspendisse potenti. Sed aliquet est vel sapien porta, eu lacinia arcu porta.
|
||||
```
|
||||
|
||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla imperdiet, eros in aliquet eleifend, felis tellus laoreet velit, a feugiat purus mi at arcu. Sed tempor congue gravida. Suspendisse sodales ultricies lacus, nec consequat mauris dictum in. Aliquam at lacus sodales, porta velit in, consequat mauris. Maecenas consequat fermentum tortor, vitae tincidunt sem porta vel. Sed elementum dui libero, vitae bibendum est imperdiet non. Curabitur sit amet libero quis nulla faucibus euismod. Cras condimentum ante tortor, a sollicitudin elit accumsan eget. Phasellus scelerisque mi nunc, nec finibus tellus volutpat et. In et finibus dui, eget commodo massa. Pellentesque vitae dapibus quam, sed venenatis augue. Mauris semper a leo ut rutrum. Curabitur sed ante nisl.
|
||||
|
||||
Cras nec dictum turpis, ut tristique lectus. Duis posuere erat a dolor cursus interdum. Nulla sed turpis justo. Donec tempus turpis magna, in tempus dolor vulputate at. Nullam eget velit elementum, consequat lorem in, volutpat eros. Donec non dui sapien. Donec sed ultrices dui, eget interdum ipsum.
|
||||
|
||||
Nunc a sapien eros. Suspendisse sollicitudin semper ligula. Praesent ut laoreet ante, nec blandit nulla. Pellentesque ac venenatis nisi. Integer tincidunt nisi ut eros consequat condimentum. Duis a odio tristique, malesuada lorem eget, mollis leo. Quisque in neque nec mauris sodales mattis ac molestie risus.
|
||||
|
||||
Aenean et tortor lacinia lectus pulvinar tempus. Sed consequat nunc sed sagittis tempus. Integer consectetur turpis et suscipit posuere. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Etiam ultricies mi nec euismod ultrices. Aenean mollis tellus et magna semper, in gravida mi bibendum. In ex urna, fringilla sit amet viverra nec, euismod venenatis velit. Duis tincidunt erat semper est sollicitudin, a aliquet enim fermentum. Fusce in dui semper, suscipit dolor tincidunt, elementum nulla. In massa velit, finibus a felis ut, elementum bibendum nulla. Nunc malesuada consequat tellus, a auctor sem maximus eget. Donec eleifend enim sit amet libero finibus commodo. Vivamus at auctor eros, sed vulputate tortor. Nullam semper pellentesque eros, eu pretium leo pharetra et.
|
||||
|
||||
Nunc luctus turpis sed leo scelerisque mattis. Aliquam pellentesque non risus a placerat. Vivamus congue ipsum eget vestibulum tincidunt. Sed vitae urna dolor. Suspendisse ac fermentum magna, ut iaculis ligula. Nam fermentum ante egestas, porta justo pharetra, euismod sapien. Integer eu feugiat lorem. Aenean vestibulum, justo in pretium facilisis, magna elit aliquam risus, a vestibulum orci enim vel turpis. Suspendisse potenti. Sed aliquet est vel sapien porta, eu lacinia arcu porta.
|
||||
```
|
||||
@@ -1,12 +0,0 @@
|
||||
---
|
||||
title: WikiBonsai
|
||||
---
|
||||
|
||||
![[wikibonsai-way.png]][^twt]
|
||||
|
||||
Astro-Bloomz is a [WikiBonsai](https://github.com/wikibonsai/wikibonsai) project.
|
||||
|
||||
![[astro-bloomz]]
|
||||
|
||||
|
||||
[^twt]: [explain](https://twitter.com/wibomd/status/1703930973371412699)
|
||||
@@ -1,19 +0,0 @@
|
||||
---
|
||||
title: WikiRefs
|
||||
---
|
||||
|
||||
plugin::[[remark-wikirefs]]
|
||||
|
||||
|
||||
`[[WikiRefs]]`[^names] are a crucial part of the world of [[digital-garden|digital gardening]]. They are the basic building block of the interlinking accomplished in many gardens, including this one. They are rendered with the [[remark-wikirefs]] plugin, are rendered in a different color than external web links, and you can check out those docs for more details.
|
||||
|
||||
But in short, This particular flavour of `[[wikirefs]]` includes three kinds of wiki constructs: wikiattrs, wikilinks, and wikiembeds.
|
||||
|
||||
_WikiAttrs_ are formalized attributes of a file. They include a descriptive attrtype and a wikilink to another file. They look `:like-this::[[wikilink]]` (with a newline after) and are rendered in the attributes box (attrbox).
|
||||
|
||||
_WikiLinks_ are traditional bidirectional links using the square bracket syntax and may appear anywhere in a file. There are `:typed::[[wikilinks]]` and regular untyped `[[wikilinks]]`. They are highlighted in a different color than external web links.
|
||||
|
||||
_WikiEmbeds_ embed the content of the linked file into the current one in-place. Markdown files may be embedded as well as images, audio, or video files. WikiEmbeds look like `![[this]]`.
|
||||
|
||||
|
||||
[^names]: "wikiref" actually goes by many names: "[wikilink](https://en.wikipedia.org/wiki/Help:Link)", "[bidirectional link](https://maggieappleton.com/bidirectionals)", "[wikitext linking](https://tiddlywiki.com/#Linking%20in%20WikiText)","backlink", "[internal link](https://help.obsidian.md/How+to/Internal+link)", "humble double bracket internal link", to name only a few...
|
||||
+50
-16
@@ -1,13 +1,13 @@
|
||||
---
|
||||
import '../styles/global.css';
|
||||
import PageEditor from '../components/PageEditor.svelte';
|
||||
|
||||
interface Props {
|
||||
title?: string;
|
||||
description?: string;
|
||||
public?: boolean;
|
||||
}
|
||||
const { title = 'BincioWiki', description = 'The Bincio group wiki' } = Astro.props;
|
||||
const editUrl = import.meta.env.PUBLIC_EDIT_URL ?? '';
|
||||
const editEnabled = editUrl !== '';
|
||||
const { title = 'BincioWiki', description = 'La memoria collettiva del gruppo Bincio.', public: isPublic = false } = Astro.props;
|
||||
---
|
||||
<!doctype html>
|
||||
<html lang="en" data-theme="dark">
|
||||
@@ -26,6 +26,37 @@ const editEnabled = editUrl !== '';
|
||||
document.documentElement.setAttribute('data-theme', t);
|
||||
</script>
|
||||
|
||||
<!-- Race-calendar palette: auto-switches accent colour during Grand Tours -->
|
||||
<script is:inline>
|
||||
(function () {
|
||||
var palettes = {
|
||||
default: { accent: '#60a5fa', dim: 'rgba(96,165,250,0.15)' },
|
||||
giro: { accent: '#f472b6', dim: 'rgba(244,114,182,0.15)' },
|
||||
tour: { accent: '#facc15', dim: 'rgba(250,204,21,0.15)' },
|
||||
vuelta: { accent: '#ef4444', dim: 'rgba(239,68,68,0.15)' },
|
||||
};
|
||||
// [month 0-indexed, day] inclusive — update each year
|
||||
var races = [
|
||||
{ key: 'giro', start: [4, 8], end: [5, 1] },
|
||||
{ key: 'tour', start: [5, 27], end: [6, 19] },
|
||||
{ key: 'vuelta', start: [7, 15], end: [8, 6] },
|
||||
];
|
||||
function autoKey() {
|
||||
var now = new Date(), y = now.getFullYear();
|
||||
for (var i = 0; i < races.length; i++) {
|
||||
var r = races[i];
|
||||
if (now >= new Date(y, r.start[0], r.start[1]) &&
|
||||
now < new Date(y, r.end[0], r.end[1] + 1)) return r.key;
|
||||
}
|
||||
return 'default';
|
||||
}
|
||||
var key = autoKey();
|
||||
var p = palettes[key] || palettes.default;
|
||||
document.documentElement.style.setProperty('--accent', p.accent);
|
||||
document.documentElement.style.setProperty('--accent-dim', p.dim);
|
||||
})();
|
||||
</script>
|
||||
|
||||
<style is:global>
|
||||
/* ── Theme tokens ───────────────────────────────────────────────── */
|
||||
:root, [data-theme="dark"] {
|
||||
@@ -40,10 +71,10 @@ const editEnabled = editUrl !== '';
|
||||
--text-5: #71717a;
|
||||
--border: #27272a;
|
||||
--border-sub: #3f3f46;
|
||||
--accent: #00c8ff;
|
||||
--accent-dim: rgba(0,200,255,0.15);
|
||||
--text-color-wiki: #00c8ff;
|
||||
--text-color-wiki-visited: #009ab8;
|
||||
--accent: #60a5fa;
|
||||
--accent-dim: rgba(96,165,250,0.15);
|
||||
--text-color-wiki: var(--accent);
|
||||
--text-color-wiki-visited: #3b82f6;
|
||||
--text-color-invalid-wikilink: #52525b;
|
||||
}
|
||||
[data-theme="light"] {
|
||||
@@ -60,7 +91,7 @@ const editEnabled = editUrl !== '';
|
||||
--border-sub: #d4d4d8;
|
||||
--accent: #0284c7;
|
||||
--accent-dim: rgba(2,132,199,0.12);
|
||||
--text-color-wiki: #0284c7;
|
||||
--text-color-wiki: var(--accent);
|
||||
--text-color-wiki-visited: #0369a1;
|
||||
--text-color-invalid-wikilink: #a1a1aa;
|
||||
}
|
||||
@@ -105,13 +136,6 @@ const editEnabled = editUrl !== '';
|
||||
<a href="/map" class="text-sm text-zinc-400 hover:text-white transition-colors shrink-0">Map</a>
|
||||
</div>
|
||||
<div class="ml-auto shrink-0 flex items-center gap-1">
|
||||
{editEnabled && (
|
||||
<a
|
||||
href={editUrl}
|
||||
target="_blank"
|
||||
class="text-xs text-zinc-400 hover:text-white transition-colors px-2 py-1 rounded border border-zinc-700 hover:border-zinc-500"
|
||||
>Edit</a>
|
||||
)}
|
||||
<button
|
||||
id="theme-toggle"
|
||||
class="text-zinc-400 hover:text-white transition-colors w-8 h-8 flex items-center justify-center rounded-md hover:bg-zinc-800 text-base"
|
||||
@@ -126,9 +150,19 @@ const editEnabled = editUrl !== '';
|
||||
</main>
|
||||
|
||||
<footer class="border-t mt-12 py-6 text-center text-sm" style="border-color: var(--border); color: var(--text-5)">
|
||||
<p>BincioWiki — built with <a href="https://astro.build" class="hover:text-white transition-colors" style="color: var(--accent)">Astro</a> & <a href="https://github.com/wikibonsai/astro-bloomz" class="hover:text-white transition-colors" style="color: var(--accent)">astro-bloomz</a></p>
|
||||
<p>BincioWiki — built with <a href="https://astro.build" class="hover:text-white transition-colors" style="color: var(--accent)">Astro</a></p>
|
||||
</footer>
|
||||
|
||||
<PageEditor client:load />
|
||||
|
||||
<script define:vars={{ isPublic }}>
|
||||
if (!isPublic) {
|
||||
fetch('/api/me', { credentials: 'include' })
|
||||
.then(r => { if (r.status === 401 || r.status === 403) window.location.replace('/login/'); })
|
||||
.catch(() => {});
|
||||
}
|
||||
</script>
|
||||
|
||||
<script>
|
||||
const btn = document.getElementById('theme-toggle') as HTMLButtonElement;
|
||||
function applyTheme(theme: string) {
|
||||
|
||||
@@ -3,9 +3,9 @@ import type { CollectionEntry } from 'astro:content';
|
||||
import Base from './Base.astro';
|
||||
import FormattedDate from '../components/FormattedDate.astro';
|
||||
|
||||
type Props = CollectionEntry<'blog'>['data'];
|
||||
type Props = CollectionEntry<'blog'>['data'] & { id?: string };
|
||||
|
||||
const { title, description, pubDate, updatedDate, heroImage } = Astro.props;
|
||||
const { title, description, pubDate, updatedDate, heroImage, id } = Astro.props;
|
||||
---
|
||||
|
||||
<Base title={title} description={description}>
|
||||
@@ -17,13 +17,29 @@ const { title, description, pubDate, updatedDate, heroImage } = Astro.props;
|
||||
<div class="text-sm mb-2" style="color: var(--text-4)">
|
||||
<FormattedDate date={pubDate} />
|
||||
{updatedDate && (
|
||||
<span class="italic"> · Updated <FormattedDate date={updatedDate} /></span>
|
||||
<span class="italic"> · Aggiornato <FormattedDate date={updatedDate} /></span>
|
||||
)}
|
||||
</div>
|
||||
<div class="flex items-start justify-between gap-4">
|
||||
<h1 class="text-3xl font-bold" style="color: var(--text-primary)">{title}</h1>
|
||||
{id && (
|
||||
<button
|
||||
data-slug={id}
|
||||
id="edit-post-btn"
|
||||
class="shrink-0 text-xs text-zinc-500 hover:text-white transition-colors px-2 py-1 rounded border border-zinc-700 hover:border-zinc-500 mt-1"
|
||||
>Modifica</button>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
<div class="prose-wiki">
|
||||
<slot />
|
||||
</div>
|
||||
</article>
|
||||
</Base>
|
||||
|
||||
<script>
|
||||
document.getElementById('edit-post-btn')?.addEventListener('click', (e) => {
|
||||
const slug = (e.currentTarget as HTMLElement).dataset.slug;
|
||||
window.dispatchEvent(new CustomEvent('open-editor', { detail: { slug, apiBase: '/stories' } }));
|
||||
});
|
||||
</script>
|
||||
|
||||
+19
-3
@@ -4,15 +4,24 @@ import Base from './Base.astro';
|
||||
import BreadCrumbs from '../components/BreadCrumbs.astro';
|
||||
import BackRefs from '../components/BackRefs.astro';
|
||||
|
||||
type Props = CollectionEntry<'entries'>['data'];
|
||||
type Props = CollectionEntry<'entries'>['data'] & { id?: string };
|
||||
|
||||
const { title, frontmatter } = Astro.props;
|
||||
const { title, frontmatter, id } = Astro.props;
|
||||
---
|
||||
|
||||
<Base title={title}>
|
||||
<article class="max-w-3xl mx-auto">
|
||||
<div class="mb-6 pb-4 border-b" style="border-color: var(--border)">
|
||||
<h1 class="text-3xl font-bold mb-2" style="color: var(--text-primary)">{title}</h1>
|
||||
<div class="flex items-start justify-between gap-4">
|
||||
<h1 class="text-3xl font-bold" style="color: var(--text-primary)">{title}</h1>
|
||||
{id && (
|
||||
<button
|
||||
data-slug={id}
|
||||
class="shrink-0 text-xs text-zinc-500 hover:text-white transition-colors px-2 py-1 rounded border border-zinc-700 hover:border-zinc-500 mt-1"
|
||||
id="edit-entry-btn"
|
||||
>Modifica</button>
|
||||
)}
|
||||
</div>
|
||||
<BreadCrumbs current={frontmatter.fname} />
|
||||
</div>
|
||||
<div class="prose-wiki">
|
||||
@@ -23,3 +32,10 @@ const { title, frontmatter } = Astro.props;
|
||||
</div>
|
||||
</article>
|
||||
</Base>
|
||||
|
||||
<script>
|
||||
document.getElementById('edit-entry-btn')?.addEventListener('click', (e) => {
|
||||
const slug = (e.currentTarget as HTMLElement).dataset.slug;
|
||||
window.dispatchEvent(new CustomEvent('open-editor', { detail: { slug, apiBase: '/pages' } }));
|
||||
});
|
||||
</script>
|
||||
|
||||
@@ -15,6 +15,6 @@ const post = Astro.props;
|
||||
const { Content } = await render(post);
|
||||
---
|
||||
|
||||
<BlogPost {...post.data}>
|
||||
<BlogPost {...post.data} id={post.id}>
|
||||
<Content />
|
||||
</BlogPost>
|
||||
|
||||
@@ -4,16 +4,22 @@ import { SITE_TITLE, SITE_DESCRIPTION } from '../../consts';
|
||||
import { getCollection } from 'astro:content';
|
||||
import FormattedDate from '../../components/FormattedDate.astro';
|
||||
|
||||
const posts = (await getCollection('blog')).sort(
|
||||
(a, b) => b.data.pubDate.valueOf() - a.data.pubDate.valueOf()
|
||||
);
|
||||
const posts = (await getCollection('blog'))
|
||||
.filter(p => !p.id.startsWith('_'))
|
||||
.sort((a, b) => b.data.pubDate.valueOf() - a.data.pubDate.valueOf());
|
||||
---
|
||||
|
||||
<Base title={`Blog — ${SITE_TITLE}`} description={SITE_DESCRIPTION}>
|
||||
<Base title={`Storie — ${SITE_TITLE}`} description={SITE_DESCRIPTION}>
|
||||
<div class="max-w-3xl mx-auto">
|
||||
<h1 class="text-3xl font-bold mb-6" style="color: var(--text-primary)">Blog</h1>
|
||||
<div class="flex items-center justify-between mb-6">
|
||||
<h1 class="text-3xl font-bold" style="color: var(--text-primary)">Storie</h1>
|
||||
<button
|
||||
id="new-story-btn"
|
||||
class="text-xs text-zinc-400 hover:text-white transition-colors px-2 py-1 rounded border border-zinc-700 hover:border-zinc-500"
|
||||
>+ Nuova storia</button>
|
||||
</div>
|
||||
{posts.length === 0 && (
|
||||
<p style="color: var(--text-4)">No posts yet.</p>
|
||||
<p style="color: var(--text-4)">Nessuna storia ancora.</p>
|
||||
)}
|
||||
<ul class="space-y-4">
|
||||
{posts.map(post => (
|
||||
@@ -43,3 +49,9 @@ const posts = (await getCollection('blog')).sort(
|
||||
</ul>
|
||||
</div>
|
||||
</Base>
|
||||
|
||||
<script>
|
||||
document.getElementById('new-story-btn')?.addEventListener('click', () => {
|
||||
window.dispatchEvent(new CustomEvent('open-editor', { detail: { apiBase: '/stories' } }));
|
||||
});
|
||||
</script>
|
||||
|
||||
@@ -16,6 +16,6 @@ const { Content, remarkPluginFrontmatter } = await render(entry);
|
||||
entry.data.frontmatter = remarkPluginFrontmatter;
|
||||
---
|
||||
|
||||
<Entry {...entry.data}>
|
||||
<Entry {...entry.data} id={entry.id}>
|
||||
<Content />
|
||||
</Entry>
|
||||
|
||||
@@ -3,19 +3,34 @@ import Base from '../../layouts/Base.astro';
|
||||
import { SITE_TITLE, SITE_DESCRIPTION } from '../../consts';
|
||||
import { getCollection } from 'astro:content';
|
||||
|
||||
const entries = (await getCollection('entries'))
|
||||
const allEntries = await getCollection('entries');
|
||||
|
||||
const wikiEntries = allEntries
|
||||
.filter(e => !e.id.startsWith('_'))
|
||||
.sort((a, b) => (b.data.updatedDate ?? b.data.pubDate ?? new Date(0)).valueOf()
|
||||
- (a.data.updatedDate ?? a.data.pubDate ?? new Date(0)).valueOf());
|
||||
|
||||
const docEntries = allEntries
|
||||
.filter(e => e.id.startsWith('_docs/'))
|
||||
.sort((a, b) => a.data.title.localeCompare(b.data.title));
|
||||
---
|
||||
|
||||
<Base title={`Pages — ${SITE_TITLE}`} description={SITE_DESCRIPTION}>
|
||||
<Base title={`Pagine — ${SITE_TITLE}`} description={SITE_DESCRIPTION}>
|
||||
<div class="max-w-3xl mx-auto">
|
||||
<h1 class="text-3xl font-bold mb-6" style="color: var(--text-primary)">All Pages</h1>
|
||||
{entries.length === 0 && (
|
||||
<p style="color: var(--text-4)">No pages yet.</p>
|
||||
)}
|
||||
<div class="flex items-center justify-between mb-8">
|
||||
<h1 class="text-3xl font-bold" style="color: var(--text-primary)">Tutte le pagine</h1>
|
||||
<button
|
||||
id="new-page-btn"
|
||||
class="text-xs text-zinc-400 hover:text-white transition-colors px-2 py-1 rounded border border-zinc-700 hover:border-zinc-500"
|
||||
>+ Nuova pagina</button>
|
||||
</div>
|
||||
|
||||
{wikiEntries.length === 0 ? (
|
||||
<p style="color: var(--text-4)" class="text-sm italic mb-10">Nessuna pagina ancora.</p>
|
||||
) : (
|
||||
<section class="mb-10">
|
||||
<ul class="space-y-2">
|
||||
{entries.map(entry => (
|
||||
{wikiEntries.map(entry => (
|
||||
<li>
|
||||
<a
|
||||
href={`/entries/${entry.id}/`}
|
||||
@@ -29,5 +44,35 @@ const entries = (await getCollection('entries'))
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</section>
|
||||
)}
|
||||
|
||||
{docEntries.length > 0 && (
|
||||
<section>
|
||||
<h2 class="text-lg font-semibold mb-1" style="color: var(--text-2)">Documentazione</h2>
|
||||
<p class="text-xs mb-4" style="color: var(--text-5)">Come funziona questo wiki</p>
|
||||
<ul class="space-y-2">
|
||||
{docEntries.map(entry => (
|
||||
<li>
|
||||
<a
|
||||
href={`/entries/${entry.id}/`}
|
||||
class="flex items-center gap-2 px-3 py-2 rounded-lg hover:bg-zinc-800 transition-colors group"
|
||||
style="background: var(--bg-card)"
|
||||
>
|
||||
<span class="text-sm font-medium group-hover:text-white transition-colors" style="color: var(--text-4)">
|
||||
{entry.data.title}
|
||||
</span>
|
||||
</a>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</section>
|
||||
)}
|
||||
</div>
|
||||
</Base>
|
||||
|
||||
<script>
|
||||
document.getElementById('new-page-btn')?.addEventListener('click', () => {
|
||||
window.dispatchEvent(new CustomEvent('open-editor', { detail: {} }));
|
||||
});
|
||||
</script>
|
||||
|
||||
+40
-7
@@ -3,10 +3,17 @@ import Base from '../layouts/Base.astro';
|
||||
import { SITE_TITLE, SITE_DESCRIPTION } from '../consts';
|
||||
import { getCollection } from 'astro:content';
|
||||
|
||||
const entries = (await getCollection('entries'))
|
||||
const allEntries = await getCollection('entries');
|
||||
|
||||
const wikiEntries = allEntries
|
||||
.filter(e => !e.id.startsWith('_'))
|
||||
.sort((a, b) => (b.data.updatedDate ?? b.data.pubDate ?? new Date(0)).valueOf()
|
||||
- (a.data.updatedDate ?? a.data.pubDate ?? new Date(0)).valueOf())
|
||||
.slice(0, 10);
|
||||
|
||||
const docEntries = allEntries
|
||||
.filter(e => e.id.startsWith('_docs/'))
|
||||
.sort((a, b) => a.data.title.localeCompare(b.data.title));
|
||||
---
|
||||
|
||||
<Base title={SITE_TITLE} description={SITE_DESCRIPTION}>
|
||||
@@ -15,14 +22,14 @@ const entries = (await getCollection('entries'))
|
||||
<h1 class="text-3xl font-bold mb-2" style="color: var(--text-primary)">
|
||||
Bincio<span style="color: var(--accent)">Wiki</span>
|
||||
</h1>
|
||||
<p style="color: var(--text-4)">The collective memory of the Bincio group.</p>
|
||||
<p style="color: var(--text-4)">La memoria collettiva del gruppo Bincio.</p>
|
||||
</div>
|
||||
|
||||
{entries.length > 0 && (
|
||||
<section>
|
||||
<h2 class="text-lg font-semibold mb-4" style="color: var(--text-2)">Recent pages</h2>
|
||||
{wikiEntries.length > 0 ? (
|
||||
<section class="mb-10">
|
||||
<h2 class="text-lg font-semibold mb-4" style="color: var(--text-2)">Pagine recenti</h2>
|
||||
<ul class="space-y-2">
|
||||
{entries.map(entry => (
|
||||
{wikiEntries.map(entry => (
|
||||
<li>
|
||||
<a
|
||||
href={`/entries/${entry.id}/`}
|
||||
@@ -37,9 +44,35 @@ const entries = (await getCollection('entries'))
|
||||
))}
|
||||
</ul>
|
||||
<p class="mt-4 text-sm">
|
||||
<a href="/entries" style="color: var(--accent)" class="hover:opacity-80 transition-opacity">All pages →</a>
|
||||
<a href="/entries" style="color: var(--accent)" class="hover:opacity-80 transition-opacity">Tutte le pagine →</a>
|
||||
</p>
|
||||
</section>
|
||||
) : (
|
||||
<section class="mb-10">
|
||||
<p style="color: var(--text-4)" class="text-sm italic">Nessuna pagina ancora.</p>
|
||||
</section>
|
||||
)}
|
||||
|
||||
{docEntries.length > 0 && (
|
||||
<section>
|
||||
<h2 class="text-lg font-semibold mb-1" style="color: var(--text-2)">Documentazione</h2>
|
||||
<p class="text-xs mb-4" style="color: var(--text-5)">Come funziona questo wiki</p>
|
||||
<ul class="space-y-2">
|
||||
{docEntries.map(entry => (
|
||||
<li>
|
||||
<a
|
||||
href={`/entries/${entry.id}/`}
|
||||
class="flex items-center gap-2 px-3 py-2 rounded-lg hover:bg-zinc-800 transition-colors group"
|
||||
style="background: var(--bg-card)"
|
||||
>
|
||||
<span class="text-sm font-medium group-hover:text-white transition-colors" style="color: var(--text-4)">
|
||||
{entry.data.title}
|
||||
</span>
|
||||
</a>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</section>
|
||||
)}
|
||||
</div>
|
||||
</Base>
|
||||
|
||||
@@ -0,0 +1,96 @@
|
||||
---
|
||||
import Base from '../../layouts/Base.astro';
|
||||
---
|
||||
|
||||
<Base title="Accedi — BincioWiki" public={true}>
|
||||
<div class="max-w-sm mx-auto mt-16">
|
||||
<h1 class="text-2xl font-bold mb-8 text-center" style="color: var(--text-primary)">
|
||||
Bincio<span style="color: var(--accent)">Wiki</span>
|
||||
</h1>
|
||||
|
||||
<form id="login-form" class="flex flex-col gap-4">
|
||||
<div id="error-msg" class="hidden text-sm px-3 py-2 rounded bg-red-900/40 text-red-300 border border-red-800"></div>
|
||||
|
||||
<div class="flex flex-col gap-1">
|
||||
<label class="text-sm" style="color: var(--text-4)">Handle</label>
|
||||
<input
|
||||
id="handle"
|
||||
name="handle"
|
||||
type="text"
|
||||
autocomplete="username"
|
||||
autocapitalize="none"
|
||||
required
|
||||
class="px-3 py-2 rounded border text-sm bg-zinc-900 border-zinc-700 focus:outline-none focus:border-zinc-500"
|
||||
style="color: var(--text-primary)"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="flex flex-col gap-1">
|
||||
<label class="text-sm" style="color: var(--text-4)">Password</label>
|
||||
<input
|
||||
id="password"
|
||||
name="password"
|
||||
type="password"
|
||||
autocomplete="current-password"
|
||||
required
|
||||
class="px-3 py-2 rounded border text-sm bg-zinc-900 border-zinc-700 focus:outline-none focus:border-zinc-500"
|
||||
style="color: var(--text-primary)"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<button
|
||||
type="submit"
|
||||
id="submit-btn"
|
||||
class="mt-2 px-4 py-2 rounded text-sm font-medium transition-colors"
|
||||
style="background: var(--accent); color: #000"
|
||||
>
|
||||
Accedi
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
</Base>
|
||||
|
||||
<script>
|
||||
const form = document.getElementById('login-form') as HTMLFormElement;
|
||||
const errorMsg = document.getElementById('error-msg') as HTMLDivElement;
|
||||
const submitBtn = document.getElementById('submit-btn') as HTMLButtonElement;
|
||||
|
||||
// If already logged in, go home
|
||||
fetch('/api/me', { credentials: 'include' })
|
||||
.then(r => { if (r.ok) window.location.replace('/'); })
|
||||
.catch(() => {});
|
||||
|
||||
form.addEventListener('submit', async (e) => {
|
||||
e.preventDefault();
|
||||
errorMsg.classList.add('hidden');
|
||||
submitBtn.disabled = true;
|
||||
submitBtn.textContent = 'Accesso in corso…';
|
||||
|
||||
const handle = (document.getElementById('handle') as HTMLInputElement).value.trim();
|
||||
const password = (document.getElementById('password') as HTMLInputElement).value;
|
||||
|
||||
try {
|
||||
const res = await fetch('/api/auth/login', {
|
||||
method: 'POST',
|
||||
credentials: 'include',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ handle, password }),
|
||||
});
|
||||
|
||||
if (res.ok) {
|
||||
const params = new URLSearchParams(window.location.search);
|
||||
window.location.replace(params.get('next') || '/');
|
||||
} else {
|
||||
const data = await res.json().catch(() => ({}));
|
||||
errorMsg.textContent = data.detail || 'Credenziali non valide';
|
||||
errorMsg.classList.remove('hidden');
|
||||
}
|
||||
} catch {
|
||||
errorMsg.textContent = 'Errore di rete. Riprova.';
|
||||
errorMsg.classList.remove('hidden');
|
||||
} finally {
|
||||
submitBtn.disabled = false;
|
||||
submitBtn.textContent = 'Accedi';
|
||||
}
|
||||
});
|
||||
</script>
|
||||
Reference in New Issue
Block a user