mirror of
https://github.com/saicaca/fuwari.git
synced 2026-01-11 14:52:52 +01:00
Merge branch 'main' into wind-v4
This commit is contained in:
4
.gitignore
vendored
4
.gitignore
vendored
@@ -25,3 +25,7 @@ pnpm-debug.log*
|
|||||||
package-lock.json
|
package-lock.json
|
||||||
bun.lockb
|
bun.lockb
|
||||||
yarn.lock
|
yarn.lock
|
||||||
|
|
||||||
|
# ide
|
||||||
|
.idea
|
||||||
|
*.iml
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
{
|
{
|
||||||
"$schema": "https://biomejs.dev/schemas/2.0.0/schema.json",
|
"$schema": "https://biomejs.dev/schemas/2.2.0/schema.json",
|
||||||
"vcs": {
|
"vcs": {
|
||||||
"enabled": false,
|
"enabled": false,
|
||||||
"clientKind": "git",
|
"clientKind": "git",
|
||||||
|
|||||||
@@ -18,7 +18,7 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@astrojs/check": "^0.9.4",
|
"@astrojs/check": "^0.9.4",
|
||||||
"@astrojs/rss": "^4.0.12",
|
"@astrojs/rss": "^4.0.12",
|
||||||
"@astrojs/sitemap": "^3.4.2",
|
"@astrojs/sitemap": "^3.5.0",
|
||||||
"@astrojs/svelte": "7.1.0",
|
"@astrojs/svelte": "7.1.0",
|
||||||
"@expressive-code/core": "^0.41.3",
|
"@expressive-code/core": "^0.41.3",
|
||||||
"@expressive-code/plugin-collapsible-sections": "^0.41.3",
|
"@expressive-code/plugin-collapsible-sections": "^0.41.3",
|
||||||
@@ -33,7 +33,7 @@
|
|||||||
"@swup/astro": "^1.7.0",
|
"@swup/astro": "^1.7.0",
|
||||||
"@tailwindcss/typography": "^0.5.16",
|
"@tailwindcss/typography": "^0.5.16",
|
||||||
"@tailwindcss/vite": "^4.1.11",
|
"@tailwindcss/vite": "^4.1.11",
|
||||||
"astro": "5.12.5",
|
"astro": "5.13.2",
|
||||||
"astro-expressive-code": "^0.41.3",
|
"astro-expressive-code": "^0.41.3",
|
||||||
"astro-icon": "^1.1.5",
|
"astro-icon": "^1.1.5",
|
||||||
"hastscript": "^9.0.1",
|
"hastscript": "^9.0.1",
|
||||||
@@ -56,14 +56,14 @@
|
|||||||
"sanitize-html": "^2.17.0",
|
"sanitize-html": "^2.17.0",
|
||||||
"sharp": "^0.34.3",
|
"sharp": "^0.34.3",
|
||||||
"stylus": "^0.64.0",
|
"stylus": "^0.64.0",
|
||||||
"svelte": "^5.37.2",
|
"svelte": "^5.38.2",
|
||||||
"tailwindcss": "^4.1.11",
|
"tailwindcss": "^4.1.11",
|
||||||
"typescript": "^5.9.2",
|
"typescript": "^5.9.2",
|
||||||
"unist-util-visit": "^5.0.0"
|
"unist-util-visit": "^5.0.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@astrojs/ts-plugin": "^1.10.4",
|
"@astrojs/ts-plugin": "^1.10.4",
|
||||||
"@biomejs/biome": "2.1.3",
|
"@biomejs/biome": "2.2.0",
|
||||||
"@rollup/plugin-yaml": "^4.1.2",
|
"@rollup/plugin-yaml": "^4.1.2",
|
||||||
"@types/hast": "^3.0.4",
|
"@types/hast": "^3.0.4",
|
||||||
"@types/markdown-it": "^14.1.2",
|
"@types/markdown-it": "^14.1.2",
|
||||||
|
|||||||
817
pnpm-lock.yaml
generated
817
pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
@@ -75,8 +75,8 @@ onMount(async () => {
|
|||||||
);
|
);
|
||||||
|
|
||||||
const groupedPostsArray = Object.keys(grouped).map((yearStr) => ({
|
const groupedPostsArray = Object.keys(grouped).map((yearStr) => ({
|
||||||
year: Number.parseInt(yearStr),
|
year: Number.parseInt(yearStr, 10),
|
||||||
posts: grouped[Number.parseInt(yearStr)],
|
posts: grouped[Number.parseInt(yearStr, 10)],
|
||||||
}));
|
}));
|
||||||
|
|
||||||
groupedPostsArray.sort((a, b) => b.year - a.year);
|
groupedPostsArray.sort((a, b) => b.year - a.year);
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ $: if (hue || hue === 0) {
|
|||||||
before:absolute before:-left-3 before:top-[0.33rem]"
|
before:absolute before:-left-3 before:top-[0.33rem]"
|
||||||
>
|
>
|
||||||
{i18n(I18nKey.themeColor)}
|
{i18n(I18nKey.themeColor)}
|
||||||
<button aria-label="Reset to Default" class="btn-regular w-7 h-7 rounded-md active:scale-90"
|
<button aria-label="Reset to Default" class="btn-regular w-7 h-7 rounded-md active:scale-90 will-change-transform"
|
||||||
class:opacity-0={hue === defaultHue} class:pointer-events-none={hue === defaultHue} on:click={resetHue}>
|
class:opacity-0={hue === defaultHue} class:pointer-events-none={hue === defaultHue} on:click={resetHue}>
|
||||||
<div class="text-[var(--btn-content)]">
|
<div class="text-[var(--btn-content)]">
|
||||||
<Icon icon="fa6-solid:arrow-rotate-left" class="text-[0.875rem]"></Icon>
|
<Icon icon="fa6-solid:arrow-rotate-left" class="text-[0.875rem]"></Icon>
|
||||||
|
|||||||
@@ -55,7 +55,7 @@ const maxLevel = siteConfig.toc.depth;
|
|||||||
}]}>{removeTailingHash(heading.text)}</div>
|
}]}>{removeTailingHash(heading.text)}</div>
|
||||||
</a>
|
</a>
|
||||||
)}
|
)}
|
||||||
<div id="active-indicator" class:list={[{'hidden': headings.length == 0}, "-z-10 absolute bg-[var(--toc-btn-hover)] left-0 right-0 rounded-xl transition-all " +
|
<div id="active-indicator" style="opacity: 0" class:list={[{'hidden': headings.length == 0}, "-z-10 absolute bg-[var(--toc-btn-hover)] left-0 right-0 rounded-xl transition-all " +
|
||||||
"group-hover:bg-transparent border-2 border-[var(--toc-btn-hover)] group-hover:border-[var(--toc-btn-active)] border-dashed"]}></div>
|
"group-hover:bg-transparent border-2 border-[var(--toc-btn-hover)] group-hover:border-[var(--toc-btn-active)] border-dashed"]}></div>
|
||||||
</table-of-contents>}
|
</table-of-contents>}
|
||||||
|
|
||||||
@@ -97,7 +97,7 @@ class TableOfContents extends HTMLElement {
|
|||||||
|
|
||||||
toggleActiveHeading = () => {
|
toggleActiveHeading = () => {
|
||||||
let i = this.active.length - 1;
|
let i = this.active.length - 1;
|
||||||
let min = this.active.length - 1, max = 0;
|
let min = this.active.length - 1, max = -1;
|
||||||
while (i >= 0 && !this.active[i]) {
|
while (i >= 0 && !this.active[i]) {
|
||||||
this.tocEntries[i].classList.remove(this.visibleClass);
|
this.tocEntries[i].classList.remove(this.visibleClass);
|
||||||
i--;
|
i--;
|
||||||
@@ -112,11 +112,15 @@ class TableOfContents extends HTMLElement {
|
|||||||
this.tocEntries[i].classList.remove(this.visibleClass);
|
this.tocEntries[i].classList.remove(this.visibleClass);
|
||||||
i--;
|
i--;
|
||||||
}
|
}
|
||||||
|
if (min > max) {
|
||||||
|
this.activeIndicator?.setAttribute("style", `opacity: 0`);
|
||||||
|
} else {
|
||||||
let parentOffset = this.tocEl?.getBoundingClientRect().top || 0;
|
let parentOffset = this.tocEl?.getBoundingClientRect().top || 0;
|
||||||
let scrollOffset = this.tocEl?.scrollTop || 0;
|
let scrollOffset = this.tocEl?.scrollTop || 0;
|
||||||
let top = this.tocEntries[min].getBoundingClientRect().top - parentOffset + scrollOffset;
|
let top = this.tocEntries[min].getBoundingClientRect().top - parentOffset + scrollOffset;
|
||||||
let bottom = this.tocEntries[max].getBoundingClientRect().bottom - parentOffset + scrollOffset;
|
let bottom = this.tocEntries[max].getBoundingClientRect().bottom - parentOffset + scrollOffset;
|
||||||
this.activeIndicator?.setAttribute("style", `top: ${top}px; height: ${bottom - top}px`);
|
this.activeIndicator?.setAttribute("style", `top: ${top}px; height: ${bottom - top}px`);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
scrollToActiveHeading = () => {
|
scrollToActiveHeading = () => {
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ import { LinkPreset } from "./types/config";
|
|||||||
export const siteConfig: SiteConfig = {
|
export const siteConfig: SiteConfig = {
|
||||||
title: "Fuwari",
|
title: "Fuwari",
|
||||||
subtitle: "Demo Site",
|
subtitle: "Demo Site",
|
||||||
lang: "en", // Language code, e.g. 'en', 'zh-CN', 'ja', etc.
|
lang: "en", // Language code, e.g. 'en', 'zh_CN', 'ja', etc.
|
||||||
themeColor: {
|
themeColor: {
|
||||||
hue: 250, // Default hue for the theme color, from 0 to 360. e.g. red: 0, teal: 200, cyan: 250, pink: 345
|
hue: 250, // Default hue for the theme color, from 0 to 360. e.g. red: 0, teal: 200, cyan: 250, pink: 345
|
||||||
fixed: false, // Hide the theme color picker for visitors
|
fixed: false, // Hide the theme color picker for visitors
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import rss from "@astrojs/rss";
|
import rss from "@astrojs/rss";
|
||||||
import { getSortedPosts } from "@utils/content-utils";
|
import { getSortedPosts } from "@utils/content-utils";
|
||||||
|
import { url } from "@utils/url-utils";
|
||||||
import type { APIContext } from "astro";
|
import type { APIContext } from "astro";
|
||||||
import MarkdownIt from "markdown-it";
|
import MarkdownIt from "markdown-it";
|
||||||
import sanitizeHtml from "sanitize-html";
|
import sanitizeHtml from "sanitize-html";
|
||||||
@@ -30,7 +31,7 @@ export async function GET(context: APIContext) {
|
|||||||
title: post.data.title,
|
title: post.data.title,
|
||||||
pubDate: post.data.published,
|
pubDate: post.data.published,
|
||||||
description: post.data.description || "",
|
description: post.data.description || "",
|
||||||
link: `/posts/${post.slug}/`,
|
link: url(`/posts/${post.slug}/`),
|
||||||
content: sanitizeHtml(parser.render(cleanedContent), {
|
content: sanitizeHtml(parser.render(cleanedContent), {
|
||||||
allowedTags: sanitizeHtml.defaults.allowedTags.concat(["img"]),
|
allowedTags: sanitizeHtml.defaults.allowedTags.concat(["img"]),
|
||||||
}),
|
}),
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import { definePlugin } from "@expressive-code/core";
|
|||||||
export function pluginLanguageBadge() {
|
export function pluginLanguageBadge() {
|
||||||
return definePlugin({
|
return definePlugin({
|
||||||
name: "Language Badge",
|
name: "Language Badge",
|
||||||
// @ts-ignore
|
// @ts-expect-error
|
||||||
baseStyles: ({ _cssVar }) => `
|
baseStyles: ({ _cssVar }) => `
|
||||||
[data-language]::before {
|
[data-language]::before {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
@@ -15,6 +15,7 @@ export function pluginLanguageBadge() {
|
|||||||
top: 0.5rem;
|
top: 0.5rem;
|
||||||
padding: 0.1rem 0.5rem;
|
padding: 0.1rem 0.5rem;
|
||||||
content: attr(data-language);
|
content: attr(data-language);
|
||||||
|
font-family: "JetBrains Mono Variable", ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
|
||||||
font-size: 0.75rem;
|
font-size: 0.75rem;
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
text-transform: uppercase;
|
text-transform: uppercase;
|
||||||
|
|||||||
@@ -1,5 +1,11 @@
|
|||||||
@reference "tailwindcss";
|
@reference "tailwindcss";
|
||||||
|
|
||||||
.expressive-code .frame {
|
.expressive-code {
|
||||||
|
.frame {
|
||||||
@apply !shadow-none;
|
@apply !shadow-none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.title {
|
||||||
|
font-family: "JetBrains Mono Variable", ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -26,6 +26,7 @@
|
|||||||
underline decoration-[var(--link-underline)] decoration-1 decoration-dashed underline-offset-4;
|
underline decoration-[var(--link-underline)] decoration-1 decoration-dashed underline-offset-4;
|
||||||
box-decoration-break: clone;
|
box-decoration-break: clone;
|
||||||
-webkit-box-decoration-break: clone;
|
-webkit-box-decoration-break: clone;
|
||||||
|
display: inline-block;
|
||||||
|
|
||||||
&:hover, &:active {
|
&:hover, &:active {
|
||||||
@apply decoration-transparent;
|
@apply decoration-transparent;
|
||||||
|
|||||||
@@ -57,8 +57,8 @@ export async function getTagList(): Promise<Tag[]> {
|
|||||||
});
|
});
|
||||||
|
|
||||||
const countMap: { [key: string]: number } = {};
|
const countMap: { [key: string]: number } = {};
|
||||||
allBlogPosts.map((post: { data: { tags: string[] } }) => {
|
allBlogPosts.forEach((post: { data: { tags: string[] } }) => {
|
||||||
post.data.tags.map((tag: string) => {
|
post.data.tags.forEach((tag: string) => {
|
||||||
if (!countMap[tag]) countMap[tag] = 0;
|
if (!countMap[tag]) countMap[tag] = 0;
|
||||||
countMap[tag]++;
|
countMap[tag]++;
|
||||||
});
|
});
|
||||||
@@ -83,7 +83,7 @@ export async function getCategoryList(): Promise<Category[]> {
|
|||||||
return import.meta.env.PROD ? data.draft !== true : true;
|
return import.meta.env.PROD ? data.draft !== true : true;
|
||||||
});
|
});
|
||||||
const count: { [key: string]: number } = {};
|
const count: { [key: string]: number } = {};
|
||||||
allBlogPosts.map((post: { data: { category: string | null } }) => {
|
allBlogPosts.forEach((post: { data: { category: string | null } }) => {
|
||||||
if (!post.data.category) {
|
if (!post.data.category) {
|
||||||
const ucKey = i18n(I18nKey.uncategorized);
|
const ucKey = i18n(I18nKey.uncategorized);
|
||||||
count[ucKey] = count[ucKey] ? count[ucKey] + 1 : 1;
|
count[ucKey] = count[ucKey] ? count[ucKey] + 1 : 1;
|
||||||
|
|||||||
@@ -10,12 +10,12 @@ import type { LIGHT_DARK_MODE } from "@/types/config";
|
|||||||
export function getDefaultHue(): number {
|
export function getDefaultHue(): number {
|
||||||
const fallback = "250";
|
const fallback = "250";
|
||||||
const configCarrier = document.getElementById("config-carrier");
|
const configCarrier = document.getElementById("config-carrier");
|
||||||
return Number.parseInt(configCarrier?.dataset.hue || fallback);
|
return Number.parseInt(configCarrier?.dataset.hue || fallback, 10);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getHue(): number {
|
export function getHue(): number {
|
||||||
const stored = localStorage.getItem("hue");
|
const stored = localStorage.getItem("hue");
|
||||||
return stored ? Number.parseInt(stored) : getDefaultHue();
|
return stored ? Number.parseInt(stored, 10) : getDefaultHue();
|
||||||
}
|
}
|
||||||
|
|
||||||
export function setHue(hue: number): void {
|
export function setHue(hue: number): void {
|
||||||
|
|||||||
Reference in New Issue
Block a user