mirror of
https://github.com/litruv/lit.ruv.wtf.git
synced 2026-07-24 02:36:02 +10:00
feat: enhance blog layout with footer and improved navigation; add SVG icons for GitHub and Bluesky
This commit is contained in:
@@ -247,14 +247,17 @@ class StaticBlogGenerator {
|
|||||||
'</head>',
|
'</head>',
|
||||||
'<body class="blog-page">',
|
'<body class="blog-page">',
|
||||||
'<nav class="quick-links" aria-label="Primary">',
|
'<nav class="quick-links" aria-label="Primary">',
|
||||||
|
' <div class="quick-links-inner">',
|
||||||
this.renderHeaderLinks(),
|
this.renderHeaderLinks(),
|
||||||
' <a class="quick-link rss-link" href="/rss.xml" aria-label="RSS feed" title="RSS feed">',
|
' <a class="quick-link rss-link" href="/rss.xml" aria-label="RSS feed" title="RSS feed">',
|
||||||
' <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="currentColor" aria-hidden="true"><path d="M6.18 15.64a2.18 2.18 0 0 1 2.18 2.18C8.36 19.01 7.38 20 6.18 20C4.98 20 4 19.01 4 17.82a2.18 2.18 0 0 1 2.18-2.18M4 4.44A15.56 15.56 0 0 1 19.56 20h-2.83A12.73 12.73 0 0 0 4 7.27V4.44m0 5.66a9.9 9.9 0 0 1 9.9 9.9h-2.83A7.07 7.07 0 0 0 4 12.93V10.1z"/></svg>',
|
' <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="currentColor" aria-hidden="true"><path d="M6.18 15.64a2.18 2.18 0 0 1 2.18 2.18C8.36 19.01 7.38 20 6.18 20C4.98 20 4 19.01 4 17.82a2.18 2.18 0 0 1 2.18-2.18M4 4.44A15.56 15.56 0 0 1 19.56 20h-2.83A12.73 12.73 0 0 0 4 7.27V4.44m0 5.66a9.9 9.9 0 0 1 9.9 9.9h-2.83A7.07 7.07 0 0 0 4 12.93V10.1z"/></svg>',
|
||||||
' RSS',
|
' RSS',
|
||||||
' </a>',
|
' </a>',
|
||||||
|
' </div>',
|
||||||
'</nav>',
|
'</nav>',
|
||||||
this.renderScrollTopBar(),
|
this.renderScrollTopBar(),
|
||||||
bodyHtml,
|
bodyHtml,
|
||||||
|
this.renderFooter(),
|
||||||
' <script type="module" src="/scripts/blogPage.js"></script>',
|
' <script type="module" src="/scripts/blogPage.js"></script>',
|
||||||
'</body>',
|
'</body>',
|
||||||
'</html>'
|
'</html>'
|
||||||
@@ -274,16 +277,37 @@ class StaticBlogGenerator {
|
|||||||
renderScrollTopBar() {
|
renderScrollTopBar() {
|
||||||
return [
|
return [
|
||||||
'<header class="blog-scroll-topbar" data-blog-scroll-topbar>',
|
'<header class="blog-scroll-topbar" data-blog-scroll-topbar>',
|
||||||
' <a class="blog-scroll-logo-link" href="/" aria-label="Back to main site">',
|
' <div class="blog-scroll-topbar-inner">',
|
||||||
' <img src="/logos/LogoFull.svg" alt="lit.ruv.wtf" class="blog-scroll-logo" />',
|
' <a class="blog-scroll-logo-link" href="/" aria-label="Back to main site">',
|
||||||
' </a>',
|
' <img src="/logos/LogoFull.svg" alt="lit.ruv.wtf" class="blog-scroll-logo" />',
|
||||||
' <nav class="blog-scroll-links" aria-label="Scrolled navigation">',
|
' </a>',
|
||||||
|
' <nav class="blog-scroll-links" aria-label="Scrolled navigation">',
|
||||||
this.renderHeaderLinks(),
|
this.renderHeaderLinks(),
|
||||||
' </nav>',
|
' </nav>',
|
||||||
|
' </div>',
|
||||||
'</header>'
|
'</header>'
|
||||||
].join('\n');
|
].join('\n');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @returns {string}
|
||||||
|
*/
|
||||||
|
renderFooter() {
|
||||||
|
return [
|
||||||
|
'<footer class="blog-footer">',
|
||||||
|
' <div class="blog-footer-inner">',
|
||||||
|
' <a href="/" class="blog-footer-logo" aria-label="Back to main site">',
|
||||||
|
' <img src="/logos/LogoFull.svg" alt="lit.ruv.wtf" class="blog-footer-logo-img" />',
|
||||||
|
' </a>',
|
||||||
|
' <div class="blog-footer-links">',
|
||||||
|
this.renderHeaderLinks(),
|
||||||
|
' </div>',
|
||||||
|
` <p class="blog-footer-copy">© ${new Date().getFullYear()} lit.ruv.wtf</p>`,
|
||||||
|
' </div>',
|
||||||
|
'</footer>',
|
||||||
|
].join('\n');
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @returns {string}
|
* @returns {string}
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -1,10 +1,14 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
|
const GITHUB_SVG = '<svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24" fill="currentColor" aria-hidden="true"><path d="M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12"/></svg>';
|
||||||
|
const BLUESKY_SVG = '<svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24" fill="currentColor" aria-hidden="true"><path d="M5.202 2.857C7.954 4.922 10.913 9.11 12 11.358c1.087-2.247 4.046-6.436 6.798-8.501C20.783 1.366 24 .213 24 3.883c0 .732-.42 6.156-.667 7.037-.856 3.061-3.978 3.842-6.755 3.37 4.854.826 6.089 3.562 3.422 6.299-5.065 5.196-7.28-1.304-7.847-2.97-.104-.305-.152-.448-.153-.327 0-.121-.05.022-.153.327-.568 1.666-2.782 8.166-7.847 2.97-2.667-2.737-1.432-5.473 3.422-6.3-2.777.473-5.899-.308-6.755-3.369C.42 10.04 0 4.615 0 3.883c0-3.67 3.217-2.517 5.202-1.026"/></svg>';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @typedef {Object} NavLink
|
* @typedef {Object} NavLink
|
||||||
* @property {string} label
|
* @property {string} label
|
||||||
* @property {string} href
|
* @property {string} href
|
||||||
* @property {boolean} [external]
|
* @property {boolean} [external]
|
||||||
|
* @property {string} [svg] - Inline SVG string shown instead of label text.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/** @type {NavLink[]} */
|
/** @type {NavLink[]} */
|
||||||
@@ -12,9 +16,9 @@ const NAV_LINKS = [
|
|||||||
{ label: 'home', href: '/' },
|
{ label: 'home', href: '/' },
|
||||||
{ label: 'blog', href: '/blog.html' },
|
{ label: 'blog', href: '/blog.html' },
|
||||||
{ label: 'docs', href: '/docs/' },
|
{ label: 'docs', href: '/docs/' },
|
||||||
{ label: 'github', href: 'https://github.com/litruv', external: true },
|
|
||||||
{ label: 'bluesky', href: 'https://bsky.app/profile/lit.mates.dev', external: true },
|
|
||||||
{ label: 'materials', href: '/materials' },
|
{ label: 'materials', href: '/materials' },
|
||||||
|
{ label: 'GitHub', href: 'https://github.com/litruv', external: true, svg: GITHUB_SVG },
|
||||||
|
{ label: 'Bluesky', href: 'https://bsky.app/profile/lit.mates.dev', external: true, svg: BLUESKY_SVG },
|
||||||
];
|
];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -24,9 +28,11 @@ const NAV_LINKS = [
|
|||||||
* @returns {string}
|
* @returns {string}
|
||||||
*/
|
*/
|
||||||
function renderNavLinkItems(indent = ' ') {
|
function renderNavLinkItems(indent = ' ') {
|
||||||
return NAV_LINKS.map(({ label, href, external }) => {
|
return NAV_LINKS.map(({ label, href, external, svg }) => {
|
||||||
const attrs = external ? ' target="_blank" rel="noopener"' : '';
|
const attrs = external ? ' target="_blank" rel="noopener"' : '';
|
||||||
return `${indent}<a href="${href}"${attrs} class="quick-link">${label}</a>`;
|
const content = svg ? svg : label;
|
||||||
|
const extraClass = svg ? ' quick-link--icon' : '';
|
||||||
|
return `${indent}<a href="${href}"${attrs} class="quick-link${extraClass}" aria-label="${label}"${svg ? ` title="${label}"` : ''}>${content}</a>`;
|
||||||
}).join('\n');
|
}).join('\n');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,46 +0,0 @@
|
|||||||
[
|
|
||||||
{
|
|
||||||
"slug": "markdown-test",
|
|
||||||
"title": "Markdown Formatting Test",
|
|
||||||
"date": "2026-09-11",
|
|
||||||
"author": "Test Author",
|
|
||||||
"tags": [
|
|
||||||
"test",
|
|
||||||
"formatting",
|
|
||||||
"markdown"
|
|
||||||
],
|
|
||||||
"content": "# Heading 1 test 123\n\n## Heading 2\n\n### Heading 3\n\n#### Heading 4\n\n##### Heading 5\n\n###### Heading 6\n\n## Text Formatting\n\nThis is **bold text** and this is *italic text* and this is ***bold italic text***.\n\nHere's some `inline code` in a sentence.\n\n## Links\n\nHere's a [regular link](https://example.com) and here's a [YouTube link](https://youtube.com/watch?v=test).\n\n## Lists\n\nUnordered list:\n\n* First item\n\n* Second item\n\n* Third item\n\nOrdered list:\n\n1. First step\n2. Second step\n3. Third step\n\n## Code Blocks\n\nStandard JavaScript:\n\n```javascript\nconst hello = \"world\";\nconsole.log(hello);\n\nfunction test() {\n return true;\n}\n```\n\nPython with syntax highlighting:\n\n```python\ndef hello_world():\n print(\"Hello, World!\")\n return True\n```\n\nCode with max height (200px):\n\n```javascript\n// This is a long code block that will scroll\nconst data = [1, 2, 3, 4, 5];\n\nfunction processData(arr) {\n return arr.map(x => x * 2);\n}\n\nconsole.log(processData(data));\n\n// Adding more lines to demonstrate scrolling\nfor (let i = 0; i < 10; i++) {\n console.log(`Iteration ${i}`);\n}\n\n// Even more content\nconst obj = {\n name: \"Test\",\n value: 42,\n nested: {\n deep: true\n }\n};\n```\n\n## Blockquotes\n\n> This is a blockquote.\n> It can span multiple lines.\n> And continues here.\n\n## Horizontal Rule\n\n***\n\n## Images\n\n\n\n\n\n## Mixed Content\n\n<br />\n\nYou can mix **bold**, *italic*, and `code` in the same paragraph. Here's a [link with](https://example.com) **[bold](https://example.com)** [text](https://example.com) too.\n\n### Nested Lists\n\n* Top level itemsss\n\n* Another top level\n\n * Nested item (if supported)\n\n * Another nested\n\n1. Numbered item\n2. Another numbered\n\n * Mixed with bullets\n\n * More bullets\n\n## Special Characters\n\nTesting special chars: < > & \" '\n\n## Long Paragraph\n\nLorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.\n\nDuis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.\n"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"slug": "testddd",
|
|
||||||
"title": "test d d d d",
|
|
||||||
"date": "2026-05-10",
|
|
||||||
"author": "it me",
|
|
||||||
"tags": [],
|
|
||||||
"content": "asdffdsaasdffdsa\n\n| <br /> | <br /> | <br /> | <br /> |\n| :----- | :----- | :----- | -----: |\n| <br /> | <br /> | <br /> | <br /> |\n| <br /> | <br /> | <br /> | <br /> |\n\n<br />\n\nthis is a test post, should't publish i guess, but who's reading lmao\n"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"slug": "welcome",
|
|
||||||
"title": "Welcome to My Blog",
|
|
||||||
"date": "2026-05-10",
|
|
||||||
"author": "Max Litruv Boonzaayer",
|
|
||||||
"tags": [
|
|
||||||
"welcome",
|
|
||||||
"meta",
|
|
||||||
"introduction"
|
|
||||||
],
|
|
||||||
"content": "# Welcome to My Blog\n\nThis is my first blog post! I'm excited to share my thoughts and experiences with you.\n\n## What This Blog Is About\n\nThis blog is built using a **custom node-based graph system** where each blog post is represented as a node in an interactive visual graph. Pretty cool, right?\n\n### Features\n\n* 📝 Markdown support with YAML front matter\n\n* 📅 Date-based organization\n\n* 🏷️ Tag system for categorization\n\n* 🎨 Interactive node-based visualization\n\n* 📁 Media support in `data/blog/media/`\n\n## Technical Details\n\nThe build system automatically:\n\n1. Scans the `data/blog/` directory for `.md` files\n2. Parses YAML front matter for metadata\n3. Generates a `blogs.json` file\n4. Makes posts available to the BlogPostNode\n\nYou can reference images like this:\n\n\n## Code Examples\n\nHere's some example code:\n\n```javascript\nconst greeting = \"Hello, World!\";\r\nconsole.log(greeting);\n```\n\n## Conclusion\n\nStay tuned for more posts! This is just the beginning of an exciting journey.\n"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"slug": "node-graphs",
|
|
||||||
"title": "Building Interactive Node Graphs",
|
|
||||||
"date": "2026-04-15",
|
|
||||||
"author": "Max Litruv Boonzaayer",
|
|
||||||
"tags": [
|
|
||||||
"javascript",
|
|
||||||
"graph-systems",
|
|
||||||
"tutorial"
|
|
||||||
],
|
|
||||||
"content": "\r\n# Building Interactive Node Graphs\r\n\r\nIn this post, I'll share some insights on building interactive node-based graph systems for the web.\r\n\r\n## Why Node Graphs?\r\n\r\nNode graphs are powerful visual programming tools that make complex logic easier to understand and manipulate:\r\n\r\n- **Visual Clarity**: See the flow of data and execution at a glance\r\n- **Modularity**: Each node is a self-contained unit\r\n- **Flexibility**: Easy to add new node types and behaviors\r\n\r\n## The Architecture\r\n\r\nThe system is built on several key classes:\r\n\r\n### NodeBase\r\nThe abstract base class that all nodes inherit from. It defines the blueprint interface:\r\n\r\n```javascript\r\nclass NodeBase {\r\n static NodeType = \"\";\r\n static BlueprintPure_GetDefaultPins() { }\r\n BlueprintNativeEvent_OnRender(article, graphNode, renderCtx) { }\r\n async BlueprintCallable_Execute(ctx) { }\r\n}\r\n```\r\n\r\n### Node Registry\r\nAutomatically registers node types and creates instances based on type strings.\r\n\r\n### Execution Context\r\nHandles the graph traversal and execution flow when nodes are triggered.\r\n\r\n## Creating Custom Nodes\r\n\r\nTo create a new node type:\r\n\r\n1. Extend `NodeBase`\r\n2. Set a unique `NodeType`\r\n3. Define pins with `BlueprintPure_GetDefaultPins()`\r\n4. Implement rendering in `BlueprintNativeEvent_OnRender()`\r\n5. Implement logic in `BlueprintCallable_Execute()`\r\n\r\nThat's the blueprint system in a nutshell!\r\n"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
5
website/icons/bluesky-black-icon.svg
Normal file
5
website/icons/bluesky-black-icon.svg
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||||
|
<svg width="100%" height="100%" viewBox="0 0 512 453" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" xmlns:serif="http://www.serif.com/" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2;">
|
||||||
|
<path d="M110.985,30.441C169.68,74.658 232.822,164.297 255.998,212.402C279.175,164.297 342.321,74.658 401.015,30.441C443.376,-1.455 512,-26.142 512,52.402C512,68.082 503.038,184.177 497.777,203.03C479.504,268.545 412.904,285.258 353.665,275.146C457.215,292.825 483.554,351.383 426.665,409.945C318.624,521.168 271.377,382.04 259.279,346.391C255.791,336.129 256.288,335.893 252.719,346.391C240.621,382.04 193.377,521.168 85.336,409.945C28.447,351.383 54.785,292.825 158.335,275.146C99.096,285.258 32.495,268.545 14.223,203.03C8.962,184.177 0,68.082 0,52.402C0,-26.142 68.633,-1.455 110.985,30.441ZM96.799,49.275C84.105,39.715 68.726,30.778 54.004,26.256C44.996,23.49 36.38,21.013 30.395,25.642C24.778,29.987 23.579,38.884 23.579,52.402C23.579,67.42 31.895,178.636 36.934,196.692L36.935,196.696C51.648,249.45 106.666,260.046 154.367,251.903C167.204,249.712 179.386,258.342 181.578,271.178C183.769,284.015 175.14,296.197 162.303,298.389C135.291,303 114.19,310.441 99.405,320.491C88.594,327.839 81.552,336.27 79.887,346.191C77.4,361.01 86.042,376.833 102.249,393.516C127.513,419.524 147.307,430.205 164.581,428.535C178.755,427.164 189.413,417.046 198.267,405.504C215.828,382.612 225.787,352.38 230.391,338.814L230.395,338.801C232.485,332.655 234.064,328.904 235.05,327.229L238.226,322.916L243.134,318.787L249.091,316.051L256.946,315.045L263.15,316.115L269.971,319.512L274.366,323.551L277.231,327.669C278.172,329.34 279.629,332.994 281.604,338.803L281.607,338.814C286.211,352.38 296.171,382.612 313.732,405.504C322.586,417.046 333.245,427.164 347.419,428.535C364.693,430.205 384.488,419.524 409.752,393.516C425.959,376.833 434.601,361.01 432.114,346.191C430.449,336.27 423.406,327.84 412.596,320.491C397.81,310.441 376.709,303 349.697,298.389C336.86,296.197 328.231,284.015 330.422,271.178C332.614,258.342 344.796,249.712 357.633,251.903C405.334,260.046 460.351,249.45 475.065,196.695L475.066,196.692C480.105,178.636 488.421,67.42 488.421,52.402C488.421,38.884 487.222,29.987 481.606,25.642C475.622,21.012 467.007,23.49 458,26.256C443.277,30.778 427.897,39.716 415.2,49.276C359.312,91.38 299.309,176.831 277.24,222.636C273.309,230.795 265.054,235.981 255.998,235.981C246.942,235.981 238.686,230.794 234.756,222.636C212.688,176.831 152.688,91.379 96.799,49.275Z"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 2.7 KiB |
4
website/icons/github-outline.svg
Normal file
4
website/icons/github-outline.svg
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?><!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools -->
|
||||||
|
<svg width="800px" height="800px" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path fill-rule="evenodd" clip-rule="evenodd" d="M12 2C6.475 2 2 6.475 2 12C2 16.425 4.8625 20.1625 8.8375 21.4875C9.3375 21.575 9.525 21.275 9.525 21.0125C9.525 20.775 9.5125 19.9875 9.5125 19.15C7 19.6125 6.35 18.5375 6.15 17.975C6.0375 17.6875 5.55 16.8 5.125 16.5625C4.775 16.375 4.275 15.9125 5.1125 15.9C5.9 15.8875 6.4625 16.625 6.65 16.925C7.55 18.4375 8.9875 18.0125 9.5625 17.75C9.65 17.1 9.9125 16.6625 10.2 16.4125C7.975 16.1625 5.65 15.3 5.65 11.475C5.65 10.3875 6.0375 9.4875 6.675 8.7875C6.575 8.5375 6.225 7.5125 6.775 6.1375C6.775 6.1375 7.6125 5.875 9.525 7.1625C10.325 6.9375 11.175 6.825 12.025 6.825C12.875 6.825 13.725 6.9375 14.525 7.1625C16.4375 5.8625 17.275 6.1375 17.275 6.1375C17.825 7.5125 17.475 8.5375 17.375 8.7875C18.0125 9.4875 18.4 10.375 18.4 11.475C18.4 15.3125 16.0625 16.1625 13.8375 16.4125C14.2 16.725 14.5125 17.325 14.5125 18.2625C14.5125 19.6 14.5 20.675 14.5 21.0125C14.5 21.275 14.6875 21.5875 15.1875 21.4875C17.1727 20.8173 18.8977 19.5415 20.1198 17.8395C21.3419 16.1376 21.9995 14.0953 22 12C22 6.475 17.525 2 12 2Z" stroke="#000000" stroke-linejoin="round"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 1.3 KiB |
@@ -73,26 +73,26 @@ function renderStaticBlogPost() {
|
|||||||
function setupScrollTopBar() {
|
function setupScrollTopBar() {
|
||||||
const body = document.body;
|
const body = document.body;
|
||||||
const bar = document.querySelector("[data-blog-scroll-topbar]");
|
const bar = document.querySelector("[data-blog-scroll-topbar]");
|
||||||
const heroLogo = document.querySelector(".blog-logo-link");
|
|
||||||
|
|
||||||
if (!bar) return;
|
if (!bar) return;
|
||||||
|
|
||||||
if (heroLogo && "IntersectionObserver" in window) {
|
let lastScrollTop = 0;
|
||||||
const observer = new IntersectionObserver(
|
|
||||||
([entry]) => {
|
const applyState = () => {
|
||||||
body.classList.toggle("blog-scrolled", !entry.isIntersecting);
|
const scrollTop = body.scrollTop;
|
||||||
},
|
const scrollingDown = scrollTop > lastScrollTop;
|
||||||
{ threshold: 0 }
|
lastScrollTop = scrollTop;
|
||||||
);
|
|
||||||
observer.observe(heroLogo);
|
if (scrollTop < 80) {
|
||||||
} else {
|
body.classList.remove("blog-scrolled");
|
||||||
// Fallback: fixed pixel threshold
|
} else if (scrollingDown) {
|
||||||
const applyState = () => {
|
body.classList.add("blog-scrolled");
|
||||||
body.classList.toggle("blog-scrolled", window.scrollY >= 80);
|
} else {
|
||||||
};
|
body.classList.remove("blog-scrolled");
|
||||||
window.addEventListener("scroll", applyState, { passive: true });
|
}
|
||||||
applyState();
|
};
|
||||||
}
|
body.addEventListener("scroll", applyState, { passive: true });
|
||||||
|
applyState();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -586,6 +586,18 @@ svg.world-image {
|
|||||||
color: rgba(205, 214, 244, 0.9);
|
color: rgba(205, 214, 244, 0.9);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.quick-link--icon {
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
opacity: 0.5;
|
||||||
|
transition: opacity 0.2s;
|
||||||
|
color: rgba(205, 214, 244, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.quick-link--icon:hover {
|
||||||
|
opacity: 0.9;
|
||||||
|
}
|
||||||
|
|
||||||
.rss-link {
|
.rss-link {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
@@ -637,17 +649,22 @@ body.blog-page {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.blog-page .quick-links {
|
.blog-page .quick-links {
|
||||||
position: fixed;
|
position: static;
|
||||||
top: 0;
|
|
||||||
left: 0;
|
|
||||||
right: 0;
|
|
||||||
width: 100%;
|
width: 100%;
|
||||||
min-height: 52px;
|
min-height: 52px;
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
padding: 0 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.blog-page .quick-links-inner {
|
||||||
|
width: 100%;
|
||||||
|
max-width: 900px;
|
||||||
|
margin: 0 auto;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
gap: 16px;
|
gap: 16px;
|
||||||
padding: 10px 16px;
|
padding: 10px 0;
|
||||||
z-index: 620;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.blog-scroll-topbar {
|
.blog-scroll-topbar {
|
||||||
@@ -658,8 +675,7 @@ body.blog-page {
|
|||||||
height: 44px;
|
height: 44px;
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
gap: 14px;
|
padding: 0 16px;
|
||||||
padding: 6px 14px;
|
|
||||||
background: var(--ctp-base);
|
background: var(--ctp-base);
|
||||||
border-bottom: 1px solid rgba(205, 214, 244, 0.15);
|
border-bottom: 1px solid rgba(205, 214, 244, 0.15);
|
||||||
box-shadow: 0 8px 20px rgba(0, 0, 0, 0.28);
|
box-shadow: 0 8px 20px rgba(0, 0, 0, 0.28);
|
||||||
@@ -670,6 +686,15 @@ body.blog-page {
|
|||||||
z-index: 700;
|
z-index: 700;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.blog-scroll-topbar-inner {
|
||||||
|
width: 100%;
|
||||||
|
max-width: 900px;
|
||||||
|
margin: 0 auto;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
.blog-scroll-logo-link {
|
.blog-scroll-logo-link {
|
||||||
display: inline-flex;
|
display: inline-flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
@@ -866,7 +891,54 @@ body.blog-page {
|
|||||||
position: relative;
|
position: relative;
|
||||||
}
|
}
|
||||||
|
|
||||||
@media (max-width: 1100px) {
|
/* ─── Blog Footer ─────────────────────────────────────────────────────────── */
|
||||||
|
|
||||||
|
.blog-footer {
|
||||||
|
width: 100%;
|
||||||
|
border-top: 1px solid rgba(205, 214, 244, 0.1);
|
||||||
|
margin-top: 48px;
|
||||||
|
padding: 32px 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.blog-footer-inner {
|
||||||
|
max-width: 900px;
|
||||||
|
margin: 0 auto;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
gap: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.blog-footer-logo {
|
||||||
|
opacity: 0.6;
|
||||||
|
transition: opacity 0.2s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.blog-footer-logo:hover {
|
||||||
|
opacity: 0.9;
|
||||||
|
}
|
||||||
|
|
||||||
|
.blog-footer-logo-img {
|
||||||
|
height: 28px;
|
||||||
|
width: auto;
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.blog-footer-links {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 20px;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.blog-footer-copy {
|
||||||
|
font-size: 12px;
|
||||||
|
color: rgba(205, 214, 244, 0.3);
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
.blog-post-peek {
|
.blog-post-peek {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user