From 8704b8f58f4123ce42ce031e5a453daf1f87e35e Mon Sep 17 00:00:00 2001 From: xihale Date: Tue, 20 Jan 2026 14:42:46 +0800 Subject: [PATCH 01/11] ui: implement site-wide redesign and layout restructuring --- assets/highlight.css | 150 ++--- assets/index.css | 6 +- assets/js/code-block.js | 43 ++ assets/js/toc.js | 71 ++ assets/style.css | 1073 ++++++++++++++++++++++++++----- content/learn/index.smd | 96 ++- content/monthly/202207.smd | 2 +- content/monthly/202208.smd | 2 +- content/monthly/202209.smd | 2 +- content/monthly/202210.smd | 2 +- content/monthly/202211.smd | 2 +- content/monthly/202212.smd | 2 +- content/monthly/202301.smd | 2 +- content/monthly/202302.smd | 2 +- content/monthly/202303.smd | 2 +- content/monthly/202304.smd | 2 +- content/monthly/202305.smd | 2 +- content/monthly/202306.smd | 2 +- content/monthly/202307.smd | 2 +- content/monthly/202308.smd | 2 +- content/monthly/202309.smd | 2 +- content/monthly/202310.smd | 2 +- content/monthly/202311.smd | 2 +- content/monthly/202402.smd | 2 +- content/monthly/202403.smd | 2 +- content/monthly/202404.smd | 2 +- content/monthly/202405.smd | 2 +- content/monthly/202406.smd | 2 +- content/monthly/202407.smd | 2 +- content/monthly/202410.smd | 2 +- content/monthly/202411.smd | 2 +- layouts/index.shtml | 3 +- layouts/learn.shtml | 2 +- layouts/monthly.shtml | 55 +- layouts/post.shtml | 63 +- layouts/templates/base.shtml | 32 +- layouts/templates/content.shtml | 31 +- 37 files changed, 1342 insertions(+), 333 deletions(-) create mode 100644 assets/js/code-block.js create mode 100644 assets/js/toc.js diff --git a/assets/highlight.css b/assets/highlight.css index b510ed7..8c14972 100644 --- a/assets/highlight.css +++ b/assets/highlight.css @@ -1,103 +1,79 @@ :root { - --code-fg: #BD976A; - --keyword: #4D9375; - --variable: #BD976A; - --comment: #758575DD; - --operator: #666666; - --string: #C98A7D; - --number: #4C9A91; - --function: #CB7676; - --bracket: #93aa9e; + /* Light Mode Syntax Tokens (GitHub Light inspired) */ + --hl-fg: #24292f; + --hl-keyword: #cf222e; /* Red */ + --hl-variable: #953800; /* Orange */ + --hl-comment: #6e7781; /* Gray */ + --hl-operator: #24292f; /* Dark Gray */ + --hl-string: #0a3069; /* Dark Blue */ + --hl-number: #0550ae; /* Blue */ + --hl-function: #8250df; /* Purple */ + --hl-bracket: #24292f; + --hl-constant: #0550ae; +} + +@media (prefers-color-scheme: dark) { + :root { + /* Dark Mode Syntax Tokens (GitHub Dark inspired) */ + --hl-fg: #c9d1d9; + --hl-keyword: #ff7b72; /* Coral */ + --hl-variable: #ffa657; /* Orange */ + --hl-comment: #8b949e; /* Gray */ + --hl-operator: #c9d1d9; /* Light Gray */ + --hl-string: #a5d6ff; /* Light Blue */ + --hl-number: #79c0ff; /* Blue */ + --hl-function: #d2a8ff; /* Purple */ + --hl-bracket: #c9d1d9; + --hl-constant: #79c0ff; + } } code { - color: var(--code-fg); + color: var(--hl-fg); } -code.zig, code.javascript, code.c, code.cpp, code.zon, code.go{ - color: var(--code-fg); - .keyword, .keyword_modifier, .type_builtin, .keyword_type, .keyword_return, .keyword_conditional, .keyword_repeat, .keyword_operator, .constant_builtin, .keyword_exception, .type{ - color: var(--keyword); - } - .variable, .function_builtin{ - color: var(--variable); - } - .comment{ - color: var(--comment); - } - .operator, .punctuation{ - color: var(--operator); - } - .string, .character{ - color: var(--string); - } - .number{ - color: var(--number); - } - .keyword_function, .punctuation_delimiter, .function{ - color: var(--function); - } - .punctuation_bracket{ - color: var(--bracket); - } +/* General Syntax Highlighting */ +.keyword, .keyword_modifier, .type_builtin, .keyword_type, .keyword_return, .keyword_conditional, .keyword_repeat, .keyword_operator, .keyword_exception, .type, .storage, .tag { + color: var(--hl-keyword); } -code.conf{ - color: var(--code-fg); - .function{ - color: var(--function); - } - .punctuation_bracket{ - color: var(--bracket); - } +.variable, .function_builtin, .attr-name { + color: var(--hl-variable); } -code.diff{ - color: var(--code-fg); - .addition, .string{ - color: #4D9375; - } - .deletion, .keyword{ - color: #CB7676; - } +.comment, .prolog, .doctype, .cdata { + color: var(--hl-comment); + font-style: italic; } -/* TODO 分词器太烂了 */ -code.bash { - color: var(--code-fg); - .comment { - color: var(--comment); - font-style: italic; - } - span.operator { - color: var(--operator); - } - .constant { - color: var(--number); - } - .string { - color: var(--string); - } - .function { - color: var(--function); - } +.operator, .punctuation, .punctuation_delimiter { + color: var(--hl-operator); } -code.json{ - color: var(--code-fg); - .constant_builtin{ - color: var(--keyword); - } - span.string_special_key{ - color: var(--string) - } - .string{ - color: var(--function) - } +.string, .character, .attr-value { + color: var(--hl-string); } -@media (prefers-color-scheme: light) { - code{ - filter: brightness(0.8) contrast(1.5); - } -} \ No newline at end of file +.number, .constant_builtin, .constant, .boolean { + color: var(--hl-number); +} + +.function, .keyword_function, .method { + color: var(--hl-function); +} + +.punctuation_bracket, .bracket { + color: var(--hl-bracket); +} + +/* Language Specific Overrides if needed */ +code.diff .addition { color: #1a7f37; } /* Green */ +code.diff .deletion { color: #cf222e; } /* Red */ + +@media (prefers-color-scheme: dark) { + code.diff .addition { color: #3fb950; } + code.diff .deletion { color: #ff7b72; } +} + +/* Bash specific adjustments */ +code.bash .constant { color: var(--hl-variable); } diff --git a/assets/index.css b/assets/index.css index 0450b32..2660efd 100644 --- a/assets/index.css +++ b/assets/index.css @@ -1,5 +1 @@ -.content{ - font-size: 1.2rem; - display: flex; - flex-direction: column; -} \ No newline at end of file +/* Deprecated: Styles moved to style.css */ diff --git a/assets/js/code-block.js b/assets/js/code-block.js new file mode 100644 index 0000000..ee700fc --- /dev/null +++ b/assets/js/code-block.js @@ -0,0 +1,43 @@ +document.addEventListener('DOMContentLoaded', () => { + const codeBlocks = document.querySelectorAll('pre code'); + + codeBlocks.forEach((code) => { + const preElement = code.parentNode; + if (preElement.tagName !== 'PRE') return; + + const codeContainer = document.createElement('div'); + codeContainer.className = 'code-block-container'; + preElement.parentNode.insertBefore(codeContainer, preElement); + codeContainer.appendChild(preElement); + + const copyButton = document.createElement('button'); + copyButton.className = 'copy-code-btn'; + copyButton.innerHTML = ''; + codeContainer.appendChild(copyButton); + + copyButton.addEventListener('click', () => { + const codeText = code.innerText; + navigator.clipboard.writeText(codeText).then(() => { + copyButton.classList.add('copied'); + setTimeout(() => { copyButton.classList.remove('copied'); }, 2000); + }); + }); + + const codeLines = code.innerHTML.split(/\r?\n/); + const hasTrailingEmptyLine = codeLines.length > 0 && codeLines[codeLines.length - 1].trim() === ''; + if (hasTrailingEmptyLine) { + codeLines.pop(); + } + + if (codeLines.length > 0) { + const lineNumbersContainer = document.createElement('div'); + lineNumbersContainer.className = 'line-numbers'; + for (let i = 1; i <= codeLines.length; i++) { + const lineNumber = document.createElement('span'); + lineNumber.innerText = i; + lineNumbersContainer.appendChild(lineNumber); + } + preElement.insertBefore(lineNumbersContainer, code); + } + }); +}); diff --git a/assets/js/toc.js b/assets/js/toc.js new file mode 100644 index 0000000..7dd9346 --- /dev/null +++ b/assets/js/toc.js @@ -0,0 +1,71 @@ +document.addEventListener('DOMContentLoaded', () => { + const tocLinks = document.querySelectorAll('.toc-sticky a'); + + // Find all headings within main-content + // We query all headings first, then filter/map to find the actual anchor ID + const rawHeadings = document.querySelectorAll('.main-content h1, .main-content h2, .main-content h3, .main-content h4, .main-content h5, .main-content h6'); + + const headings = []; + rawHeadings.forEach(h => { + let id = h.getAttribute('id'); + // If the heading itself doesn't have an ID, check if it contains an element with an ID (e.g. ) + // or if the Zine renderer placed the ID on a wrapper. + if (!id) { + const childWithId = h.querySelector('[id]'); + if (childWithId) { + id = childWithId.getAttribute('id'); + } + } + + if (id) { + headings.push({ element: h, id: id }); + } + }); + + if (tocLinks.length === 0 || headings.length === 0) return; + + const onScroll = () => { + let currentId = null; + const scrollPosition = window.scrollY + 120; // Offset for header + padding + + // Find the last heading that is above the current scroll position + for (const h of headings) { + if (h.element.offsetTop <= scrollPosition) { + currentId = h.id; + } else { + break; // Since headings are in order, we can stop + } + } + + if (currentId) { + tocLinks.forEach(link => { + link.classList.remove('active'); + // Decode URI component to handle non-ASCII IDs if any + const href = link.getAttribute('href'); + if (href === `#${currentId}`) { + link.classList.add('active'); + } + }); + } else { + // If no header is "current" (e.g. at very top), highlight the first one + if (window.scrollY < 100 && tocLinks.length > 0) { + tocLinks.forEach(link => link.classList.remove('active')); + tocLinks[0].classList.add('active'); + } + } + }; + + // Throttle scroll event slightly for performance + let ticking = false; + window.addEventListener('scroll', () => { + if (!ticking) { + window.requestAnimationFrame(() => { + onScroll(); + ticking = false; + }); + ticking = true; + } + }); + + onScroll(); // Initial check +}); diff --git a/assets/style.css b/assets/style.css index c5fa064..d1deced 100644 --- a/assets/style.css +++ b/assets/style.css @@ -1,278 +1,1019 @@ :root { - /* TODO */ - --bg: #fff; - --fg: #111; - --border: #aaa; - --link: #0070f3; + /* -- Design Tokens -- */ + + --bg-primary: #ffffff; + --bg-secondary: #f9fafb; + --text-primary: #030712; /* Darker black */ + --text-secondary: #374151; /* Darker gray */ + --text-tertiary: #6b7280; + + --border-subtle: #e5e7eb; + --border-strong: #d1d5db; + + --brand-primary: #0070f3; + --brand-accent: #f7a41d; + + --link: var(--brand-primary); + --link-hover: #0051a2; + + --code-bg: #f3f4f6; + --code-text: #111827; /* Darker code text */ + + --shadow-sm: 0 1px 2px 0 rgb(0 0 0 / 0.05); + --shadow-md: 0 4px 6px -1px rgb(0 0 0 / 0.1), 0 2px 4px -2px rgb(0 0 0 / 0.1); + + --font-sans: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol"; + --font-mono: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, "Liberation Mono", monospace; + + --spacing-unit: 8px; + --container-width: 900px; + --header-height: 64px; + --page-padding: 24px; } + @media (prefers-color-scheme: dark) { :root { - --bg: #181818; - --fg: #eee; - --border: #444; - --link: #4ea1ff; + --bg-primary: #0d1117; + --bg-secondary: #161b22; + --text-primary: #e6edf3; /* Lighter white */ + --text-secondary: #c9d1d9; /* Lighter gray */ + --text-tertiary: #8b949e; + + --border-subtle: #30363d; + --border-strong: #484f58; + + --brand-primary: #58a6ff; + --brand-accent: #f7a41d; + + --link: var(--brand-primary); + --link-hover: #79c0ff; + + --code-bg: #161b22; + --code-text: #e6edf3; /* Lighter code text */ + + --shadow-sm: 0 1px 2px 0 rgb(0 0 0 / 0.3); + --shadow-md: 0 4px 6px -1px rgb(0 0 0 / 0.3), 0 2px 4px -2px rgb(0 0 0 / 0.3); } } -.center{ +/* -- Reset & Base -- */ + +*, *::before, *::after { + box-sizing: border-box; +} + +html { + font-family: var(--font-sans); + font-size: 16px; + line-height: 1.6; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; + scroll-behavior: smooth; + scroll-padding-top: calc(var(--header-height) + 1rem); +} + +body { + margin: 0; + padding: 0; + background: var(--bg-primary); + color: var(--text-primary); display: flex; - justify-content: center; - align-items: center; + flex-direction: column; + min-height: 100vh; } -.large{ - font-size: 2rem; - line-height: 2; + +/* -- Typography -- */ + +h1, h2, h3, h4, h5, h6 { + margin-top: 2em; + margin-bottom: 1rem; + font-weight: 600; + line-height: 1.3; + color: var(--text-primary); + letter-spacing: -0.025em; } -.bold{ - font-weight: bold; + +h1 { + font-size: 2.25rem; + margin-top: 0; + margin-bottom: 0.5rem; } -body { - margin: 20px auto; - max-width: 60vw; - @media screen and (max-width: 800px) { - max-width: 93vw; - } - line-height: 1.7; - font-family: sans-serif; - background: var(--bg); - color: var(--fg); +h2 { font-size: 1.75rem; border-bottom: 1px solid var(--border-subtle); padding-bottom: 0.3rem; } +h3 { font-size: 1.5rem; } +h4 { font-size: 1.25rem; } + +p { + margin-bottom: 1.5rem; + line-height: 1.75; + color: var(--text-secondary); } a { - color: inherit; - line-break: anywhere; + color: var(--link); + text-decoration: none; + font-weight: 500; + transition: color 0.2s ease, text-decoration-color 0.2s ease; } -p:has(+ pre) { - margin-bottom: 0; +a:hover { + color: var(--link-hover); + text-decoration: underline; + text-decoration-thickness: 1.5px; + text-underline-offset: 3px; } -p + pre { - margin-top: 5px; +ul, ol { + padding-left: 1.5rem; + margin-bottom: 1.5rem; + line-height: 1.75; + color: var(--text-secondary); } -pre { - overflow: auto; - border-top: 2px solid var(--border); - border-bottom: 1px solid var(--border); - padding: 4px 0; - background: #8888880a; - line-height: 1.5; +li { + margin-bottom: 0.5rem; } -code { - font-family: monospace; - font-size: 14px; +/* -- Article List (Post/Monthly Index) -- */ + +.article-list { + list-style: none; + padding: 0; + margin: 2rem 0; } -.header { +.article-list li { + margin-bottom: 0.75rem; +} + +.article-item { display: flex; justify-content: space-between; align-items: baseline; - @media screen and (max-width: 800px) { - justify-content: center; + padding: 0.75rem 1rem; + border-radius: 6px; + background: var(--bg-secondary); + border: 1px solid var(--border-subtle); + text-decoration: none !important; + transition: all 0.2s ease; +} + +.article-item:hover { + border-color: var(--brand-primary); + transform: translateX(4px); + box-shadow: var(--shadow-sm); +} + +.article-title { + font-weight: 600; + color: var(--text-primary); + font-size: 1.05rem; +} + +.article-date { + font-size: 0.85rem; + color: var(--text-tertiary); + font-family: var(--font-mono); + margin-left: 1rem; + white-space: nowrap; +} + +.article-item:hover .article-title { + color: var(--brand-primary); +} + +@media screen and (max-width: 600px) { + .article-item { + flex-direction: column; + gap: 0.25rem; + } + + .article-date { + margin-left: 0; + font-size: 0.8rem; } } -.site-title { - display: inline-block; - text-decoration: none; - color: inherit; - @media screen and (max-width: 800px) { - display: none; + +/* -- Monthly Timeline -- */ + +.monthly-intro { + margin-bottom: 3rem; + font-size: 1.1rem; + color: var(--text-secondary); +} + +.monthly-timeline { + display: flex; + flex-direction: column; + gap: 0.5rem; + padding-left: 0; + margin-top: 2rem; +} + +.monthly-item { + display: flex; + justify-content: space-between; + align-items: baseline; + padding: 0.75rem 0; + border-bottom: 1px solid var(--border-subtle); + text-decoration: none !important; + transition: all 0.2s ease; +} + +.monthly-item:hover { + border-bottom-color: var(--brand-primary); +} + +.monthly-item:hover .monthly-item-title { + color: var(--brand-primary); +} + +.monthly-item-title { + font-size: 1.1rem; + color: var(--text-primary); + font-weight: 500; +} + +.monthly-item-meta { + display: flex; + align-items: center; + gap: 0.25rem; + font-family: var(--font-mono); + font-size: 0.95rem; + margin-left: 2rem; + white-space: nowrap; +} + +.monthly-date-part { + font-weight: 600; + color: var(--text-secondary); +} + +.monthly-sep { + opacity: 0.4; + color: var(--text-tertiary); + margin: 0 1px; +} + +@media screen and (max-width: 600px) { + .monthly-item { + flex-direction: column; + gap: 0.25rem; + padding: 1rem 0; + } + + .monthly-item-meta { + margin-left: 0; + font-size: 0.85rem; } } -table{ - border-collapse: collapse; +/* -- Learn Landing Page -- */ + +.learn-chapter-list { + display: grid; + grid-template-columns: repeat(auto-fill, minmax(300px, 1fr)); + gap: 1.5rem; + margin: 3rem 0; } -th, td { - border: 1px solid var(--border); - padding: 0.5rem; +.learn-item { + display: flex; + align-items: flex-start; + padding: 1.5rem; + background: var(--bg-secondary); + border: 1px solid var(--border-subtle); + border-radius: 12px; + text-decoration: none !important; + transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1); + height: 100%; } -blockquote { - border-left: 2px solid var(--border); - padding-left: 1rem; - margin-left: 1rem; - margin-right: 1rem; +.learn-item:hover { + border-color: var(--brand-primary); + transform: translateY(-4px); + box-shadow: var(--shadow-md); + background: var(--bg-primary); } -img { - max-width: 100%; +.learn-num { + font-family: var(--font-mono); + font-size: 2rem; + font-weight: 800; + color: var(--text-tertiary); + opacity: 0.2; + margin-right: 1.25rem; + line-height: 1; } -figcaption { - font-size: small; - text-align: center; +.learn-item:hover .learn-num { + color: var(--brand-primary); + opacity: 0.8; +} + +.learn-info { + display: flex; + flex-direction: column; +} + +.learn-title { + font-size: 1.25rem; + font-weight: 700; + color: var(--text-primary); + margin-bottom: 0.5rem; +} + +.learn-item:hover .learn-title { + color: var(--brand-primary); +} + +.learn-desc { + font-size: 0.9rem; + color: var(--text-secondary); + line-height: 1.5; +} + +/* -- Components -- */ + +.header { + position: sticky; + top: 0; + z-index: 100; + height: var(--header-height); + background: rgba(255, 255, 255, 0.85); + backdrop-filter: blur(12px); + -webkit-backdrop-filter: blur(12px); + border-bottom: 1px solid var(--border-subtle); + width: 100%; +} + +@media (prefers-color-scheme: dark) { + .header { + background: rgba(13, 17, 23, 0.85); + } +} + +.site-title h1 { + font-size: 1.25rem; + margin: 0; + border: none; + padding: 0; + font-weight: 700; + color: var(--text-primary); + letter-spacing: -0.01em; +} + +.site-title { + text-decoration: none !important; + color: var(--text-primary) !important; +} + +.site-title:hover { + color: var(--brand-accent) !important; } nav { - display: inline-block; + display: flex; + gap: 1.5rem; + align-items: center; } + nav a { - text-decoration: none; - font-size: large; - margin: 0 10px; - @media screen and (max-width: 800px) { - margin: 0 8px; + font-size: 0.95rem; + font-weight: 500; + color: var(--text-secondary); + text-decoration: none !important; + transition: color 0.2s ease; +} + +nav a:hover { + color: var(--brand-primary); +} + +.mobile-menu-toggle { + display: none; + flex-direction: column; + justify-content: center; + align-items: center; + width: 2rem; + height: 2rem; + background: transparent; + border: none; + cursor: pointer; + padding: 0.25rem; + border-radius: 0.25rem; + z-index: 50; + transition: background-color 0.2s; + margin-right: -0.5rem; +} + +.mobile-menu-toggle:hover { + background: var(--bg-secondary); +} + +.mobile-menu-line { + width: 1.25rem; + height: 2px; + background: var(--text-primary); + border-radius: 1px; + transition: all 0.3s; +} + +.mobile-menu-line:not(:last-child) { + margin-bottom: 0.25rem; +} + +.mobile-menu-toggle.active .mobile-menu-line:nth-child(1) { + transform: rotate(45deg) translate(0.375rem, 0.375rem); +} + +.mobile-menu-toggle.active .mobile-menu-line:nth-child(2) { + opacity: 0; + transform: scale(0); +} + +.mobile-menu-toggle.active .mobile-menu-line:nth-child(3) { + transform: rotate(-45deg) translate(0.375rem, -0.375rem); +} + +@media screen and (max-width: 600px) { + .mobile-menu-toggle { + display: flex; } } -nav a:first-child{ - margin-left: 0; + +.content-wrapper { + width: 100%; + max-width: var(--container-width); + margin: 0 auto; + padding: 2rem var(--page-padding); + flex: 1; + display: flex; + flex-direction: column; } -nav a:last-child{ - margin-right: 0; + +.container { + width: 100%; + max-width: var(--container-width); + margin: 0 auto; + padding: 0 var(--page-padding); } -footer > div { +.header-inner { display: flex; - flex-direction: row; + align-items: center; justify-content: space-between; - flex-wrap: wrap; + height: 100%; } -footer > div div { - margin: auto 0; +#search { + max-width: var(--container-width); + margin: 0 auto; + padding: 0 var(--page-padding); } -footer > div i { - font-size: 24px; - margin: 0 5px; +.main-content { + width: 100%; + min-width: 0; } -footer > div a { - text-decoration: none; +.main-content > h1:first-child { + margin-top: 0; } -footer > div img { - height: 1.5em; - width: auto; - vertical-align: middle; +/* Hide duplicate H1s that come from markdown content since the template already renders the title */ +.main-content div > h1:first-child, +.monthly-intro h1:first-child { + display: none; +} - filter: invert(0%) sepia(0%) saturate(0%) hue-rotate(0deg) brightness(0%) contrast(100%); +.toc-sidebar { + display: none; } -@media (prefers-color-scheme: dark) { - footer > div img { - filter: invert(100%) sepia(0%) saturate(0%) hue-rotate(0deg) brightness(1.2) contrast(100%); +@media screen and (min-width: 1024px) { + .container { + max-width: 1100px; + } + + .content-wrapper { + flex-direction: row; + gap: 3rem; + max-width: 1100px; + } + + .toc-sidebar { + display: block; + width: 240px; + flex-shrink: 0; + order: 2; + font-size: 0.85rem; + } + + .toc-sticky { + position: sticky; + top: calc(var(--header-height) + 2rem); + max-height: calc(100vh - var(--header-height) - 4rem); + overflow-y: auto; + padding-left: 1rem; + } + + .toc-sticky h3 { + margin: 0 0 1rem 0; + font-size: 0.75rem; + text-transform: uppercase; + letter-spacing: 0.05em; + color: var(--text-tertiary); + font-weight: 600; + } + + .toc-sticky ul { + list-style: none; + padding: 0; + margin: 0; + border-left: 1px solid var(--border-subtle); + } + + .toc-sticky ul ul { + margin: 0; + padding: 0; + border: none; + } + + .toc-sticky li { + margin: 0; + } + + .toc-sticky a { + display: block; + padding: 0.4rem 1rem; + color: var(--text-secondary); + text-decoration: none; + line-height: 1.4; + transition: all 0.2s ease; + border-left: 2px solid transparent; + margin-left: -1px; /* Align border with the container border */ + } + + .toc-sticky ul ul a { + padding-left: 2rem; + font-size: 0.95em; + } + + .toc-sticky ul ul ul a { + padding-left: 3rem; + } + + .toc-sticky a:hover { + color: var(--brand-primary); + border-left-color: var(--brand-primary); + background: linear-gradient(to right, var(--bg-secondary), transparent); + text-decoration: none; } + + .toc-sticky a.active { + color: var(--brand-primary); + border-left-color: var(--brand-primary); + background: linear-gradient(to right, var(--bg-secondary), transparent); + } + + .toc-sticky::-webkit-scrollbar { width: 4px; } + .toc-sticky::-webkit-scrollbar-thumb { background: var(--border-strong); border-radius: 4px; } } -#prev-next { +blockquote { + margin: 1.5rem 0; + padding: 0.5rem 0 0.5rem 1.25rem; + color: var(--text-secondary); + border-left: 3px solid var(--brand-primary); + background: transparent; + border-radius: 0; + font-style: italic; + font-size: 1.05rem; + line-height: 1.6; +} + +blockquote p { + margin: 0; +} + +/* -- Code Blocks -- */ + +.code-block-container { + position: relative; + margin: 1.5rem 0; + background: var(--code-bg); + border: 1px solid var(--border-subtle); + border-radius: 0; +} + +pre { display: flex; - justify-content: space-between; - align-items: center; - margin-top: 20px; - padding-top: 5px; - border-top: 2px solid var(--border); + margin: 0; + padding: 0; + background: transparent; + border: none; + border-radius: 0; + overflow-x: auto; + font-family: var(--font-mono); + font-size: 0.9em; + line-height: 1.6; + color: var(--code-text); + scrollbar-width: thin; + scrollbar-color: var(--border-strong) transparent; } -#prev-next a { - text-decoration: none; +pre::-webkit-scrollbar { + height: 6px; } -#prev-next > :first-child span::before{ - content: "←"; +pre::-webkit-scrollbar-track { + background: transparent; } -#prev-next > :last-child span::after{ - content: "→"; +pre::-webkit-scrollbar-thumb { + background: var(--border-strong); + border-radius: 3px; } -::-webkit-scrollbar { - width: 10px; - height: 10px; - background: var(--bg); +.line-numbers { + flex-shrink: 0; + display: flex; + flex-direction: column; + padding: 1rem 0.5rem; + border-right: 1px solid var(--border-subtle); + background: var(--code-bg); + color: var(--text-tertiary); + text-align: right; + user-select: none; + position: sticky; + left: 0; + z-index: 10; + min-width: 2.5rem; + font-size: 0.9rem; +} + +.line-numbers span { + display: block; + height: 1.6em; +} + +pre code { + flex-grow: 1; + display: block; + padding: 1rem 0.75rem; + background: transparent; + border: none; + font-family: var(--font-mono); + font-size: 0.9rem; + color: inherit; + line-height: 1.6; + border-radius: 0; +} + +:not(pre) > code { + font-family: var(--font-mono); + font-size: 0.95em; + background: transparent; + padding: 0; + color: var(--code-text); + border: none; + display: inline; + white-space: normal; + word-break: break-all; +} + +.copy-code-btn { + position: absolute; + top: 0.5rem; + right: 0.5rem; + z-index: 20; + display: flex; + align-items: center; + justify-content: center; + width: 32px; + height: 32px; + padding: 6px; + background: var(--bg-secondary); + border: 1px solid var(--border-subtle); + border-radius: 6px; + color: var(--text-secondary); + cursor: pointer; + transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1); + opacity: 0; + transform: scale(0.95); } -::-webkit-scrollbar-thumb { - background: #ccc; - border-radius: 8px; - border: 2px solid var(--bg); - min-height: 40px; + +.code-block-container:hover .copy-code-btn { + opacity: 1; + transform: scale(1); } -::-webkit-scrollbar-thumb:hover { - background: #bbb; + +.copy-code-btn:hover { + background: var(--bg-primary); + color: var(--brand-primary); + border-color: var(--brand-primary); + box-shadow: var(--shadow-sm); } -::-webkit-scrollbar-corner { - background: var(--bg); + +.copy-code-btn.copied { + color: #10b981; + border-color: #10b981; } -@media (prefers-color-scheme: dark) { - ::-webkit-scrollbar { - background: var(--bg); +p:has(+ .code-block-container) { + margin-bottom: 0.75rem; +} + +@media screen and (max-width: 600px) { + .code-block-container { + margin-left: -24px; + margin-right: -24px; + border-radius: 0; + border-left: none; + border-right: none; } - ::-webkit-scrollbar-thumb { - background: #444; - border: 2px solid var(--bg); + + .copy-code-btn { + top: 0.75rem; + right: 0.75rem; + background: var(--bg-primary); } - ::-webkit-scrollbar-thumb:hover { - background: #555; + + .line-numbers { + padding-left: 1rem; } - ::-webkit-scrollbar-corner { - background: var(--bg); +} + +table { + width: 100%; + border-collapse: collapse; + margin: 1.5rem 0; + font-size: 0.95rem; +} + +th, td { + padding: 0.75rem; + border: 1px solid var(--border-subtle); + text-align: left; +} + +th { + background: var(--bg-secondary); + font-weight: 600; + color: var(--text-primary); +} + +tr:nth-child(even) { + background-color: rgba(0,0,0,0.01); +} + +img { + max-width: 100%; + height: auto; + border-radius: 4px; +} + +figcaption { + margin-top: 0.5rem; + text-align: center; + font-size: 0.875rem; + color: var(--text-tertiary); +} + +footer { + margin-top: auto; + border-top: 1px solid var(--border-subtle); + padding: 2rem 24px; + background: var(--bg-secondary); + font-size: 0.875rem; + color: var(--text-secondary); +} + +footer > div { + max-width: var(--container-width); + margin: 0 auto; + display: flex; + flex-direction: column; + gap: 1rem; + align-items: center; + text-align: center; +} + +@media screen and (min-width: 640px) { + footer > div { + flex-direction: row; + justify-content: space-between; + text-align: left; } } -html { - scrollbar-width: thin; - scrollbar-color: #ccc var(--bg); +footer a { + color: var(--text-secondary); + text-decoration: none; +} + +footer a:hover { + color: var(--brand-primary); +} + +footer img { + height: 20px; + width: auto; + vertical-align: middle; + opacity: 0.7; + transition: opacity 0.2s, transform 0.2s; + filter: none; } + @media (prefers-color-scheme: dark) { - html { - scrollbar-color: #444 var(--bg); + footer img { + filter: invert(1); } } -#meta p{ - margin: 0; +footer img:hover { + opacity: 1; + transform: scale(1.1); } -#meta #author::before{ - content: "借由:"; +footer .social-links { + display: flex; + gap: 1rem; + align-items: center; } -h1{ - margin-bottom: 0; +/* -- Legacy/Utility Classes -- */ + +.center { + display: flex; + justify-content: center; + align-items: center; + text-align: center; + flex-wrap: wrap; + gap: 10px; + margin: 1.5rem 0; } -/* Sidebar Layout */ -.content-wrapper { +.large { + font-size: 1.5rem; + line-height: 1.4; + font-weight: 300; +} + +.bold { + font-weight: 700; +} + +#meta { + color: var(--text-tertiary); + font-size: 0.9rem; + margin-bottom: 1.5rem; + border-bottom: 1px solid var(--border-subtle); + padding-bottom: 1rem; +} + +#meta p { margin: 0; } + +#meta #author::before { + content: "by "; + opacity: 0.7; +} + +#prev-next { + display: flex; + justify-content: space-between; + gap: 2rem; + margin-top: 4rem; + padding-top: 2rem; + border-top: 1px solid var(--border-subtle); +} + +#prev-next > div { + flex: 1; + min-width: 0; +} + +#prev-next a { display: flex; flex-direction: column; + padding: 0; + border: none; + background: transparent; + text-decoration: none !important; +} + +#prev-next span { + font-size: 1rem; + font-weight: 500; + color: var(--text-primary); + line-height: 1.4; + overflow: hidden; + text-overflow: ellipsis; + display: -webkit-box; + -webkit-line-clamp: 2; + -webkit-box-orient: vertical; + transition: color 0.2s ease; +} + +#prev-next a:hover span { + color: var(--brand-primary); +} + +#prev-next > :first-child a::before { + content: "← PREV"; + display: block; + font-family: var(--font-mono); + font-size: 0.75rem; + color: var(--text-tertiary); + margin-bottom: 0.4rem; + text-transform: uppercase; + letter-spacing: 0.05em; +} + +#prev-next > :last-child a { + text-align: right; + align-items: flex-end; +} + +#prev-next > :last-child a::before { + content: "NEXT →"; + display: block; + font-family: var(--font-mono); + font-size: 0.75rem; + color: var(--text-tertiary); + margin-bottom: 0.4rem; + text-transform: uppercase; + letter-spacing: 0.05em; +} + +#prev-next > :first-child span::before { content: none; } +#prev-next > :last-child span::after { content: none; } + +::-webkit-scrollbar { + width: 8px; + height: 8px; +} +::-webkit-scrollbar-track { + background: transparent; +} +::-webkit-scrollbar-thumb { + background: var(--border-strong); + border-radius: 4px; +} +::-webkit-scrollbar-thumb:hover { + background: var(--text-tertiary); } -@media screen and (min-width: 1200px) { - body { - max-width: 80vw; +@media screen and (max-width: 600px) { + :root { + --page-padding: 20px; } + .header { + padding: 0; + } + .content-wrapper { - flex-direction: row; - align-items: stretch; - gap: 2rem; + padding: 0.75rem var(--page-padding) 1.5rem; + } + + h1 { font-size: 1.75rem; } + h2 { font-size: 1.5rem; } + + nav { + display: none; + position: absolute; + top: var(--header-height); + left: 0; + width: 100%; + background: var(--bg-primary); + flex-direction: column; + padding: 0.5rem 0; + border-bottom: 1px solid var(--border-subtle); + box-shadow: var(--shadow-md); + z-index: 90; + gap: 0; } - .main-content { - flex: 1; - min-width: 0; + nav.active { + display: flex; } - .toc-sidebar { - width: 250px; - flex-shrink: 0; - order: 2; - border-left: 1px solid var(--border); - padding-left: 1rem; - font-size: 0.9em; + nav a { + width: 100%; + padding: 1rem 24px; + border-bottom: 1px solid var(--border-subtle); + font-size: 1rem; } - .toc-sticky { - position: sticky; - top: 50%; - transform: translateY(-50%); - max-height: 90vh; - overflow-y: auto; + nav a:last-child { + border-bottom: none; } -} \ No newline at end of file +} + +hr { + border: none; + margin: 4rem 0; + height: 1px; +} diff --git a/content/learn/index.smd b/content/learn/index.smd index 12d1a3d..58cccc7 100644 --- a/content/learn/index.smd +++ b/content/learn/index.smd @@ -11,24 +11,92 @@ .draft = false, --- -# [《学习 Zig》 目录]($heading.id('table-of-contents')) - -- [前言](./preface) -- [安装 Zig](./installing-zig) -- [语言概述 - 第一部分](./language-overview-1) -- [语言概述 - 第二部分](./language-overview-2) -- [编码风格](./style-guide) -- [指针](./pointers) -- [栈内存](./stack-memory) -- [堆内存和分配器](./heap-memory) -- [泛型](./generics) -- [实战](./coding-in-zig) -- [总结](./conclusion) - [《学习 Zig》](https://www.openmymind.net/learning_zig/)系列教程最初由 [Karl Seguin](https://github.com/karlseguin) 编写,该教程行文流畅,讲述的脉络由浅入深,深入浅出,是入门 Zig 非常不错的选择。因此,[Zig 中文社区](https://ziglang.cc)将其翻译成中文,便于在中文用户内阅读与传播。 初次接触 Zig 的用户可以按序号依次阅读,对于有经验的 Zig 开发者可按需阅读感兴趣的章节。 +```=html +
+ + 01 +
+ 前言 + 关于本教程与 Zig 语言的简要介绍。 +
+
+ + 02 +
+ 安装 Zig + 环境配置与编译器安装指南。 +
+
+ + 03 +
+ 语言概述 - 第一部分 + 基本语法、变量、控制流与函数。 +
+
+ + 04 +
+ 语言概述 - 第二部分 + 结构体、数组、切片与错误处理。 +
+
+ + 05 +
+ 编码风格 + Zig 官方推荐的代码格式与命名规范。 +
+
+ + 06 +
+ 指针 + 理解 Zig 中的指针、多级指针与切片。 +
+
+ + 07 +
+ 栈内存 + 栈分配、生命周期与内存安全。 +
+
+ + 08 +
+ 堆内存和分配器 + Allocator 接口、常用分配器与内存管理。 +
+
+ + 09 +
+ 泛型 + 编译期多态、Comptime 与泛型数据结构。 +
+
+ + 10 +
+ 实战 + 综合运用所学知识构建实际应用。 +
+
+ + 11 +
+ 总结 + 教程回顾与进阶学习路线。 +
+
+
+``` + # [关于原作者]($heading.id('about-original-author')) [Karl Seguin](https://www.linkedin.com/in/karlseguin/) 在多个领域有着丰富经验,前微软 MVP,他撰写了大量文章,是多个微软公共新闻组的活跃成员。现居新加坡。他还是以下教程的作者: diff --git a/content/monthly/202207.smd b/content/monthly/202207.smd index 2587e78..e45b182 100644 --- a/content/monthly/202207.smd +++ b/content/monthly/202207.smd @@ -1,5 +1,5 @@ --- -.title = "202207 | 开刊 HelloWorld", +.title = "开刊 HelloWorld", .date = @date("2022-07-30T14:08:15+0800"), .author = "ZigCC", .layout = "monthly.shtml", diff --git a/content/monthly/202208.smd b/content/monthly/202208.smd index 82604f1..60b0bef 100644 --- a/content/monthly/202208.smd +++ b/content/monthly/202208.smd @@ -1,5 +1,5 @@ --- -.title = "202208 | stage2 默认开启", +.title = "stage2 默认开启", .date = @date("2022-08-28T16:03:12+0800"), .author = "ZigCC", .layout = "monthly.shtml", diff --git a/content/monthly/202209.smd b/content/monthly/202209.smd index 8f87cc2..2bba652 100644 --- a/content/monthly/202209.smd +++ b/content/monthly/202209.smd @@ -1,5 +1,5 @@ --- -.title = "202209 | 锋芒毕露", +.title = "锋芒毕露", .date = @date("2022-10-03T23:32:12+0800"), .author = "ZigCC", .layout = "monthly.shtml", diff --git a/content/monthly/202210.smd b/content/monthly/202210.smd index 227258f..268e81b 100644 --- a/content/monthly/202210.smd +++ b/content/monthly/202210.smd @@ -1,5 +1,5 @@ --- -.title = "202210 | 0.10 蓄势待发", +.title = "0.10 蓄势待发", .date = @date("2022-10-30T10:10:14+0800"), .author = "ZigCC", .layout = "monthly.shtml", diff --git a/content/monthly/202211.smd b/content/monthly/202211.smd index 87d90ad..d4ac576 100644 --- a/content/monthly/202211.smd +++ b/content/monthly/202211.smd @@ -1,5 +1,5 @@ --- -.title = "202211 | 0.10 横空出世", +.title = "0.10 横空出世", .date = @date("2022-12-04T18:45:34+0800"), .author = "ZigCC", .layout = "monthly.shtml", diff --git a/content/monthly/202212.smd b/content/monthly/202212.smd index 2720888..73f1ba6 100644 --- a/content/monthly/202212.smd +++ b/content/monthly/202212.smd @@ -1,5 +1,5 @@ --- -.title = "202212 | TBD", +.title = "告别 C++ 实现", .date = @date("2022-12-11T14:11:38+0800"), .author = "ZigCC", .layout = "monthly.shtml", diff --git a/content/monthly/202301.smd b/content/monthly/202301.smd index 0e410ea..3f7d18f 100644 --- a/content/monthly/202301.smd +++ b/content/monthly/202301.smd @@ -1,5 +1,5 @@ --- -.title = "202301 | 包管理来了", +.title = "包管理来了", .date = @date("2023-01-31T20:05:19+0800"), .author = "ZigCC", .layout = "monthly.shtml", diff --git a/content/monthly/202302.smd b/content/monthly/202302.smd index c46e723..09375c7 100644 --- a/content/monthly/202302.smd +++ b/content/monthly/202302.smd @@ -1,5 +1,5 @@ --- -.title = "202302 | 精益求精的包管理", +.title = "精益求精的包管理", .date = @date("2023-02-26T17:36:12+0800"), .author = "ZigCC", .layout = "monthly.shtml", diff --git a/content/monthly/202303.smd b/content/monthly/202303.smd index f9f687b..b36e30a 100644 --- a/content/monthly/202303.smd +++ b/content/monthly/202303.smd @@ -1,5 +1,5 @@ --- -.title = "202303 | 并发编译", +.title = "并发编译", .date = @date("2023-04-10T19:25:59+0800"), .author = "ZigCC", .layout = "monthly.shtml", diff --git a/content/monthly/202304.smd b/content/monthly/202304.smd index 9d81e3b..fc39ee0 100644 --- a/content/monthly/202304.smd +++ b/content/monthly/202304.smd @@ -1,5 +1,5 @@ --- -.title = "202304 | 首次闯入 Tiobe 前 50", +.title = "首次闯入 Tiobe 前 50", .date = @date("2023-05-03T10:31:04+0800"), .author = "ZigCC", .layout = "monthly.shtml", diff --git a/content/monthly/202305.smd b/content/monthly/202305.smd index d6e6576..383e041 100644 --- a/content/monthly/202305.smd +++ b/content/monthly/202305.smd @@ -1,5 +1,5 @@ --- -.title = "202305 | HTTP is built-in", +.title = "HTTP is built-in", .date = @date("2023-06-16T16:32:29+0800"), .author = "ZigCC", .layout = "monthly.shtml", diff --git a/content/monthly/202306.smd b/content/monthly/202306.smd index d978407..5aea201 100644 --- a/content/monthly/202306.smd +++ b/content/monthly/202306.smd @@ -1,5 +1,5 @@ --- -.title = "202306 | Zig 要分叉了?", +.title = "Zig 要分叉了?", .date = @date("2023-07-01T17:35:43+0800"), .author = "ZigCC", .layout = "monthly.shtml", diff --git a/content/monthly/202307.smd b/content/monthly/202307.smd index 78ccf39..87c296a 100644 --- a/content/monthly/202307.smd +++ b/content/monthly/202307.smd @@ -1,5 +1,5 @@ --- -.title = "202307 | 异步缺席 0.11", +.title = "异步缺席 0.11", .date = @date("2023-08-07T20:05:29+0800"), .author = "ZigCC", .layout = "monthly.shtml", diff --git a/content/monthly/202308.smd b/content/monthly/202308.smd index d518254..82a2f46 100644 --- a/content/monthly/202308.smd +++ b/content/monthly/202308.smd @@ -1,5 +1,5 @@ --- -.title = "202308 | 0.11 正式发布", +.title = "0.11 正式发布", .date = @date("2023-09-03T19:38:04+0800"), .author = "ZigCC", .layout = "monthly.shtml", diff --git a/content/monthly/202309.smd b/content/monthly/202309.smd index 09ea3f3..9857d4e 100644 --- a/content/monthly/202309.smd +++ b/content/monthly/202309.smd @@ -1,5 +1,5 @@ --- -.title = "202309 | Bun 正式发布 1.0", +.title = "Bun 正式发布 1.0", .date = @date("2023-09-23T10:10:58+0800"), .author = "ZigCC", .layout = "monthly.shtml", diff --git a/content/monthly/202310.smd b/content/monthly/202310.smd index b21b34c..8b0ce5a 100644 --- a/content/monthly/202310.smd +++ b/content/monthly/202310.smd @@ -1,5 +1,5 @@ --- -.title = "202310", +.title = "Zig 接口与 io_uring 探索", .date = @date("2023-10-13T07:53:24+0800"), .author = "ZigCC", .layout = "monthly.shtml", diff --git a/content/monthly/202311.smd b/content/monthly/202311.smd index cbf7370..c629bda 100644 --- a/content/monthly/202311.smd +++ b/content/monthly/202311.smd @@ -1,5 +1,5 @@ --- -.title = "202311 | 传值或传引用,这是个大问题", +.title = "传值或传引用,这是个大问题", .date = @date("2023-11-19T18:26:29+0800"), .author = "ZigCC", .layout = "monthly.shtml", diff --git a/content/monthly/202402.smd b/content/monthly/202402.smd index 1e0b2ad..037b947 100644 --- a/content/monthly/202402.smd +++ b/content/monthly/202402.smd @@ -1,5 +1,5 @@ --- -.title = "202402 | Zig 2024 Roadmap 新鲜出炉", +.title = "Zig 2024 Roadmap 新鲜出炉", .date = @date("2024-03-04T20:54:50+0800"), .author = "ZigCC", .layout = "monthly.shtml", diff --git a/content/monthly/202403.smd b/content/monthly/202403.smd index fcd5b25..b668fe6 100644 --- a/content/monthly/202403.smd +++ b/content/monthly/202403.smd @@ -1,5 +1,5 @@ --- -.title = "202403 | ziglang.cc 正式上线", +.title = "ziglang.cc 正式上线", .date = @date("2024-03-13T20:32:27+0800"), .author = "ZigCC", .layout = "monthly.shtml", diff --git a/content/monthly/202404.smd b/content/monthly/202404.smd index c92c564..0c6babe 100644 --- a/content/monthly/202404.smd +++ b/content/monthly/202404.smd @@ -1,5 +1,5 @@ --- -.title = "202404 | Zig 0.12.0 正式释出", +.title = "Zig 0.12.0 正式释出", .date = @date("2024-04-18T21:59:49+0800"), .author = "ZigCC", .layout = "monthly.shtml", diff --git a/content/monthly/202405.smd b/content/monthly/202405.smd index 99df486..cfd62c1 100644 --- a/content/monthly/202405.smd +++ b/content/monthly/202405.smd @@ -1,5 +1,5 @@ --- -.title = "202405", +.title = "Zig 任务调度器与 CLI 进度条", .date = @date("2024-06-02T22:18:59+0800"), .author = "ZigCC", .layout = "monthly.shtml", diff --git a/content/monthly/202406.smd b/content/monthly/202406.smd index b3ead4a..205a15c 100644 --- a/content/monthly/202406.smd +++ b/content/monthly/202406.smd @@ -1,5 +1,5 @@ --- -.title = "202406 | 0.13 来了", +.title = "0.13 来了", .date = @date("2024-07-01T20:34:51+0800"), .author = "ZigCC", .layout = "monthly.shtml", diff --git a/content/monthly/202407.smd b/content/monthly/202407.smd index 8366be8..982de20 100644 --- a/content/monthly/202407.smd +++ b/content/monthly/202407.smd @@ -1,5 +1,5 @@ --- -.title = "202407 | Zig 成为最热门的编程语言", +.title = "Zig 成为最热门的编程语言", .date = @date("2024-07-05T21:22:52+0800"), .author = "ZigCC", .layout = "monthly.shtml", diff --git a/content/monthly/202410.smd b/content/monthly/202410.smd index 0a099fb..a2277bc 100644 --- a/content/monthly/202410.smd +++ b/content/monthly/202410.smd @@ -1,5 +1,5 @@ --- -.title = "202410 | 向 Zig 软件基金会认捐 30 万美元", +.title = "向 Zig 软件基金会认捐 30 万美元", .date = @date("2024-10-26T00:17:35+0800"), .author = "ZigCC", .layout = "monthly.shtml", diff --git a/content/monthly/202411.smd b/content/monthly/202411.smd index 7931766..f66c22e 100644 --- a/content/monthly/202411.smd +++ b/content/monthly/202411.smd @@ -1,5 +1,5 @@ --- -.title = "202411", +.title = "JAM 与 JS 工具链重构", .date = @date("2024-12-09T21:02:40+0800"), .author = "ZigCC", .layout = "monthly.shtml", diff --git a/layouts/index.shtml b/layouts/index.shtml index 9cfbdff..83aa524 100644 --- a/layouts/index.shtml +++ b/layouts/index.shtml @@ -1,7 +1,6 @@ - -
+
\ No newline at end of file diff --git a/layouts/learn.shtml b/layouts/learn.shtml index 5e5789c..bbb577d 100644 --- a/layouts/learn.shtml +++ b/layouts/learn.shtml @@ -2,7 +2,6 @@ -

@@ -11,6 +10,7 @@
+

diff --git a/layouts/monthly.shtml b/layouts/monthly.shtml index 981189b..8d11a32 100644 --- a/layouts/monthly.shtml +++ b/layouts/monthly.shtml @@ -1,6 +1,53 @@ - + -
-
-
\ No newline at end of file + +
+ +
+
+

TOC

+
+
+
+ +
+

+ + +
+
+ +
+ + +
+
+
+
+ + + +
+
+ + + +
+
+
+ +
+
+ \ No newline at end of file diff --git a/layouts/post.shtml b/layouts/post.shtml index 4d2a979..1004d1c 100644 --- a/layouts/post.shtml +++ b/layouts/post.shtml @@ -1,4 +1,4 @@ - + @@ -26,6 +26,61 @@ -
-
-
+ +
+ +
+
+

TOC

+
+
+
+ +
+

+ + + + + +
+
+

+ + | + +

+
+
+
+
+ + + +
+
+ + + +
+
+
+
+
+ diff --git a/layouts/templates/base.shtml b/layouts/templates/base.shtml index ff4b9a8..8de7a52 100644 --- a/layouts/templates/base.shtml +++ b/layouts/templates/base.shtml @@ -30,22 +30,36 @@ fetch('https://en.liujiacai.net/pv/write?' + new URLSearchParams(payload), {mode: 'no-cors'}).catch(console.log); + +
-

- +
+

+ + +
+ -