diff --git a/.github/workflows/deploy-pages.yml b/.github/workflows/deploy-pages.yml new file mode 100644 index 0000000..f042abd --- /dev/null +++ b/.github/workflows/deploy-pages.yml @@ -0,0 +1,48 @@ +name: Deploy blog to GitHub Pages + +on: + push: + branches: [master] + workflow_dispatch: + +permissions: + contents: read + pages: write + id-token: write + +concurrency: + group: pages + cancel-in-progress: false + +jobs: + build: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v6 + + - name: Configure GitHub Pages + id: pages + uses: actions/configure-pages@v5 + + - name: Build with Jekyll + uses: actions/jekyll-build-pages@v1 + with: + source: ./ + destination: ./_site + + - name: Upload GitHub Pages artifact + uses: actions/upload-pages-artifact@v4 + with: + path: ./_site + + deploy: + environment: + name: github-pages + url: ${{ steps.deployment.outputs.page_url }} + runs-on: ubuntu-latest + needs: build + steps: + - name: Deploy to GitHub Pages + id: deployment + uses: actions/deploy-pages@v4 diff --git a/.gitignore b/.gitignore index 9444158..f01ac3b 100644 --- a/.gitignore +++ b/.gitignore @@ -2,4 +2,8 @@ .cursorrules actionlint .claude/ -.cursor \ No newline at end of file +.cursor +_site/ +.jekyll-cache/ +.jekyll-metadata +.sass-cache/ diff --git a/404.html b/404.html new file mode 100644 index 0000000..bd2efd6 --- /dev/null +++ b/404.html @@ -0,0 +1,12 @@ +--- +layout: default +title: 页面没有找到 +permalink: /404.html +--- +
+

404

+

PAGE NOT FOUND

+

这张地图上,没有这一页。

+

链接可能已经移动,或者它从未存在过。你可以返回首页继续探索。

+ 返回首页 → +
diff --git "a/AI/AI \350\256\272\346\226\207\350\265\204\346\226\231.md" "b/AI/AI \350\256\272\346\226\207\350\265\204\346\226\231.md" index 78ea84d..9964211 100644 --- "a/AI/AI \350\256\272\346\226\207\350\265\204\346\226\231.md" +++ "b/AI/AI \350\256\272\346\226\207\350\265\204\346\226\231.md" @@ -5,8 +5,6 @@ date: 2025-12-14 # Attention Is All You Need - 英文原版:[Attention Is All You Need.pdf](https://arxiv.org/pdf/1706.03762) -- 中文翻译:[Attention Is All You Need 中文翻译.pdf](./资料/Attention%20Is%20All%20You%20Need%20中文翻译.pdf) - # The Illustrated Transformer -[The Illustrated Transformer](https://jalammar.github.io/illustrated-transformer/) \ No newline at end of file +[The Illustrated Transformer](https://jalammar.github.io/illustrated-transformer/) diff --git "a/AI/MCP \345\216\237\347\220\206\345\217\212 Java \345\274\200\345\217\221\346\214\207\345\215\227.md" "b/AI/MCP \345\216\237\347\220\206\345\217\212 Java \345\274\200\345\217\221\346\214\207\345\215\227.md" index cc84a20..b45f5cd 100644 --- "a/AI/MCP \345\216\237\347\220\206\345\217\212 Java \345\274\200\345\217\221\346\214\207\345\215\227.md" +++ "b/AI/MCP \345\216\237\347\220\206\345\217\212 Java \345\274\200\345\217\221\346\214\207\345\215\227.md" @@ -157,7 +157,7 @@ spring.ai.mcp.server.name=my-invoice-server spring.ai.mcp.server.version=0.0.1 ``` -详细的配置参数及默认值可以参考官方文档:[Spring AI / Model Context Protocol (MCP) / MCP Server Boot Starters]([https://](https://docs.spring.io/spring-ai/reference/api/mcp/mcp-server-boot-starter-docs.html#_configuration_properties))。 +详细的配置参数及默认值可以参考官方文档:[Spring AI / Model Context Protocol (MCP) / MCP Server Boot Starters](https://docs.spring.io/spring-ai/reference/api/mcp/mcp-server-boot-starter-docs.html#_configuration_properties)。 ### 暴露 Tool @@ -228,7 +228,7 @@ cline_mcp_setting.json 增加如下配置: 1. JDK 版本必须 >= 17 2. Spring Boot 版本必须 >= 3.2 -3. Spring AI 底层使用 [modelcontextprotocol / java-sdk]([https://](https://github.com/modelcontextprotocol/java-sdk)) +3. Spring AI 底层使用 [modelcontextprotocol / java-sdk](https://github.com/modelcontextprotocol/java-sdk) 4. MCP 协议等都在快速发展中,上面的代码示例仅供参考,具体实现可能会有所不同 ## 完整配置示例 @@ -965,4 +965,4 @@ A: 常见瓶颈: - **Java SDK**: https://github.com/modelcontextprotocol/java-sdk - **TypeScript SDK**: https://github.com/modelcontextprotocol/typescript-sdk - **Python SDK**: https://github.com/modelcontextprotocol/python-sdk -- **MCP Inspector**: https://github.com/modelcontextprotocol/inspector \ No newline at end of file +- **MCP Inspector**: https://github.com/modelcontextprotocol/inspector diff --git a/Gemfile b/Gemfile new file mode 100644 index 0000000..df725fa --- /dev/null +++ b/Gemfile @@ -0,0 +1,6 @@ +source "https://rubygems.org" + +# Keep local builds aligned with the dependency set used by GitHub Pages. +gem "github-pages", "~> 232", group: :jekyll_plugins +gem "nokogiri", "1.16.7" +gem "webrick", "1.8.1" diff --git a/README.md b/README.md index a0b67fa..4286016 100644 --- a/README.md +++ b/README.md @@ -4,6 +4,8 @@ ### 在代码、书影音与生活之间,持续构建自己的知识地图 +### [访问在线博客 →](https://ljyyano.github.io/Thinking_in_Java_MindMapping/) +

Code AI @@ -217,7 +219,7 @@ LeetCode 二叉树系统题解.md2019-10-10 Linux mmap 技术.md2021-09-23 Linux 虚拟内存.md2021-03-21 -LSM.md- +LSM.md2024-01-24 Mac mini 家庭网络设置内网穿透.md2025-05-14 Maven 依赖树的解析规则.md2020-11-13 MySQL 锁深入分析.md2023-12-14 diff --git a/_config.yml b/_config.yml new file mode 100644 index 0000000..7828155 --- /dev/null +++ b/_config.yml @@ -0,0 +1,71 @@ +title: "Yano's Notes" +tagline: "在代码、书影音与生活之间,持续构建自己的知识地图" +description: "Yano 的个人博客:Java、Redis、Spring、AI、读书、观影、游戏与生活随笔。" +author: "Yano" +lang: zh-CN +timezone: Asia/Shanghai + +url: "https://ljyyano.github.io" +baseurl: "/Thinking_in_Java_MindMapping" +repository: "LjyYano/Thinking_in_Java_MindMapping" + +markdown: kramdown +highlighter: rouge +strict_front_matter: true + +kramdown: + input: GFM + syntax_highlighter: rouge + hard_wrap: false + auto_ids: true + +plugins: + - jekyll-relative-links + +relative_links: + enabled: true + collections: true + +defaults: + - scope: + path: "AI" + values: + layout: article + category: AI + - scope: + path: "编程" + values: + layout: article + category: 编程 + - scope: + path: "游戏" + values: + layout: article + category: 游戏 + - scope: + path: "观影" + values: + layout: article + category: 观影 + - scope: + path: "读书" + values: + layout: article + category: 读书 + - scope: + path: "随笔" + values: + layout: article + category: 随笔 + +exclude: + - README.md + - Gemfile + - Gemfile.lock + - scripts + - vendor + - node_modules + - .claude + - .cursor + - .cursorrules + - .DS_Store diff --git a/_data/categories.yml b/_data/categories.yml new file mode 100644 index 0000000..a1e8c29 --- /dev/null +++ b/_data/categories.yml @@ -0,0 +1,36 @@ +- name: 编程 + path: 编程/ + slug: code + icon: "⌘" + kicker: CODE + description: "Java、Redis、Spring 与工程原理" +- name: AI + path: AI/ + slug: ai + icon: "✦" + kicker: INTELLIGENCE + description: "Agent、MCP 与人工智能实践" +- name: 读书 + path: 读书/ + slug: books + icon: "◫" + kicker: BOOKS + description: "读书笔记、摘抄与长期思考" +- name: 观影 + path: 观影/ + slug: films + icon: "▶" + kicker: FILMS + description: "电影、剧集与年度观影总结" +- name: 游戏 + path: 游戏/ + slug: games + icon: "◆" + kicker: GAMES + description: "JRPG、任天堂与游戏体验" +- name: 随笔 + path: 随笔/ + slug: essays + icon: "≈" + kicker: ESSAYS + description: "生活记录、复盘与偶然所得" diff --git a/_includes/footer.html b/_includes/footer.html new file mode 100644 index 0000000..863ea0b --- /dev/null +++ b/_includes/footer.html @@ -0,0 +1,14 @@ +

diff --git a/_includes/header.html b/_includes/header.html new file mode 100644 index 0000000..ad30dfc --- /dev/null +++ b/_includes/header.html @@ -0,0 +1,32 @@ + diff --git a/_includes/search.html b/_includes/search.html new file mode 100644 index 0000000..0e1659a --- /dev/null +++ b/_includes/search.html @@ -0,0 +1,12 @@ + diff --git a/_layouts/article.html b/_layouts/article.html new file mode 100644 index 0000000..4e89afc --- /dev/null +++ b/_layouts/article.html @@ -0,0 +1,52 @@ +--- +layout: default +--- +{% assign article_title = page.title | default: page.name | replace: '.md', '' %} +{% assign path_parts = page.path | split: '/' %} +{% assign category_name = page.category | default: path_parts[0] %} +{% assign category_slug = '' %} +{% for item in site.data.categories %} + {% if item.name == category_name %}{% assign category_slug = item.slug %}{% endif %} +{% endfor %} + +
+
+ + +
+
+ {{ category_name }} + {% if page.date %}{% endif %} +
+

{{ article_title }}

+
+
+ +
+ {{ content }} +
+ + +
+ + +
diff --git a/_layouts/category.html b/_layouts/category.html new file mode 100644 index 0000000..5f56227 --- /dev/null +++ b/_layouts/category.html @@ -0,0 +1,45 @@ +--- +layout: default +--- +{% assign articles = site.pages | where_exp: 'item', 'item.date != nil and item.path contains page.category_path' | sort: 'date' | reverse %} +
+
+ ← 返回首页 +

{{ page.kicker }}

+
+

{{ page.title }}

+ {{ articles.size }} +
+

{{ page.description }}

+
+ +
+
+ + 共 {{ articles.size }} 篇 +
+ +
+ {% for article in articles %} + {% assign article_title = article.title | default: article.name | replace: '.md', '' %} + {% assign parts = article.path | split: '/' %} + + +
+ {% if parts.size > 2 %}{{ parts[1] }}{% endif %} +

{{ article_title }}

+

{{ article.content | strip_html | strip_newlines | normalize_whitespace | truncate: 120 }}

+
+ +
+ {% endfor %} +
+ +
+
diff --git a/_layouts/default.html b/_layouts/default.html new file mode 100644 index 0000000..3998edc --- /dev/null +++ b/_layouts/default.html @@ -0,0 +1,39 @@ + + + + + + + + {% assign page_title = page.title | default: page.name | replace: '.md', '' | replace: '.html', '' %} + {% assign meta_description = page.description | default: site.description | strip_html | normalize_whitespace | truncate: 160 %} + {% if page.url == '/' %}{{ site.title }} · {{ site.tagline }}{% else %}{{ page_title }} · {{ site.title }}{% endif %} + + + + + + + + + + + + + + + + + {% include header.html %} +
{{ content }}
+ {% include footer.html %} + {% include search.html %} + + + diff --git a/about.html b/about.html new file mode 100644 index 0000000..848ce35 --- /dev/null +++ b/about.html @@ -0,0 +1,40 @@ +--- +layout: default +title: 关于 +permalink: /about/ +description: 关于 Yano 与这个持续生长的个人知识博客。 +--- +
+
+ ← 返回首页 +

ABOUT THIS ARCHIVE

+

你好,我是 Yano。

+

一名喜欢追问原理的程序员,也是一名长期记录者。

+
+ +
+
+

一切从《Java 编程思想》开始

+

最初,我只是把读书时整理的思维导图截图发布到简书;收到许多读者留言后,便创建了这个项目,将完整笔记持续沉淀下来。

+

后来内容逐渐越过了 Java 的边界,从编程与源码分析,延伸到 AI、读书、观影、游戏和生活随笔。Thinking_in_Java_MindMapping 这个名字已经无法概括这里的一切,但它保留了整个知识库最初的起点。

+
Think deeply. Learn continuously. Write things down.
+

现在关注什么

+

我仍然关注 Java 生态、分布式系统与底层原理,也在持续探索 AI Agent、MCP 和人与智能工具协作的新方式。技术之外,我同样认真对待书、电影、游戏和日常生活。

+
+ + +
+
diff --git a/archive.html b/archive.html new file mode 100644 index 0000000..77a3399 --- /dev/null +++ b/archive.html @@ -0,0 +1,48 @@ +--- +layout: default +title: 文章归档 +permalink: /archive/ +description: 按时间浏览 Yano's Notes 的全部文章。 +--- +{% assign articles = site.pages | where_exp: 'item', 'item.date != nil' | sort: 'date' | reverse %} +
+
+ ← 返回首页 +

THE COMPLETE ARCHIVE

+
+

文章归档

+ {{ articles.size }} +
+

从最近写下的内容开始,沿着时间回看这份持续生长的知识档案。

+
+ +
+
+ + 共 {{ articles.size }} 篇 +
+ +
+ {% assign previous_year = '' %} + {% for article in articles %} + {% assign current_year = article.date | date: '%Y' %} + {% if current_year != previous_year %} +

{{ current_year }}

+ {% assign previous_year = current_year %} + {% endif %} + {% assign article_title = article.title | default: article.name | replace: '.md', '' %} + {% assign parts = article.path | split: '/' %} + + + {{ parts[0] }} +

{{ article_title }}

+ +
+ {% endfor %} +
+ +
+
diff --git a/assets/css/style.css b/assets/css/style.css new file mode 100644 index 0000000..f5fe119 --- /dev/null +++ b/assets/css/style.css @@ -0,0 +1,1993 @@ +:root { + --ink: #171a20; + --ink-soft: #555b64; + --paper: #f6f4ef; + --paper-raised: #fcfbf8; + --paper-deep: #ebe8e0; + --line: rgba(23, 26, 32, 0.14); + --line-strong: rgba(23, 26, 32, 0.28); + --acid: #e9f65d; + --acid-bright: #f1ff5d; + --orange: #e56e45; + --blue: #9dc8dd; + --violet: #b8a5d4; + --green: #8fb99e; + --yellow: #e7c765; + --shadow: 0 24px 70px rgba(32, 31, 27, 0.09); + --sans: Inter, ui-sans-serif, -apple-system, BlinkMacSystemFont, "Segoe UI", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", sans-serif; + --serif: "Iowan Old Style", "Baskerville", "Times New Roman", "Songti SC", "STSong", serif; + --mono: "SFMono-Regular", Consolas, "Liberation Mono", Menlo, monospace; + --wrap: min(1180px, calc(100vw - 48px)); + --header-height: 82px; +} + +html[data-theme="dark"] { + --ink: #ecece6; + --ink-soft: #a4a7ac; + --paper: #141619; + --paper-raised: #1b1e22; + --paper-deep: #23262b; + --line: rgba(245, 245, 235, 0.12); + --line-strong: rgba(245, 245, 235, 0.26); + --shadow: 0 24px 70px rgba(0, 0, 0, 0.24); +} + +* { + box-sizing: border-box; +} + +html { + scroll-behavior: smooth; + scroll-padding-top: calc(var(--header-height) + 24px); +} + +body { + margin: 0; + color: var(--ink); + background: var(--paper); + font-family: var(--sans); + line-height: 1.65; + -webkit-font-smoothing: antialiased; + text-rendering: optimizeLegibility; +} + +body.search-open, +body.nav-open { + overflow: hidden; +} + +::selection { + color: #171a20; + background: var(--acid-bright); +} + +a { + color: inherit; + text-decoration: none; +} + +button, +input { + color: inherit; + font: inherit; +} + +button { + cursor: pointer; +} + +img, +video { + max-width: 100%; + height: auto; +} + +.wrap { + width: var(--wrap); + margin-inline: auto; +} + +.skip-link { + position: fixed; + top: 10px; + left: 10px; + z-index: 1000; + padding: 10px 14px; + color: #171a20; + background: var(--acid-bright); + transform: translateY(-150%); +} + +.skip-link:focus { + transform: translateY(0); +} + +/* Header */ +.site-header { + position: sticky; + top: 0; + z-index: 100; + height: var(--header-height); + border-bottom: 1px solid var(--line); + background: color-mix(in srgb, var(--paper) 90%, transparent); + backdrop-filter: blur(18px); +} + +.header-inner { + width: var(--wrap); + height: 100%; + margin-inline: auto; + display: grid; + grid-template-columns: 1fr auto 1fr; + align-items: center; +} + +.brand { + width: max-content; + display: inline-flex; + align-items: center; + gap: 11px; +} + +.brand-mark { + width: 37px; + height: 37px; + display: grid; + place-items: center; + color: var(--paper); + background: var(--ink); + border-radius: 50%; + font-family: var(--serif); + font-size: 22px; + font-style: italic; + font-weight: 700; + line-height: 1; +} + +.brand-copy { + display: grid; + line-height: 1.05; +} + +.brand-copy strong { + font-family: var(--serif); + font-size: 18px; + letter-spacing: -0.02em; +} + +.brand-copy small { + margin-top: 5px; + color: var(--ink-soft); + font-family: var(--mono); + font-size: 8px; + letter-spacing: 0.13em; +} + +.main-nav { + display: flex; + align-items: center; + gap: 34px; + font-size: 14px; +} + +.main-nav a { + position: relative; + padding-block: 8px; +} + +.main-nav a::after { + content: ""; + position: absolute; + right: 0; + bottom: 3px; + left: 0; + height: 1px; + background: currentColor; + transform: scaleX(0); + transition: transform 180ms ease; +} + +.main-nav a:hover::after, +.main-nav a[aria-current="page"]::after { + transform: scaleX(1); +} + +.header-actions { + justify-self: end; + display: flex; + align-items: center; + gap: 8px; +} + +.icon-button { + position: relative; + width: 40px; + height: 40px; + display: grid; + place-items: center; + padding: 0; + border: 1px solid transparent; + border-radius: 50%; + background: transparent; + transition: background 180ms ease, border-color 180ms ease; +} + +.icon-button:hover { + border-color: var(--line); + background: var(--paper-raised); +} + +.icon-button svg, +.inline-filter svg, +.search-box svg { + width: 19px; + fill: none; + stroke: currentColor; + stroke-linecap: round; + stroke-linejoin: round; + stroke-width: 1.7; +} + +.search-trigger { + width: 58px; + border-color: var(--line); + border-radius: 22px; + grid-template-columns: auto auto; + gap: 5px; +} + +.shortcut { + color: var(--ink-soft); + font-family: var(--mono); + font-size: 10px; +} + +.moon-icon, +html[data-theme="dark"] .sun-icon { + display: none; +} + +html[data-theme="dark"] .moon-icon { + display: block; +} + +.nav-toggle { + display: none; +} + +/* Home hero */ +.home-hero { + position: relative; + min-height: calc(100svh - var(--header-height)); + display: flex; + flex-direction: column; + overflow: hidden; + border-bottom: 1px solid var(--line); +} + +.hero-grid { + position: absolute; + inset: 0; + opacity: 0.44; + background-image: linear-gradient(var(--line) 1px, transparent 1px), linear-gradient(90deg, var(--line) 1px, transparent 1px); + background-size: 88px 88px; + mask-image: linear-gradient(to bottom, black, transparent 88%); +} + +.hero-orbit { + position: absolute; + border: 1px solid var(--line); + border-radius: 50%; + pointer-events: none; +} + +.hero-orbit-one { + top: 5%; + right: 4%; + width: min(46vw, 680px); + aspect-ratio: 1; +} + +.hero-orbit-two { + top: 18%; + right: 13%; + width: min(29vw, 420px); + aspect-ratio: 1; +} + +.hero-inner { + position: relative; + z-index: 1; + width: var(--wrap); + margin: auto; + padding: 80px 0 72px; + display: grid; + grid-template-columns: minmax(0, 1.2fr) minmax(280px, 0.8fr); + align-items: center; + gap: 80px; +} + +.hero-kicker, +.section-kicker { + margin: 0 0 24px; + color: var(--ink-soft); + font-family: var(--mono); + font-size: 11px; + font-weight: 700; + letter-spacing: 0.16em; +} + +.hero-kicker { + display: flex; + align-items: center; + gap: 12px; +} + +.hero-kicker span { + width: 28px; + height: 2px; + background: var(--orange); +} + +.hero-copy h1 { + max-width: 830px; + margin: 0; + font-family: var(--serif); + font-size: clamp(60px, 6.6vw, 104px); + font-weight: 500; + letter-spacing: -0.065em; + line-height: 0.98; +} + +.hero-copy h1 span { + position: relative; + z-index: 0; + white-space: nowrap; + font-style: italic; +} + +.hero-copy h1 span::after { + content: ""; + position: absolute; + z-index: -1; + right: -0.05em; + bottom: 0.04em; + left: -0.02em; + height: 0.24em; + background: var(--acid); + transform: rotate(-1.5deg); +} + +.hero-intro { + max-width: 630px; + margin: 36px 0 0; + color: var(--ink-soft); + font-size: 17px; + line-height: 1.9; +} + +.hero-actions { + margin-top: 38px; + display: flex; + align-items: center; + gap: 26px; +} + +.primary-button { + min-height: 52px; + display: inline-flex; + align-items: center; + justify-content: center; + gap: 34px; + padding: 0 22px; + color: var(--paper); + background: var(--ink); + border: 1px solid var(--ink); + font-size: 13px; + font-weight: 700; + transition: gap 180ms ease, background 180ms ease; +} + +.primary-button:hover { + gap: 42px; + color: #171a20; + background: var(--acid-bright); + border-color: var(--acid-bright); +} + +.text-button { + padding: 12px 0; + border: 0; + border-bottom: 1px solid var(--line-strong); + background: transparent; + font-size: 13px; +} + +.text-button span { + margin-left: 16px; + color: var(--ink-soft); + font-family: var(--mono); + font-size: 10px; +} + +.hero-signature { + position: relative; + justify-self: end; +} + +.signature-ring { + position: relative; + width: clamp(220px, 25vw, 350px); + aspect-ratio: 1; + display: grid; + place-items: center; + border: 1px solid var(--line-strong); + border-radius: 50%; +} + +.signature-ring::before, +.signature-ring::after { + content: ""; + position: absolute; + background: var(--line-strong); +} + +.signature-ring::before { + top: 50%; + right: -26px; + left: -26px; + height: 1px; +} + +.signature-ring::after { + top: -26px; + bottom: -26px; + left: 50%; + width: 1px; +} + +.signature-y { + z-index: 1; + font-family: var(--serif); + font-size: clamp(130px, 17vw, 230px); + font-style: italic; + line-height: 1; +} + +.signature-dot { + position: absolute; + z-index: 2; + right: 10%; + bottom: 12%; + width: 24px; + height: 24px; + background: var(--orange); + border-radius: 50%; +} + +.hero-signature > p { + margin: 36px 0 0; + color: var(--ink-soft); + font-family: var(--mono); + font-size: 9px; + letter-spacing: 0.15em; + text-align: center; +} + +.hero-stats { + position: relative; + z-index: 2; + width: var(--wrap); + margin-inline: auto; + padding: 25px 0 28px; + display: grid; + grid-template-columns: repeat(3, minmax(110px, 160px)) 1fr; + gap: 30px; + border-top: 1px solid var(--line); +} + +.hero-stats > div { + display: flex; + align-items: baseline; + gap: 9px; +} + +.hero-stats strong { + font-family: var(--serif); + font-size: 29px; + font-weight: 500; +} + +.hero-stats span { + color: var(--ink-soft); + font-size: 11px; +} + +.hero-stats > p { + justify-self: end; + margin: 3px 0 0; + color: var(--ink-soft); + font-family: var(--mono); + font-size: 9px; + letter-spacing: 0.13em; + text-align: right; +} + +/* Sections and category cards */ +.category-section, +.manifesto-section { + padding-block: 120px; +} + +.section-heading { + margin-bottom: 54px; + display: grid; + grid-template-columns: 1fr minmax(280px, 400px); + align-items: end; + gap: 60px; +} + +.section-heading .section-kicker { + margin-bottom: 12px; +} + +.section-heading h2 { + margin: 0; + font-family: var(--serif); + font-size: clamp(38px, 4.4vw, 62px); + font-weight: 500; + letter-spacing: -0.045em; + line-height: 1.08; +} + +.section-heading > p { + margin: 0; + color: var(--ink-soft); + font-size: 14px; + line-height: 1.9; +} + +.category-grid { + display: grid; + grid-template-columns: repeat(3, 1fr); + border-top: 1px solid var(--line-strong); + border-left: 1px solid var(--line-strong); +} + +.category-card { + min-height: 330px; + padding: 28px; + display: flex; + flex-direction: column; + border-right: 1px solid var(--line-strong); + border-bottom: 1px solid var(--line-strong); + background: var(--paper-raised); + transition: color 220ms ease, background 220ms ease, transform 220ms ease; +} + +.category-card:hover { + z-index: 1; + color: #171a20; + background: var(--card-accent, var(--acid)); + transform: translateY(-5px); + box-shadow: var(--shadow); +} + +.category-code { --card-accent: var(--acid); } +.category-ai { --card-accent: var(--blue); } +.category-books { --card-accent: var(--orange); } +.category-films { --card-accent: var(--violet); } +.category-games { --card-accent: var(--yellow); } +.category-essays { --card-accent: var(--green); } + +.category-topline, +.category-bottom, +.latest-meta, +.eyebrow-row, +.article-footer-actions { + display: flex; + align-items: center; + justify-content: space-between; +} + +.category-icon { + width: 44px; + height: 44px; + display: grid; + place-items: center; + border: 1px solid currentColor; + border-radius: 50%; + font-family: var(--serif); + font-size: 22px; +} + +.category-index, +.category-kicker, +.category-bottom, +.latest-number, +.latest-meta, +.toc-label, +.sub-category, +.archive-category { + font-family: var(--mono); + font-size: 10px; + letter-spacing: 0.1em; +} + +.category-index { + color: var(--ink-soft); +} + +.category-card:hover .category-index, +.category-card:hover .category-card > p { + color: rgba(23, 26, 32, 0.66); +} + +.category-kicker { + margin: 50px 0 4px; + color: var(--ink-soft); +} + +.category-card h3 { + margin: 0; + font-family: var(--serif); + font-size: 38px; + font-weight: 500; +} + +.category-card > p:not(.category-kicker) { + max-width: 270px; + margin: 8px 0 28px; + color: var(--ink-soft); + font-size: 13px; +} + +.category-bottom { + margin-top: auto; + padding-top: 22px; + border-top: 1px solid currentColor; +} + +.round-arrow { + width: 34px; + height: 34px; + display: grid; + place-items: center; + border: 1px solid currentColor; + border-radius: 50%; + font-family: var(--sans); + font-size: 16px; + transition: transform 180ms ease; +} + +.category-card:hover .round-arrow { + transform: rotate(45deg); +} + +/* Latest */ +.latest-section { + padding-block: 120px; + color: #f1f0ea; + background: #171a20; +} + +.light-heading .section-kicker, +.latest-meta, +.latest-number, +.latest-item p { + color: #979ba2; +} + +.view-all-link { + justify-self: end; + padding-bottom: 6px; + border-bottom: 1px solid #60646c; + font-size: 13px; +} + +.view-all-link span { + margin-left: 18px; +} + +.latest-list { + border-top: 1px solid #3b3e44; +} + +.latest-item { + padding: 30px 4px; + display: grid; + grid-template-columns: 62px 1fr 50px; + gap: 30px; + align-items: center; + border-bottom: 1px solid #3b3e44; + transition: padding 180ms ease, background 180ms ease; +} + +.latest-item:hover { + padding-inline: 18px; + background: #202329; +} + +.latest-copy { + min-width: 0; +} + +.latest-meta { + width: max-content; + margin-bottom: 9px; + justify-content: flex-start; + gap: 16px; +} + +.latest-meta span { + color: var(--acid-bright); +} + +.latest-item h3 { + margin: 0; + overflow-wrap: anywhere; + font-family: var(--serif); + font-size: clamp(22px, 2.4vw, 34px); + font-weight: 500; + letter-spacing: -0.025em; + line-height: 1.28; +} + +.latest-item p { + max-width: 780px; + margin: 9px 0 0; + overflow: hidden; + display: -webkit-box; + font-size: 12px; + -webkit-box-orient: vertical; + -webkit-line-clamp: 1; +} + +.latest-arrow { + width: 44px; + height: 44px; + display: grid; + place-items: center; + border: 1px solid #4b4f57; + border-radius: 50%; + transition: color 180ms ease, border-color 180ms ease, transform 180ms ease; +} + +.latest-item:hover .latest-arrow { + color: #171a20; + background: var(--acid-bright); + border-color: var(--acid-bright); + transform: rotate(45deg); +} + +/* Manifesto */ +.manifesto-section { + position: relative; + min-height: 620px; + display: grid; + grid-template-columns: 1fr minmax(270px, 0.42fr); + align-items: center; + gap: 100px; +} + +.manifesto-mark { + position: absolute; + top: 82px; + left: 0; + margin: 0; + color: var(--paper-deep); + font-family: var(--serif); + font-size: 220px; + line-height: 1; +} + +.manifesto-section blockquote { + z-index: 1; + margin: 0; +} + +.manifesto-section blockquote p { + margin: 0; + font-family: var(--serif); + font-size: clamp(40px, 5.6vw, 76px); + letter-spacing: -0.05em; + line-height: 1.25; +} + +.manifesto-section em { + position: relative; + font-weight: 400; +} + +.manifesto-section em::after { + content: ""; + position: absolute; + right: 0; + bottom: -9px; + left: 0; + height: 4px; + background: var(--orange); + transform: rotate(-1deg); +} + +.manifesto-note { + align-self: end; + margin-bottom: 35px; +} + +.manifesto-note span { + width: 45px; + height: 2px; + display: block; + margin-bottom: 20px; + background: var(--ink); +} + +.manifesto-note p { + margin: 0; + color: var(--ink-soft); + font-size: 13px; + line-height: 1.9; +} + +/* Listing pages */ +.listing-page { + width: var(--wrap); + min-height: 70vh; + margin-inline: auto; + padding-block: 70px 120px; +} + +.listing-hero { + max-width: 850px; + margin-bottom: 75px; +} + +.back-link { + display: inline-block; + margin-bottom: 60px; + color: var(--ink-soft); + font-family: var(--mono); + font-size: 10px; + letter-spacing: 0.09em; +} + +.back-link:hover { + color: var(--ink); +} + +.listing-hero .section-kicker, +.about-hero .section-kicker { + margin-bottom: 14px; + color: var(--orange); +} + +.listing-title-row { + display: flex; + align-items: flex-start; + gap: 20px; +} + +.listing-title-row h1, +.about-hero h1 { + margin: 0; + font-family: var(--serif); + font-size: clamp(60px, 8vw, 112px); + font-weight: 500; + letter-spacing: -0.065em; + line-height: 0.95; +} + +.listing-title-row > span { + min-width: 40px; + height: 26px; + margin-top: 9px; + display: grid; + place-items: center; + padding-inline: 8px; + color: #171a20; + background: var(--acid); + border-radius: 20px; + font-family: var(--mono); + font-size: 10px; +} + +.listing-hero > p:last-child, +.about-hero > p:last-child { + max-width: 600px; + margin: 27px 0 0; + color: var(--ink-soft); + font-size: 15px; +} + +.listing-content, +.archive-content { + max-width: 980px; + margin-left: auto; +} + +.filter-row { + margin-bottom: 28px; + display: flex; + align-items: center; + justify-content: space-between; + gap: 20px; +} + +.inline-filter { + width: min(100%, 370px); + height: 46px; + display: flex; + align-items: center; + gap: 12px; + padding-inline: 15px; + border: 1px solid var(--line-strong); + background: var(--paper-raised); +} + +.inline-filter svg { + width: 17px; + flex: none; +} + +.inline-filter input { + width: 100%; + border: 0; + outline: 0; + background: transparent; + font-size: 13px; +} + +.filter-row > span { + color: var(--ink-soft); + font-family: var(--mono); + font-size: 10px; +} + +.article-list { + border-top: 1px solid var(--line-strong); +} + +.list-item { + padding: 30px 0; + display: grid; + grid-template-columns: 72px 1fr 46px; + align-items: center; + gap: 28px; + border-bottom: 1px solid var(--line); +} + +.list-item[hidden], +.archive-item[hidden] { + display: none; +} + +.list-item > time { + width: 60px; + height: 68px; + display: grid; + place-content: center; + text-align: center; + border: 1px solid var(--line-strong); +} + +.list-item time strong { + font-family: var(--serif); + font-size: 27px; + font-weight: 500; + line-height: 1; +} + +.list-item time span { + margin-top: 5px; + color: var(--ink-soft); + font-family: var(--mono); + font-size: 8px; +} + +.list-item > div { + min-width: 0; +} + +.sub-category { + color: var(--orange); +} + +.list-item h2 { + margin: 3px 0 0; + overflow-wrap: anywhere; + font-family: var(--serif); + font-size: clamp(20px, 2.5vw, 28px); + font-weight: 500; + letter-spacing: -0.02em; + line-height: 1.3; +} + +.list-item p { + margin: 8px 0 0; + overflow: hidden; + color: var(--ink-soft); + display: -webkit-box; + font-size: 12px; + -webkit-box-orient: vertical; + -webkit-line-clamp: 1; +} + +.item-arrow { + width: 38px; + height: 38px; + display: grid; + place-items: center; + border: 1px solid var(--line); + border-radius: 50%; + transition: transform 180ms ease, background 180ms ease; +} + +.list-item:hover .item-arrow { + color: #171a20; + background: var(--acid); + transform: rotate(45deg); +} + +.empty-state { + padding: 70px 0; + color: var(--ink-soft); + text-align: center; + border-top: 1px solid var(--line); +} + +/* Archive */ +.archive-content { + max-width: 1050px; +} + +.archive-year { + margin: 70px 0 10px; + display: flex; + align-items: center; + gap: 20px; + font-family: var(--serif); + font-size: 42px; + font-weight: 500; +} + +.archive-year span { + height: 1px; + flex: 1; + background: var(--line-strong); +} + +.archive-year[hidden] { + display: none; +} + +.archive-item { + min-height: 74px; + display: grid; + grid-template-columns: 65px 75px 1fr 24px; + align-items: center; + gap: 20px; + border-bottom: 1px solid var(--line); +} + +.archive-item time { + color: var(--ink-soft); + font-family: var(--mono); + font-size: 10px; +} + +.archive-category { + width: max-content; + padding: 4px 7px; + border: 1px solid var(--line-strong); +} + +.archive-item h3 { + margin: 0; + overflow-wrap: anywhere; + font-family: var(--serif); + font-size: 19px; + font-weight: 500; + line-height: 1.35; +} + +.archive-item:hover h3 { + text-decoration: underline; + text-decoration-color: var(--orange); + text-underline-offset: 5px; +} + +/* Article */ +.article-shell { + width: min(1320px, calc(100vw - 48px)); + margin: 0 auto; + padding: 60px 0 120px; + display: grid; + grid-template-columns: minmax(0, 880px) 220px; + justify-content: center; + gap: 70px; +} + +.article-card { + min-width: 0; +} + +.breadcrumbs { + margin-bottom: 65px; + display: flex; + align-items: center; + flex-wrap: wrap; + gap: 9px; + color: var(--ink-soft); + font-family: var(--mono); + font-size: 10px; +} + +.breadcrumbs a:hover { + color: var(--ink); +} + +.article-header { + margin-bottom: 62px; +} + +.eyebrow-row { + justify-content: flex-start; + gap: 17px; +} + +.category-pill { + padding: 5px 9px; + color: #171a20; + background: var(--acid); + font-family: var(--mono); + font-size: 10px; + letter-spacing: 0.08em; +} + +.eyebrow-row time { + color: var(--ink-soft); + font-family: var(--mono); + font-size: 10px; +} + +.article-header h1 { + margin: 23px 0 38px; + overflow-wrap: anywhere; + font-family: var(--serif); + font-size: clamp(42px, 5.8vw, 76px); + font-weight: 500; + letter-spacing: -0.055em; + line-height: 1.12; +} + +.article-rule { + height: 7px; + display: flex; + align-items: center; + background: repeating-linear-gradient(90deg, var(--line-strong) 0 1px, transparent 1px 7px); +} + +.article-rule span { + width: 16%; + height: 7px; + background: var(--orange); +} + +.article-aside { + position: relative; +} + +.toc-card { + position: sticky; + top: calc(var(--header-height) + 38px); + max-height: calc(100vh - var(--header-height) - 76px); + overflow: auto; + padding-left: 20px; + border-left: 1px solid var(--line-strong); + scrollbar-width: thin; +} + +.toc-card[hidden] { + display: none; +} + +.toc-label { + margin: 0 0 18px; + color: var(--ink-soft); + font-weight: 700; +} + +.toc-card nav { + display: grid; + gap: 2px; +} + +.toc-card a { + padding: 5px 0; + color: var(--ink-soft); + font-size: 11px; + line-height: 1.45; + transition: color 160ms ease, transform 160ms ease; +} + +.toc-card a[data-level="3"] { + padding-left: 13px; + font-size: 10px; +} + +.toc-card a:hover, +.toc-card a.is-active { + color: var(--ink); + transform: translateX(3px); +} + +.toc-card a.is-active { + font-weight: 700; +} + +/* Markdown prose */ +.prose { + font-size: 16px; + line-height: 1.9; +} + +.prose > :first-child { + margin-top: 0; +} + +.prose h1, +.prose h2, +.prose h3, +.prose h4, +.prose h5, +.prose h6 { + position: relative; + overflow-wrap: anywhere; + font-family: var(--serif); + font-weight: 600; + letter-spacing: -0.025em; + line-height: 1.35; +} + +.prose h1 { + margin: 2em 0 0.8em; + padding-bottom: 0.35em; + border-bottom: 2px solid var(--ink); + font-size: 2.45em; +} + +.prose h2 { + margin: 2.2em 0 0.75em; + padding-bottom: 0.38em; + border-bottom: 1px solid var(--line-strong); + font-size: 2em; +} + +.prose h2::before { + content: ""; + position: absolute; + bottom: -1px; + left: 0; + width: 54px; + height: 3px; + background: var(--orange); +} + +.prose h3 { + margin: 1.85em 0 0.6em; + font-size: 1.52em; +} + +.prose h4 { + margin: 1.6em 0 0.5em; + font-size: 1.2em; +} + +.prose p, +.prose ul, +.prose ol, +.prose dl { + margin-block: 1.15em; +} + +.prose li + li { + margin-top: 0.35em; +} + +.prose a { + text-decoration: underline; + text-decoration-color: var(--orange); + text-decoration-thickness: 1px; + text-underline-offset: 4px; + transition: color 160ms ease, background 160ms ease; +} + +.prose a:hover { + color: #171a20; + background: var(--acid); +} + +.prose blockquote { + margin: 2em 0; + padding: 19px 24px; + color: var(--ink-soft); + background: var(--paper-deep); + border-left: 4px solid var(--orange); +} + +.prose blockquote > :first-child { margin-top: 0; } +.prose blockquote > :last-child { margin-bottom: 0; } + +.prose code { + padding: 0.16em 0.38em; + color: var(--ink); + background: var(--paper-deep); + border-radius: 3px; + font-family: var(--mono); + font-size: 0.86em; +} + +.prose pre, +.prose .highlight { + max-width: 100%; + overflow: auto; +} + +.prose .highlight { + position: relative; + margin: 2em 0; + color: #e7e7e1; + background: #1d2025; + border: 1px solid #2d3036; +} + +.prose .highlight pre { + margin: 0; + padding: 22px; + background: transparent; +} + +.prose pre:not(.highlight pre) { + position: relative; + margin: 2em 0; + padding: 22px; + color: #e7e7e1; + background: #1d2025; + border: 1px solid #2d3036; +} + +.prose pre code { + padding: 0; + color: inherit; + background: transparent; + border-radius: 0; + font-size: 13px; + line-height: 1.65; +} + +.copy-code { + position: absolute; + top: 8px; + right: 8px; + z-index: 2; + padding: 5px 8px; + color: #b8bbc0; + border: 1px solid #484c53; + background: #262a30; + font-family: var(--mono); + font-size: 9px; + opacity: 0; + transition: opacity 160ms ease; +} + +.highlight:hover .copy-code, +.prose pre:hover > .copy-code, +.copy-code:focus { + opacity: 1; +} + +.prose img { + display: block; + margin: 2em auto; + border: 1px solid var(--line); + box-shadow: var(--shadow); +} + +.prose table { + width: 100%; + margin: 2em 0; + border-collapse: collapse; + display: block; + overflow-x: auto; + font-size: 13px; +} + +.prose th, +.prose td { + min-width: 100px; + padding: 10px 13px; + border: 1px solid var(--line-strong); + text-align: left; +} + +.prose th { + background: var(--paper-deep); +} + +.prose hr { + height: 1px; + margin: 3em 0; + border: 0; + background: var(--line-strong); +} + +.prose details { + margin: 1.5em 0; + padding: 14px 18px; + border: 1px solid var(--line-strong); + background: var(--paper-raised); +} + +.prose summary { + cursor: pointer; + font-weight: 700; +} + +.article-footer { + margin-top: 90px; + padding-top: 35px; + border-top: 1px solid var(--line-strong); +} + +.article-footer > p { + margin: 0 0 30px; + color: var(--ink-soft); + font-family: var(--mono); + font-size: 9px; + letter-spacing: 0.18em; + text-align: center; +} + +.article-footer-actions { + gap: 20px; +} + +.article-footer-actions a { + color: var(--ink-soft); + font-size: 12px; + text-decoration: underline; + text-underline-offset: 5px; +} + +/* About and 404 */ +.about-page { + padding-block: 70px 130px; +} + +.about-hero { + max-width: 930px; + margin-bottom: 100px; +} + +.about-hero h1 span { + position: relative; + font-style: italic; +} + +.about-hero h1 span::after { + content: ""; + position: absolute; + z-index: -1; + right: 0; + bottom: 7px; + left: 0; + height: 16px; + background: var(--acid); +} + +.about-grid { + display: grid; + grid-template-columns: minmax(0, 760px) 300px; + justify-content: space-between; + gap: 80px; +} + +.about-story h2:first-child { + margin-top: 0; +} + +.about-aside { + display: grid; + align-content: start; + gap: 22px; +} + +.about-card { + padding: 23px; + border: 1px solid var(--line-strong); + background: var(--paper-raised); +} + +.about-card > a:not(.project-link) { + padding: 13px 0; + display: flex; + justify-content: space-between; + gap: 15px; + border-bottom: 1px solid var(--line); + font-size: 12px; +} + +.about-card > a:not(.project-link):last-child { + border-bottom: 0; +} + +.about-card a span { + color: var(--ink-soft); +} + +.about-card a b { + font-weight: 500; +} + +.about-card h3 { + margin: 0 0 8px; + font-family: var(--serif); + font-size: 28px; + font-weight: 500; +} + +.about-card > p:not(.toc-label) { + color: var(--ink-soft); + font-size: 12px; +} + +.project-link { + display: inline-block; + margin-top: 12px; + font-size: 12px; + text-decoration: underline; + text-underline-offset: 4px; +} + +.not-found-page { + min-height: 70vh; + padding-block: 90px 130px; + display: flex; + flex-direction: column; + align-items: flex-start; + justify-content: center; +} + +.not-found-code { + margin: 0; + color: var(--paper-deep); + font-family: var(--serif); + font-size: clamp(130px, 24vw, 330px); + line-height: 0.65; +} + +.not-found-page h1 { + margin: 0; + font-family: var(--serif); + font-size: clamp(38px, 5vw, 66px); + font-weight: 500; + letter-spacing: -0.04em; +} + +.not-found-page > p:not(.not-found-code, .section-kicker) { + color: var(--ink-soft); +} + +.not-found-page .primary-button { + margin-top: 24px; +} + +/* Search */ +.search-dialog { + position: fixed; + z-index: 500; + inset: 0; + display: grid; + place-items: start center; + padding: min(12vh, 110px) 20px 30px; + opacity: 0; + visibility: hidden; + transition: opacity 180ms ease, visibility 180ms ease; +} + +.search-dialog.is-open { + opacity: 1; + visibility: visible; +} + +.search-backdrop { + position: absolute; + inset: 0; + width: 100%; + height: 100%; + padding: 0; + border: 0; + background: rgba(10, 12, 15, 0.68); + backdrop-filter: blur(6px); +} + +.search-panel { + position: relative; + width: min(720px, 100%); + max-height: min(720px, 80vh); + display: flex; + flex-direction: column; + overflow: hidden; + color: var(--ink); + background: var(--paper-raised); + border: 1px solid var(--line-strong); + box-shadow: 0 35px 100px rgba(0, 0, 0, 0.3); +} + +.search-box { + height: 68px; + display: flex; + align-items: center; + gap: 14px; + padding-inline: 20px; + border-bottom: 1px solid var(--line-strong); +} + +.search-box input { + min-width: 0; + height: 100%; + flex: 1; + border: 0; + outline: 0; + background: transparent; + font-size: 16px; +} + +.search-esc { + padding: 4px 7px; + color: var(--ink-soft); + border: 1px solid var(--line-strong); + background: transparent; + font-family: var(--mono); + font-size: 9px; +} + +.search-status { + padding: 13px 20px; + color: var(--ink-soft); + border-bottom: 1px solid var(--line); + font-family: var(--mono); + font-size: 9px; + letter-spacing: 0.06em; +} + +.search-results { + overflow: auto; + padding: 8px; +} + +.search-result { + padding: 15px 14px; + display: grid; + grid-template-columns: 1fr 30px; + gap: 16px; + border-bottom: 1px solid var(--line); +} + +.search-result:hover, +.search-result:focus { + outline: 0; + background: var(--paper-deep); +} + +.search-result-meta { + display: flex; + gap: 12px; + color: var(--ink-soft); + font-family: var(--mono); + font-size: 9px; +} + +.search-result-meta span:first-child { + color: var(--orange); +} + +.search-result h3 { + margin: 5px 0 3px; + overflow-wrap: anywhere; + font-family: var(--serif); + font-size: 19px; + font-weight: 500; + line-height: 1.3; +} + +.search-result p { + margin: 0; + overflow: hidden; + color: var(--ink-soft); + display: -webkit-box; + font-size: 11px; + -webkit-box-orient: vertical; + -webkit-line-clamp: 1; +} + +.search-result > span { + align-self: center; +} + +.search-empty { + padding: 70px 20px; + color: var(--ink-soft); + text-align: center; +} + +/* Footer */ +.site-footer { + color: #d7d8d5; + background: #111317; + border-top: 1px solid #2e3137; +} + +.footer-inner { + width: var(--wrap); + min-height: 220px; + margin-inline: auto; + padding-block: 55px 30px; + display: grid; + grid-template-columns: 1fr auto; + grid-template-rows: 1fr auto; + gap: 40px; +} + +.footer-brand { + font-family: var(--serif); + font-size: 27px; +} + +.footer-inner > div:first-child p { + margin: 8px 0 0; + color: #858991; + font-size: 12px; +} + +.footer-links { + display: flex; + gap: 26px; + font-size: 12px; +} + +.footer-links a:hover { + color: var(--acid-bright); +} + +.copyright { + grid-column: 1 / -1; + margin: 0; + padding-top: 22px; + color: #696d75; + border-top: 1px solid #292c31; + font-family: var(--mono); + font-size: 8px; + letter-spacing: 0.08em; +} + +/* Rouge syntax basics */ +.highlight .c, +.highlight .cm, +.highlight .c1 { color: #7f8791; font-style: italic; } +.highlight .k, +.highlight .kd, +.highlight .kn, +.highlight .kp, +.highlight .kr { color: #e697c5; } +.highlight .s, +.highlight .s1, +.highlight .s2 { color: #b7d987; } +.highlight .m, +.highlight .mi, +.highlight .mf { color: #e8ba76; } +.highlight .nf, +.highlight .na { color: #80c7e6; } +.highlight .nc, +.highlight .nt { color: #f0d77e; } +.highlight .o { color: #d7d9dc; } + +@media (max-width: 1020px) { + :root { --wrap: min(100% - 40px, 900px); } + + .hero-inner { + grid-template-columns: 1fr 270px; + gap: 40px; + } + + .hero-copy h1 { font-size: clamp(58px, 8vw, 82px); } + .category-grid { grid-template-columns: repeat(2, 1fr); } + .article-shell { grid-template-columns: minmax(0, 800px); } + .article-aside { display: none; } + .about-grid { grid-template-columns: minmax(0, 1fr) 270px; gap: 45px; } +} + +@media (max-width: 760px) { + :root { + --wrap: calc(100vw - 30px); + --header-height: 68px; + } + + .header-inner { grid-template-columns: 1fr auto; } + .brand-copy small { display: none; } + + .main-nav { + position: fixed; + top: var(--header-height); + right: 0; + left: 0; + height: calc(100svh - var(--header-height)); + padding: 44px 25px; + display: flex; + flex-direction: column; + align-items: flex-start; + gap: 0; + color: #f2f1ec; + background: #171a20; + opacity: 0; + visibility: hidden; + transform: translateY(-10px); + transition: opacity 180ms ease, transform 180ms ease, visibility 180ms ease; + } + + .nav-open .main-nav { + opacity: 1; + visibility: visible; + transform: translateY(0); + } + + .main-nav a { + width: 100%; + padding: 19px 0; + border-bottom: 1px solid #393c42; + font-family: var(--serif); + font-size: 34px; + } + + .main-nav a::after { display: none; } + .nav-toggle { display: grid; } + .search-trigger { width: 40px; border-color: transparent; } + .search-trigger .shortcut { display: none; } + + .home-hero { min-height: auto; } + .hero-grid { background-size: 52px 52px; } + .hero-orbit-one { top: 35%; right: -40%; width: 100vw; } + .hero-orbit-two { display: none; } + + .hero-inner { + margin: 0 auto; + padding: 76px 0 64px; + display: block; + } + + .hero-kicker { margin-bottom: 21px; font-size: 9px; } + .hero-copy h1 { font-size: clamp(48px, 15vw, 68px); line-height: 1.03; } + .hero-intro { margin-top: 27px; font-size: 14px; line-height: 1.85; } + .hero-actions { margin-top: 31px; flex-wrap: wrap; gap: 15px 20px; } + .primary-button { min-height: 48px; } + .hero-signature { display: none; } + + .hero-stats { + padding-block: 20px; + grid-template-columns: repeat(3, 1fr); + gap: 12px; + } + + .hero-stats > div { display: grid; gap: 0; } + .hero-stats strong { font-size: 24px; } + .hero-stats > p { display: none; } + + .category-section, + .manifesto-section, + .latest-section { padding-block: 80px; } + + .section-heading { + margin-bottom: 36px; + display: block; + } + + .section-heading h2 { font-size: 42px; } + .section-heading > p { margin-top: 18px; } + .category-grid { grid-template-columns: 1fr; } + .category-card { min-height: 285px; } + .category-kicker { margin-top: 36px; } + + .light-heading .view-all-link { + display: inline-block; + margin-top: 20px; + } + + .latest-item { + padding: 24px 0; + grid-template-columns: 32px 1fr 32px; + gap: 10px; + } + + .latest-item:hover { padding-inline: 7px; } + .latest-item h3 { font-size: 22px; } + .latest-item p { display: none; } + .latest-arrow { width: 30px; height: 30px; font-size: 12px; } + + .manifesto-section { + min-height: 500px; + display: block; + } + + .manifesto-mark { top: 35px; font-size: 150px; } + .manifesto-section blockquote p { font-size: 41px; } + .manifesto-note { max-width: 330px; margin: 70px 0 0 auto; } + + .listing-page, + .about-page { padding-block: 45px 90px; } + .back-link { margin-bottom: 45px; } + .listing-hero { margin-bottom: 55px; } + .listing-title-row h1, + .about-hero h1 { font-size: 65px; } + .listing-content, + .archive-content { margin: 0; } + + .list-item { + grid-template-columns: 58px 1fr 30px; + gap: 12px; + } + + .list-item > time { width: 52px; height: 60px; } + .list-item p { display: none; } + .item-arrow { width: 29px; height: 29px; font-size: 11px; } + + .archive-item { + padding-block: 16px; + grid-template-columns: 45px 1fr 20px; + gap: 10px; + } + + .archive-category { display: none; } + .archive-item h3 { font-size: 17px; } + + .article-shell { + width: var(--wrap); + padding: 42px 0 90px; + } + + .breadcrumbs { margin-bottom: 45px; } + .article-header { margin-bottom: 45px; } + .article-header h1 { margin-top: 18px; font-size: 43px; } + .prose { font-size: 15px; line-height: 1.85; } + .prose h1 { font-size: 2em; } + .prose h2 { font-size: 1.7em; } + .prose h3 { font-size: 1.35em; } + .prose .highlight, + .prose pre:not(.highlight pre) { margin-right: -15px; margin-left: -15px; border-right: 0; border-left: 0; } + .copy-code { opacity: 1; } + .article-footer-actions { align-items: flex-start; flex-direction: column; } + + .about-hero { margin-bottom: 65px; } + .about-grid { display: block; } + .about-aside { margin-top: 60px; } + + .footer-inner { + min-height: 250px; + grid-template-columns: 1fr; + gap: 27px; + } + + .footer-links { align-self: start; } + .copyright { grid-column: 1; } +} + +@media (prefers-reduced-motion: reduce) { + *, + *::before, + *::after { + scroll-behavior: auto !important; + transition-duration: 0.01ms !important; + animation-duration: 0.01ms !important; + animation-iteration-count: 1 !important; + } +} diff --git a/assets/images/favicon.svg b/assets/images/favicon.svg new file mode 100644 index 0000000..be4edb5 --- /dev/null +++ b/assets/images/favicon.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/assets/js/main.js b/assets/js/main.js new file mode 100644 index 0000000..301028d --- /dev/null +++ b/assets/js/main.js @@ -0,0 +1,274 @@ +(function () { + 'use strict'; + + var root = document.documentElement; + var body = document.body; + var baseurl = root.dataset.baseurl || ''; + + function all(selector, context) { + return Array.prototype.slice.call((context || document).querySelectorAll(selector)); + } + + // Color theme + var themeToggle = document.querySelector('[data-theme-toggle]'); + var themeColor = document.querySelector('meta[name="theme-color"]'); + + function applyTheme(theme) { + root.dataset.theme = theme; + localStorage.setItem('yano-theme', theme); + if (themeColor) themeColor.setAttribute('content', theme === 'dark' ? '#141619' : '#f6f4ef'); + } + + if (themeToggle) { + themeToggle.addEventListener('click', function () { + applyTheme(root.dataset.theme === 'dark' ? 'light' : 'dark'); + }); + } + + // Mobile navigation + var navToggle = document.querySelector('[data-nav-toggle]'); + if (navToggle) { + navToggle.addEventListener('click', function () { + var willOpen = !body.classList.contains('nav-open'); + body.classList.toggle('nav-open', willOpen); + navToggle.setAttribute('aria-expanded', String(willOpen)); + navToggle.setAttribute('aria-label', willOpen ? '关闭导航' : '打开导航'); + }); + } + + // Search dialog and client-side index + var searchDialog = document.querySelector('[data-search-dialog]'); + var searchInput = document.querySelector('[data-search-input]'); + var searchResults = document.querySelector('[data-search-results]'); + var searchStatus = document.querySelector('[data-search-status]'); + var searchIndex = null; + var searchPromise = null; + var lastFocused = null; + + function loadSearchIndex() { + if (searchIndex) return Promise.resolve(searchIndex); + if (!searchPromise) { + searchPromise = fetch(baseurl + '/search.json') + .then(function (response) { + if (!response.ok) throw new Error('Search index request failed'); + return response.json(); + }) + .then(function (data) { + searchIndex = data; + return data; + }) + .catch(function () { + searchStatus.textContent = '搜索索引加载失败,请刷新页面后重试'; + return []; + }); + } + return searchPromise; + } + + function openSearch() { + if (!searchDialog) return; + lastFocused = document.activeElement; + searchDialog.classList.add('is-open'); + searchDialog.setAttribute('aria-hidden', 'false'); + body.classList.add('search-open'); + loadSearchIndex().then(function () { + renderSearch(searchInput.value); + }); + window.setTimeout(function () { searchInput.focus(); }, 30); + } + + function closeSearch() { + if (!searchDialog) return; + searchDialog.classList.remove('is-open'); + searchDialog.setAttribute('aria-hidden', 'true'); + body.classList.remove('search-open'); + if (lastFocused && typeof lastFocused.focus === 'function') lastFocused.focus(); + } + + function makeResult(article) { + var link = document.createElement('a'); + link.className = 'search-result'; + link.href = article.url; + + var copy = document.createElement('div'); + var meta = document.createElement('div'); + meta.className = 'search-result-meta'; + var category = document.createElement('span'); + category.textContent = article.category; + var date = document.createElement('span'); + date.textContent = article.date; + meta.appendChild(category); + meta.appendChild(date); + + var title = document.createElement('h3'); + title.textContent = article.title; + var excerpt = document.createElement('p'); + excerpt.textContent = article.excerpt; + copy.appendChild(meta); + copy.appendChild(title); + copy.appendChild(excerpt); + + var arrow = document.createElement('span'); + arrow.setAttribute('aria-hidden', 'true'); + arrow.textContent = '↗'; + link.appendChild(copy); + link.appendChild(arrow); + return link; + } + + function renderSearch(rawQuery) { + if (!searchIndex || !searchResults) return; + var query = rawQuery.trim().toLocaleLowerCase('zh-CN'); + var ranked = searchIndex.map(function (article, index) { + var title = article.title.toLocaleLowerCase('zh-CN'); + var category = article.category.toLocaleLowerCase('zh-CN'); + var excerpt = article.excerpt.toLocaleLowerCase('zh-CN'); + var score = 0; + if (!query) score = Math.max(1, 100 - index); + if (title === query) score += 1000; + if (title.indexOf(query) !== -1) score += 300; + if (title.indexOf(query) === 0) score += 180; + if (category.indexOf(query) !== -1) score += 90; + if (excerpt.indexOf(query) !== -1) score += 30; + return { article: article, score: score }; + }).filter(function (item) { + return item.score > 0; + }).sort(function (a, b) { + return b.score - a.score; + }).slice(0, query ? 14 : 8); + + searchResults.replaceChildren(); + if (!ranked.length) { + var empty = document.createElement('p'); + empty.className = 'search-empty'; + empty.textContent = '没有找到与“' + rawQuery.trim() + '”相关的文章'; + searchResults.appendChild(empty); + searchStatus.textContent = '0 条结果'; + return; + } + + ranked.forEach(function (item) { + searchResults.appendChild(makeResult(item.article)); + }); + searchStatus.textContent = query ? '找到 ' + ranked.length + ' 条相关结果' : '最近更新'; + } + + all('[data-search-open]').forEach(function (button) { + button.addEventListener('click', openSearch); + }); + all('[data-search-close]').forEach(function (button) { + button.addEventListener('click', closeSearch); + }); + if (searchInput) { + searchInput.addEventListener('input', function () { renderSearch(searchInput.value); }); + } + + document.addEventListener('keydown', function (event) { + var tag = document.activeElement && document.activeElement.tagName; + var typing = tag === 'INPUT' || tag === 'TEXTAREA' || (document.activeElement && document.activeElement.isContentEditable); + if ((event.key === '/' && !typing) || ((event.metaKey || event.ctrlKey) && event.key.toLowerCase() === 'k')) { + event.preventDefault(); + openSearch(); + } + if (event.key === 'Escape') { + if (body.classList.contains('search-open')) closeSearch(); + if (body.classList.contains('nav-open') && navToggle) navToggle.click(); + } + }); + + // Category and archive filters + all('[data-list-filter]').forEach(function (input) { + var section = input.closest('section') || document; + var list = section.querySelector('[data-filter-list]'); + var items = all('[data-filter-item]', list); + var count = section.querySelector('[data-list-count]'); + var empty = section.querySelector('[data-filter-empty]'); + + function updateYearHeadings() { + all('[data-year-heading]', list).forEach(function (heading) { + var sibling = heading.nextElementSibling; + var hasVisibleItem = false; + while (sibling && !sibling.hasAttribute('data-year-heading')) { + if (sibling.hasAttribute('data-filter-item') && !sibling.hidden) hasVisibleItem = true; + sibling = sibling.nextElementSibling; + } + heading.hidden = !hasVisibleItem; + }); + } + + input.addEventListener('input', function () { + var query = input.value.trim().toLocaleLowerCase('zh-CN'); + var visible = 0; + items.forEach(function (item) { + var matches = !query || (item.dataset.searchText || '').indexOf(query) !== -1; + item.hidden = !matches; + if (matches) visible += 1; + }); + if (count) count.textContent = query ? '找到 ' + visible + ' 篇' : '共 ' + items.length + ' 篇'; + if (empty) empty.hidden = visible !== 0; + updateYearHeadings(); + }); + }); + + // Article enhancements: lazy images, table of contents, copy buttons. + var article = document.querySelector('[data-article-content]'); + if (article) { + all('img', article).forEach(function (image) { + image.loading = 'lazy'; + image.decoding = 'async'; + }); + + all('a[href^="http"]', article).forEach(function (link) { + if (link.hostname !== window.location.hostname) { + link.target = '_blank'; + link.rel = 'noopener noreferrer'; + } + }); + + var headings = all('h2, h3', article); + var toc = document.querySelector('[data-toc]'); + var tocCard = document.querySelector('[data-toc-card]'); + if (toc && headings.length > 1) { + headings.forEach(function (heading, index) { + if (!heading.id) heading.id = 'section-' + (index + 1); + var link = document.createElement('a'); + link.href = '#' + heading.id; + link.dataset.level = heading.tagName.slice(1); + link.textContent = heading.textContent; + toc.appendChild(link); + }); + + if ('IntersectionObserver' in window) { + var tocLinks = all('a', toc); + var observer = new IntersectionObserver(function (entries) { + entries.forEach(function (entry) { + if (!entry.isIntersecting) return; + tocLinks.forEach(function (link) { link.classList.remove('is-active'); }); + var active = toc.querySelector('a[href="#' + CSS.escape(entry.target.id) + '"]'); + if (active) active.classList.add('is-active'); + }); + }, { rootMargin: '-15% 0px -75% 0px' }); + headings.forEach(function (heading) { observer.observe(heading); }); + } + } else if (tocCard) { + tocCard.hidden = true; + } + + all('.highlight, pre:not(.highlight pre)', article).forEach(function (block) { + var pre = block.matches('pre') ? block : block.querySelector('pre'); + if (!pre || block.querySelector('.copy-code')) return; + var button = document.createElement('button'); + button.type = 'button'; + button.className = 'copy-code'; + button.textContent = 'COPY'; + button.setAttribute('aria-label', '复制代码'); + button.addEventListener('click', function () { + navigator.clipboard.writeText(pre.innerText).then(function () { + button.textContent = 'COPIED'; + window.setTimeout(function () { button.textContent = 'COPY'; }, 1400); + }); + }); + block.appendChild(button); + }); + } +})(); diff --git a/categories/ai.html b/categories/ai.html new file mode 100644 index 0000000..2e79fc0 --- /dev/null +++ b/categories/ai.html @@ -0,0 +1,8 @@ +--- +layout: category +title: AI +permalink: /categories/ai/ +category_path: AI/ +kicker: ARTIFICIAL INTELLIGENCE +description: 关注 Agent、MCP、AI 论文,以及智能工具带来的新工作方式。 +--- diff --git a/categories/books.html b/categories/books.html new file mode 100644 index 0000000..07dda12 --- /dev/null +++ b/categories/books.html @@ -0,0 +1,8 @@ +--- +layout: category +title: 读书 +permalink: /categories/books/ +category_path: 读书/ +kicker: READING & NOTES +description: 从技术经典到人文社科,留下值得反复阅读的片段与思考。 +--- diff --git a/categories/code.html b/categories/code.html new file mode 100644 index 0000000..65a1249 --- /dev/null +++ b/categories/code.html @@ -0,0 +1,8 @@ +--- +layout: category +title: 编程 +permalink: /categories/code/ +category_path: 编程/ +kicker: CODE & ENGINEERING +description: 从语言特性到源码实现,记录工程实践背后的原理。 +--- diff --git a/categories/essays.html b/categories/essays.html new file mode 100644 index 0000000..82c79f3 --- /dev/null +++ b/categories/essays.html @@ -0,0 +1,8 @@ +--- +layout: category +title: 随笔 +permalink: /categories/essays/ +category_path: 随笔/ +kicker: LIFE & THOUGHTS +description: 关于生活、工作、成长与时间的零散记录。 +--- diff --git a/categories/films.html b/categories/films.html new file mode 100644 index 0000000..3333038 --- /dev/null +++ b/categories/films.html @@ -0,0 +1,8 @@ +--- +layout: category +title: 观影 +permalink: /categories/films/ +category_path: 观影/ +kicker: FILMS & STORIES +description: 电影、剧集与年度观影回顾,记录故事留下的回声。 +--- diff --git a/categories/games.html b/categories/games.html new file mode 100644 index 0000000..edbc68b --- /dev/null +++ b/categories/games.html @@ -0,0 +1,8 @@ +--- +layout: category +title: 游戏 +permalink: /categories/games/ +category_path: 游戏/ +kicker: GAMES & WORLDS +description: JRPG、任天堂和那些让人愿意在另一个世界停留的作品。 +--- diff --git a/feed.xml b/feed.xml new file mode 100644 index 0000000..e10f83e --- /dev/null +++ b/feed.xml @@ -0,0 +1,27 @@ +--- +layout: null +permalink: /feed.xml +--- + + + {{ site.title | xml_escape }} + {{ site.description | xml_escape }} + + + {{ '/' | absolute_url }} + {% assign articles = site.pages | where_exp: 'item', 'item.date != nil' | sort: 'date' | reverse %} + {% assign latest = articles | first %} + {{ latest.date | date_to_xmlschema }} + {{ site.author | xml_escape }} + {% for article in articles limit: 30 %} + {% assign article_title = article.title | default: article.name | replace: '.md', '' %} + + {{ article_title | xml_escape }} + + {{ article.url | absolute_url }} + {{ article.date | date_to_xmlschema }} + {{ article.date | date_to_xmlschema }} + {{ article.content | strip_html | normalize_whitespace | truncate: 500 | xml_escape }} + + {% endfor %} + diff --git a/index.html b/index.html new file mode 100644 index 0000000..500405b --- /dev/null +++ b/index.html @@ -0,0 +1,110 @@ +--- +layout: default +title: 首页 +description: Yano 的个人知识博客,记录编程、AI、读书、观影、游戏与生活。 +body_class: home-page +--- +{% assign articles = site.pages | where_exp: 'item', 'item.date != nil' | sort: 'date' | reverse %} +
+
+ + + +
+
+

PERSONAL KNOWLEDGE ARCHIVE

+

把好奇心
写成一张知识地图

+

在代码、书影音与生活之间持续探索。这里存放技术原理、阅读痕迹,以及那些值得被认真记住的瞬间。

+
+ 开始阅读 ↓ + +
+
+ +
+
+
{{ articles.size }}篇文章
+
{{ site.data.categories.size }}个主题
+
10+年记录
+

THINK DEEPLY
LEARN CONTINUOUSLY

+
+
+ +
+
+
+

EXPLORE BY TOPIC

+

沿着兴趣,继续探索

+
+

知识并不生长在孤岛上。技术、故事和生活经验,总会在某处彼此照亮。

+
+ +
+ {% for category in site.data.categories %} + {% assign category_articles = site.pages | where_exp: 'item', 'item.date != nil and item.path contains category.path' %} + +
+ + 0{{ forloop.index }} +
+

{{ category.kicker }}

+

{{ category.name }}

+

{{ category.description }}

+
+ {{ category_articles.size }} ARTICLES + +
+
+ {% endfor %} +
+
+ +
+
+
+
+

LATEST WRITING

+

最近写下的

+
+ 查看全部 {{ articles.size }} 篇 → +
+ +
+ {% for article in articles limit: 10 %} + {% assign article_title = article.title | default: article.name | replace: '.md', '' %} + {% assign parts = article.path | split: '/' %} + {% assign article_category = parts[0] %} + + {% if forloop.index < 10 %}0{% endif %}{{ forloop.index }} +
+
+ {{ article_category }} + +
+

{{ article_title }}

+

{{ article.content | strip_html | strip_newlines | normalize_whitespace | truncate: 140 }}

+
+ +
+ {% endfor %} +
+
+
+ +
+ +
+

随心写,长期写。
内容可以繁杂,思考始终贵在坚持。

+
+
+ +

这个博客起源于一次《Java 编程思想》的阅读,后来逐渐越过技术的边界,成为一份持续生长的个人知识档案。

+
+
+
diff --git a/robots.txt b/robots.txt new file mode 100644 index 0000000..e5bff18 --- /dev/null +++ b/robots.txt @@ -0,0 +1,8 @@ +--- +layout: null +permalink: /robots.txt +--- +User-agent: * +Allow: / + +Sitemap: {{ '/sitemap.xml' | absolute_url }} diff --git a/scripts/update_readme_nav.py b/scripts/update_readme_nav.py index 945cd88..f465714 100644 --- a/scripts/update_readme_nav.py +++ b/scripts/update_readme_nav.py @@ -160,11 +160,11 @@ def generate_nav_block() -> str: custom_order = ["观影", "AI", "编程", "游戏", "读书", "随笔"] def sort_key(p): - # For directories in custom_order, use their index - # For others, use len(custom_order) + their name for alphabetical sorting + # Always return the same type so known and unknown directories remain + # comparable on every supported Python version. if p.name in custom_order: - return custom_order.index(p.name) - return len(custom_order), p.name + return 0, custom_order.index(p.name) + return 1, p.name.casefold() for top_dir in sorted( ( @@ -270,4 +270,3 @@ def main() -> None: if __name__ == "__main__": main() - diff --git a/search.json b/search.json new file mode 100644 index 0000000..0a01f34 --- /dev/null +++ b/search.json @@ -0,0 +1,18 @@ +--- +layout: null +permalink: /search.json +--- +{% assign articles = site.pages | where_exp: 'item', 'item.date != nil' | sort: 'date' | reverse %} +[ +{% for article in articles %} + {% assign article_title = article.title | default: article.name | replace: '.md', '' %} + {% assign parts = article.path | split: '/' %} + { + "title": {{ article_title | jsonify }}, + "url": {{ article.url | relative_url | jsonify }}, + "category": {{ parts[0] | jsonify }}, + "date": {{ article.date | date: '%Y.%m.%d' | jsonify }}, + "excerpt": {{ article.content | strip_html | strip_newlines | normalize_whitespace | truncate: 240 | jsonify }} + }{% unless forloop.last %},{% endunless %} +{% endfor %} +] diff --git a/sitemap.xml b/sitemap.xml new file mode 100644 index 0000000..9eac287 --- /dev/null +++ b/sitemap.xml @@ -0,0 +1,20 @@ +--- +layout: null +permalink: /sitemap.xml +--- + + + {% assign articles = site.pages | where_exp: 'item', 'item.date != nil' %} + {% for article in articles %} + + {{ article.url | absolute_url | xml_escape }} + {{ article.date | date_to_xmlschema }} + + {% endfor %} + {{ '/' | absolute_url | xml_escape }} + {{ '/archive/' | absolute_url | xml_escape }} + {{ '/about/' | absolute_url | xml_escape }} + {% for category in site.data.categories %} + {{ '/categories/' | append: category.slug | append: '/' | absolute_url | xml_escape }} + {% endfor %} + diff --git "a/\347\274\226\347\250\213/Java/JDK 14 \345\215\263\345\260\206\345\217\221\345\270\203\357\274\214\344\275\240\346\211\200\350\246\201\347\237\245\351\201\223\347\232\204\351\203\275\345\234\250\350\277\231\351\207\214\357\274\201.md" "b/\347\274\226\347\250\213/Java/JDK 14 \345\215\263\345\260\206\345\217\221\345\270\203\357\274\214\344\275\240\346\211\200\350\246\201\347\237\245\351\201\223\347\232\204\351\203\275\345\234\250\350\277\231\351\207\214\357\274\201.md" index e68f83e..46adff8 100644 --- "a/\347\274\226\347\250\213/Java/JDK 14 \345\215\263\345\260\206\345\217\221\345\270\203\357\274\214\344\275\240\346\211\200\350\246\201\347\237\245\351\201\223\347\232\204\351\203\275\345\234\250\350\277\231\351\207\214\357\274\201.md" +++ "b/\347\274\226\347\250\213/Java/JDK 14 \345\215\263\345\260\206\345\217\221\345\270\203\357\274\214\344\275\240\346\211\200\350\246\201\347\237\245\351\201\223\347\232\204\351\203\275\345\234\250\350\277\231\351\207\214\357\274\201.md" @@ -452,7 +452,7 @@ RecordComponent: {Annotation} UnannType Identifier RecordBody: - {{RecordBodyDeclaration} } + {% raw %}{{RecordBodyDeclaration} }{% endraw %} RecordBodyDeclaration: ClassBodyDeclaration @@ -907,6 +907,5 @@ try (MemorySegment segment = MemorySegment.allocateNative(100)) { - diff --git "a/\347\274\226\347\250\213/Java/JDK 15 \345\267\262\345\217\221\345\270\203\357\274\214\344\275\240\346\211\200\350\246\201\347\237\245\351\201\223\347\232\204\351\203\275\345\234\250\350\277\231\351\207\214\357\274\201.md" "b/\347\274\226\347\250\213/Java/JDK 15 \345\267\262\345\217\221\345\270\203\357\274\214\344\275\240\346\211\200\350\246\201\347\237\245\351\201\223\347\232\204\351\203\275\345\234\250\350\277\231\351\207\214\357\274\201.md" index 7dfb74e..1e808c7 100644 --- "a/\347\274\226\347\250\213/Java/JDK 15 \345\267\262\345\217\221\345\270\203\357\274\214\344\275\240\346\211\200\350\246\201\347\237\245\351\201\223\347\232\204\351\203\275\345\234\250\350\277\231\351\207\214\357\274\201.md" +++ "b/\347\274\226\347\250\213/Java/JDK 15 \345\267\262\345\217\221\345\270\203\357\274\214\344\275\240\346\211\200\350\246\201\347\237\245\351\201\223\347\232\204\351\203\275\345\234\250\350\277\231\351\207\214\357\274\201.md" @@ -458,7 +458,7 @@ RecordComponent: {Annotation} UnannType Identifier RecordBody: - {{RecordBodyDeclaration} } + {% raw %}{{RecordBodyDeclaration} }{% endraw %} RecordBodyDeclaration: ClassBodyDeclaration diff --git "a/\347\274\226\347\250\213/Java/Java Features from Java 8 to Java 17.md" "b/\347\274\226\347\250\213/Java/Java Features from Java 8 to Java 17.md" index ae4fb7b..a5531c9 100644 --- "a/\347\274\226\347\250\213/Java/Java Features from Java 8 to Java 17.md" +++ "b/\347\274\226\347\250\213/Java/Java Features from Java 8 to Java 17.md" @@ -385,8 +385,6 @@ First, we will go with a simple example. We will build a Hello World application Since I am working in the IntelliJ IDEA there is something that we need to understand first. IntelliJ IDEA has the concept of modules. For it to work, each Java module has to correspond to one IntelliJ module. -![Package structure!](../assets/img/posts/java-release-notes/package-structure.png "Package structure") - We have two modules: `hello.module` and `world.module`. They correspond to `hello` and `world` IntelliJ modules, respectively. Inside each of them, we have created the `module-info.java` file. This file defines our Java module. Inside, we declare which packages we need to export and on which modules we are dependent. #### Defining our First Module @@ -990,4 +988,4 @@ Several constraints have to be met for the sealed class to work: More details about sealed classes can be found in the [docs](https://docs.oracle.com/en/java/javase/17/language/sealed-classes-and-interfaces.html). -文章原文链接:https://reflectoring.io/java-release-notes/#diamond-syntax-with-inner-anonymous-classes \ No newline at end of file +文章原文链接:https://reflectoring.io/java-release-notes/#diamond-syntax-with-inner-anonymous-classes diff --git "a/\347\274\226\347\250\213/Java/Java Stream \346\272\220\347\240\201\345\210\206\346\236\220.md" "b/\347\274\226\347\250\213/Java/Java Stream \346\272\220\347\240\201\345\210\206\346\236\220.md" index 9c1c30a..37a2130 100644 --- "a/\347\274\226\347\250\213/Java/Java Stream \346\272\220\347\240\201\345\210\206\346\236\220.md" +++ "b/\347\274\226\347\250\213/Java/Java Stream \346\272\220\347\240\201\345\210\206\346\236\220.md" @@ -431,7 +431,7 @@ public void testParallelRight() {
OSCentOS 6.7 x86_64
CPUIntel Xeon X5675, 12M Cache 3.06 GHz, 6 Cores 12 Threads
内存 96GB
JDKjava version 1.8.0_91, Java HotSpot(TM) 64-Bit Server VM
-测试 [所用代码在这里](./perf/StreamBenchmark/src/lee),测试 [结果汇总](./perf/Stream_performance.xlsx). +测试所用代码与结果汇总文件已不在当前仓库中,下面保留测试方法和结果截图。 ## 测试方法和测试数据 @@ -448,7 +448,7 @@ Stream 并行执行时用到 `ForkJoinPool.commonPool()` 得到的线程池, 测试内容:找出整型数组中的最小值。对比 for 循环外部迭代和 Stream API 内部迭代性能。 -测试程序 [IntTest](./perf/StreamBenchmark/src/lee/IntTest.java),测试结果如下图: +测试程序 `IntTest`,测试结果如下图: ![](http://yano.oss-cn-beijing.aliyuncs.com/2020-12-03-074737.jpg) @@ -474,7 +474,7 @@ Stream 并行执行时用到 `ForkJoinPool.commonPool()` 得到的线程池, 测试内容:找出字符串列表中最小的元素(自然顺序),对比 for 循环外部迭代和 Stream API 内部迭代性能。 -测试程序 [StringTest](./perf/StreamBenchmark/src/lee/StringTest.java),测试结果如下图: +测试程序 `StringTest`,测试结果如下图: ![](http://yano.oss-cn-beijing.aliyuncs.com/2020-12-03-074848.jpg) @@ -500,7 +500,7 @@ Stream 并行执行时用到 `ForkJoinPool.commonPool()` 得到的线程池, 测试内容:给定订单列表,统计每个用户的总交易额。对比使用外部迭代手动实现和 Stream API 之间的性能。 -我们将订单简化为 `` 构成的元组,并用 `Order` 对象来表示。测试程序 [ReductionTest](./perf/StreamBenchmark/src/lee/ReductionTest.java),测试结果如下图: +我们将订单简化为 `` 构成的元组,并用 `Order` 对象来表示。测试程序 `ReductionTest`,测试结果如下图: ![](http://yano.oss-cn-beijing.aliyuncs.com/2020-12-03-074920.jpg) @@ -550,4 +550,4 @@ Stream 并行执行时用到 `ForkJoinPool.commonPool()` 得到的线程池, 1. [JavaLambdaInternals/6-Stream Pipelines.md](https://github.com/CarpenterLee/JavaLambdaInternals/blob/master/6-Stream%20Pipelines.md) 2. [JavaLambdaInternals/8-Stream Performance.md](https://github.com/CarpenterLee/JavaLambdaInternals/blob/master/8-Stream%20Performance.md) -3. 极客时间 - Java 性能调优实战 / 06.Stream 如何提高遍历集合效率? \ No newline at end of file +3. 极客时间 - Java 性能调优实战 / 06.Stream 如何提高遍历集合效率? diff --git "a/\347\274\226\347\250\213/Java/Java\350\265\204\346\272\220\345\244\247\345\205\250\344\270\255\346\226\207\347\211\210.md" "b/\347\274\226\347\250\213/Java/Java\350\265\204\346\272\220\345\244\247\345\205\250\344\270\255\346\226\207\347\211\210.md" index a981c46..c41bd04 100644 --- "a/\347\274\226\347\250\213/Java/Java\350\265\204\346\272\220\345\244\247\345\205\250\344\270\255\346\226\207\347\211\210.md" +++ "b/\347\274\226\347\250\213/Java/Java\350\265\204\346\272\220\345\244\247\345\205\250\344\270\255\346\226\207\347\211\210.md" @@ -211,7 +211,7 @@ Awesome 系列虽然挺全,但基本只对收录的资源做了极为简要的 * [Bamboo](http://www.importnew.com/bamboo/):Atlassian解决方案,可以很好地集成Atlassian的其他产品。可以选择开源许可,也可以购买商业版。[官网](https://www.atlassian.com/software/bamboo) * CircleCI:提供托管服务,可以免费试用。[官网](https://circleci.com/) * [Codeship](http://www.importnew.com/codeship/):提供托管服务,提供有限的免费模式。[官网](https://codeship.com/features) -* [fabric8](hao.importnew.com/fabric8/):容器集成平台。[官网](http://fabric8.io/) +* [fabric8](http://www.importnew.com/fabric8/):容器集成平台。[官网](http://fabric8.io/) * [Go](http://www.importnew.com/go/):ThoughtWork开源解决方案。[官网](https://www.gocd.io/) * [Jenkins](http://www.importnew.com/jenkins/):支持基于服务器的部署服务。[官网](http://jenkins-ci.org/) * [TeamCity](http://www.importnew.com/teamcity/):JetBrain的持续集成解决方案,有免费版。[官网](http://www.jetbrains.com/teamcity/) @@ -783,4 +783,4 @@ Awesome 系列虽然挺全,但基本只对收录的资源做了极为简要的 * [Vanilla Java](http://vanillajava.blogspot.ch/) * [Vlad Mihalcea on Hibernate](http://vladmihalcea.com/) * [Voxxed](https://www.voxxed.com/) -* [OnJava](http://www.importnew.com/onjava/):O'Reilly Java包含最新的Java技术资讯,优质代码,完全的实例和详解。[官网](http://www.onjava.com/) \ No newline at end of file +* [OnJava](http://www.importnew.com/onjava/):O'Reilly Java包含最新的Java技术资讯,优质代码,完全的实例和详解。[官网](http://www.onjava.com/) diff --git "a/\347\274\226\347\250\213/Java/Netty HashedWheelTimer \346\227\266\351\227\264\350\275\256\346\272\220\347\240\201\350\257\246\350\247\243.md" "b/\347\274\226\347\250\213/Java/Netty HashedWheelTimer \346\227\266\351\227\264\350\275\256\346\272\220\347\240\201\350\257\246\350\247\243.md" index 021d2f4..25376dc 100644 --- "a/\347\274\226\347\250\213/Java/Netty HashedWheelTimer \346\227\266\351\227\264\350\275\256\346\272\220\347\240\201\350\257\246\350\247\243.md" +++ "b/\347\274\226\347\250\213/Java/Netty HashedWheelTimer \346\227\266\351\227\264\350\275\256\346\272\220\347\240\201\350\257\246\350\247\243.md" @@ -43,11 +43,11 @@ public void test() throws InterruptedException { 官方的 4.0 版本的 doc 文档:[https://netty.io/4.0/api/io/netty/util/HashedWheelTimer.html](https://netty.io/4.0/api/io/netty/util/HashedWheelTimer.html) -
A Timer optimized for approximated I/O timeout scheduling. +
A Timer optimized for approximated I/O timeout scheduling.

Tick Duration

As described with 'approximated', this timer does not execute the scheduled -TimerTask on time. HashedWheelTimer, on every tick, will -check if there are any TimerTasks behind the schedule and execute +TimerTask on time. HashedWheelTimer, on every tick, will +check if there are any TimerTasks behind the schedule and execute them.

You can increase or decrease the accuracy of the execution timing by @@ -56,18 +56,18 @@ network applications, I/O timeout does not need to be accurate. Therefore, the default tick duration is 100 milliseconds and you will not need to try different configurations in most cases.

Ticks per Wheel (Wheel Size)

-HashedWheelTimer maintains a data structure called 'wheel'. -To put simply, a wheel is a hash table of TimerTasks whose hash +HashedWheelTimer maintains a data structure called 'wheel'. +To put simply, a wheel is a hash table of TimerTasks whose hash function is 'dead line of the task'. The default number of ticks per wheel (i.e. the size of the wheel) is 512. You could specify a larger value if you are going to schedule a lot of timeouts.

Do not create many instances.

-HashedWheelTimer creates a new thread whenever it is instantiated and +HashedWheelTimer creates a new thread whenever it is instantiated and started. Therefore, you should make sure to create only one instance and share it across your application. One of the common mistakes, that makes your application unresponsive, is to create a new instance for every connection.

Implementation Details

-HashedWheelTimer is based on +HashedWheelTimer is based on George Varghese and Tony Lauck's paper, 'Hashed @@ -488,4 +488,4 @@ private void transferTimeoutsToBuckets() { # 参考链接 - [HashedWheelTimer 使用及源码分析](https://www.javadoop.com/post/HashedWheelTimer) -- [HashedWheelTimer 时间轮原理分析](https://albenw.github.io/posts/ec8df8c/) \ No newline at end of file +- [HashedWheelTimer 时间轮原理分析](https://albenw.github.io/posts/ec8df8c/) diff --git "a/\347\274\226\347\250\213/\345\205\266\344\273\226/LSM.md" "b/\347\274\226\347\250\213/\345\205\266\344\273\226/LSM.md" index 8ab705c..5490f3b 100644 --- "a/\347\274\226\347\250\213/\345\205\266\344\273\226/LSM.md" +++ "b/\347\274\226\347\250\213/\345\205\266\344\273\226/LSM.md" @@ -1,3 +1,6 @@ +--- +date: 2024-01-24 +--- # 是什么 @@ -47,4 +50,4 @@ MemTable 达到一定大小后,会转换为 Immutable MemTable。Immutable Mem - [LSM Tree ](https://hujianxin.github.io/blog/posts/lsm/) - [LSM 树详解 -](https://zhuanlan.zhihu.com/p/181498475) \ No newline at end of file +](https://zhuanlan.zhihu.com/p/181498475) diff --git "a/\347\274\226\347\250\213/\345\205\266\344\273\226/Mac mini \345\256\266\345\272\255\347\275\221\347\273\234\350\256\276\347\275\256\345\206\205\347\275\221\347\251\277\351\200\217.md" "b/\347\274\226\347\250\213/\345\205\266\344\273\226/Mac mini \345\256\266\345\272\255\347\275\221\347\273\234\350\256\276\347\275\256\345\206\205\347\275\221\347\251\277\351\200\217.md" index 2c9984f..163833d 100644 --- "a/\347\274\226\347\250\213/\345\205\266\344\273\226/Mac mini \345\256\266\345\272\255\347\275\221\347\273\234\350\256\276\347\275\256\345\206\205\347\275\221\347\251\277\351\200\217.md" +++ "b/\347\274\226\347\250\213/\345\205\266\344\273\226/Mac mini \345\256\266\345\272\255\347\275\221\347\273\234\350\256\276\347\275\256\345\206\205\347\275\221\347\251\277\351\200\217.md" @@ -1,5 +1,6 @@ --- date: 2025-05-14 +--- # 前言 @@ -156,4 +157,4 @@ aliyun-ddns 的 github 链接:https://github.com/risfeng/aliyun-ddns-shell。 # 说明 -这样就能够通过域名在任意地点、任意网络访问家里的 mac 了,可以当成一个服务器来使用。 \ No newline at end of file +这样就能够通过域名在任意地点、任意网络访问家里的 mac 了,可以当成一个服务器来使用。