feat: add license block
This commit is contained in:
parent
a20c647495
commit
c642691dc8
|
@ -27,7 +27,8 @@ export default defineConfig({
|
||||||
icon({
|
icon({
|
||||||
include: {
|
include: {
|
||||||
'material-symbols': ['*'],
|
'material-symbols': ['*'],
|
||||||
'fa6-brands': ['*']
|
'fa6-brands': ['*'],
|
||||||
|
'fa6-regular': ['*']
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
],
|
],
|
||||||
|
|
|
@ -30,6 +30,7 @@
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@astrojs/ts-plugin": "^1.1.3",
|
"@astrojs/ts-plugin": "^1.1.3",
|
||||||
"@iconify-json/fa6-brands": "^1.1.13",
|
"@iconify-json/fa6-brands": "^1.1.13",
|
||||||
|
"@iconify-json/fa6-regular": "^1.1.13",
|
||||||
"@iconify-json/material-symbols": "^1.1.59",
|
"@iconify-json/material-symbols": "^1.1.59",
|
||||||
"@rollup/plugin-yaml": "^4.1.2",
|
"@rollup/plugin-yaml": "^4.1.2",
|
||||||
"@tailwindcss/typography": "^0.5.10",
|
"@tailwindcss/typography": "^0.5.10",
|
||||||
|
|
|
@ -58,6 +58,9 @@ devDependencies:
|
||||||
'@iconify-json/fa6-brands':
|
'@iconify-json/fa6-brands':
|
||||||
specifier: ^1.1.13
|
specifier: ^1.1.13
|
||||||
version: 1.1.13
|
version: 1.1.13
|
||||||
|
'@iconify-json/fa6-regular':
|
||||||
|
specifier: ^1.1.13
|
||||||
|
version: 1.1.13
|
||||||
'@iconify-json/material-symbols':
|
'@iconify-json/material-symbols':
|
||||||
specifier: ^1.1.59
|
specifier: ^1.1.59
|
||||||
version: 1.1.59
|
version: 1.1.59
|
||||||
|
@ -981,6 +984,12 @@ packages:
|
||||||
'@iconify/types': 2.0.0
|
'@iconify/types': 2.0.0
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
|
/@iconify-json/fa6-regular@1.1.13:
|
||||||
|
resolution: {integrity: sha512-wY5nEeWwg+fdDzfPdzOHcbgiN7Qk2bTyO0BreJUQJb8NKPcXivyHAlkWPc+wA0kQwfqrmekVCwWnrLoD7B9T0g==}
|
||||||
|
dependencies:
|
||||||
|
'@iconify/types': 2.0.0
|
||||||
|
dev: true
|
||||||
|
|
||||||
/@iconify-json/material-symbols@1.1.59:
|
/@iconify-json/material-symbols@1.1.59:
|
||||||
resolution: {integrity: sha512-azzJVyS2AKQ4cxIUUmeMHaTVlU9aWM6M98NEqf8luZ1RJpVWuDdSjExY+x58Y39wPFTf+6hgvS4pRwCJRdpohw==}
|
resolution: {integrity: sha512-azzJVyS2AKQ4cxIUUmeMHaTVlU9aWM6M98NEqf8luZ1RJpVWuDdSjExY+x58Y39wPFTf+6hgvS4pRwCJRdpohw==}
|
||||||
dependencies:
|
dependencies:
|
||||||
|
|
|
@ -88,6 +88,8 @@ color_set({
|
||||||
--codeblock-selection: oklch(0.40 0.08 var(--hue))
|
--codeblock-selection: oklch(0.40 0.08 var(--hue))
|
||||||
--codeblock-bg: oklch(0.2 0.015 var(--hue)) oklch(0.17 0.015 var(--hue))
|
--codeblock-bg: oklch(0.2 0.015 var(--hue)) oklch(0.17 0.015 var(--hue))
|
||||||
|
|
||||||
|
--license-block-bg: black(0.03) var(--codeblock-bg)
|
||||||
|
|
||||||
--link-hover: oklch(0.95 0.025 var(--hue)) oklch(0.40 0.08 var(--hue))
|
--link-hover: oklch(0.95 0.025 var(--hue)) oklch(0.40 0.08 var(--hue))
|
||||||
--link-active: oklch(0.90 0.05 var(--hue)) oklch(0.35 0.07 var(--hue))
|
--link-active: oklch(0.90 0.05 var(--hue)) oklch(0.35 0.07 var(--hue))
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,47 @@
|
||||||
|
---
|
||||||
|
import {formatDateToYYYYMMDD} from "../../utils/date-utils";
|
||||||
|
interface Props {
|
||||||
|
title: string;
|
||||||
|
slug: string;
|
||||||
|
pubDate: Date;
|
||||||
|
class: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
const { title, slug, pubDate } = Astro.props;
|
||||||
|
const className = Astro.props.class;
|
||||||
|
|
||||||
|
import { Icon } from 'astro-icon/components';
|
||||||
|
import {licenseConfig, profileConfig} from "../../config";
|
||||||
|
import {getFullUrl, getPostUrlBySlug} from "../../utils/url-utils";
|
||||||
|
import {i18n} from "../../i18n/translation";
|
||||||
|
import I18nKey from "../../i18n/i18nKey";
|
||||||
|
|
||||||
|
const profileConf = profileConfig;
|
||||||
|
const licenseConf = licenseConfig;
|
||||||
|
|
||||||
|
const postUrl = getFullUrl(getPostUrlBySlug(slug));
|
||||||
|
|
||||||
|
---
|
||||||
|
<div class=`relative transition overflow-hidden bg-[var(--license-block-bg)] py-5 px-6 ${className}`>
|
||||||
|
<div class="transition font-bold text-black/75 dark:text-white/75">
|
||||||
|
{title}
|
||||||
|
</div>
|
||||||
|
<a href={postUrl} class="link text-[var(--primary)]">
|
||||||
|
{postUrl}
|
||||||
|
</a>
|
||||||
|
<div class="flex gap-6 mt-2">
|
||||||
|
<div>
|
||||||
|
<div class="transition text-black/30 dark:text-white/30 text-sm">{i18n(I18nKey.author)}</div>
|
||||||
|
<div class="transition text-black/75 dark:text-white/75">{profileConf.name}</div>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<div class="transition text-black/30 dark:text-white/30 text-sm">{i18n(I18nKey.publishedAt)}</div>
|
||||||
|
<div class="transition text-black/75 dark:text-white/75">{formatDateToYYYYMMDD(pubDate)}</div>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<div class="transition text-black/30 dark:text-white/30 text-sm">{i18n(I18nKey.license)}</div>
|
||||||
|
<a href={licenseConf.url} target="_blank" class="link text-[var(--primary)]">{licenseConf.name}</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<Icon name="fa6-brands:creative-commons" class="transition absolute right-6 top-1/2 -translate-y-1/2 text-black/5 dark:text-white/5" size="240"></Icon>
|
||||||
|
</div>
|
|
@ -1,10 +1,11 @@
|
||||||
import type {NavBarConfig, ProfileConfig, SiteConfig} from "./types/config.ts";
|
import type {LicenseConfig, NavBarConfig, ProfileConfig, SiteConfig} from "./types/config.ts";
|
||||||
import {LinkPreset} from "./types/config.ts";
|
import {LinkPreset} from "./types/config.ts";
|
||||||
|
|
||||||
export const siteConfig: SiteConfig = {
|
export const siteConfig: SiteConfig = {
|
||||||
title: 'Fuwari',
|
title: 'Fuwari',
|
||||||
subtitle: 'Demo Site',
|
subtitle: 'Demo Site',
|
||||||
lang: 'en-US',
|
url: 'https://fuwari.vercel.app/',
|
||||||
|
lang: 'en',
|
||||||
themeHue: 250,
|
themeHue: 250,
|
||||||
banner: {
|
banner: {
|
||||||
enable: true,
|
enable: true,
|
||||||
|
@ -45,3 +46,9 @@ export const profileConfig: ProfileConfig = {
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const licenseConfig: LicenseConfig = {
|
||||||
|
enable: true,
|
||||||
|
name: 'CC BY-NC-SA 4.0',
|
||||||
|
url: 'https://creativecommons.org/licenses/by-nc-sa/4.0/',
|
||||||
|
}
|
|
@ -23,6 +23,10 @@ enum I18nKey {
|
||||||
primaryColor = "primaryColor",
|
primaryColor = "primaryColor",
|
||||||
|
|
||||||
more = "more",
|
more = "more",
|
||||||
|
|
||||||
|
author = "author",
|
||||||
|
publishedAt = "publishedAt",
|
||||||
|
license = "license",
|
||||||
}
|
}
|
||||||
|
|
||||||
export default I18nKey;
|
export default I18nKey;
|
|
@ -26,4 +26,8 @@ export const en: Translation = {
|
||||||
[Key.primaryColor]: "Primary Color",
|
[Key.primaryColor]: "Primary Color",
|
||||||
|
|
||||||
[Key.more]: "More",
|
[Key.more]: "More",
|
||||||
|
|
||||||
|
[Key.author]: "Author",
|
||||||
|
[Key.publishedAt]: "Published at",
|
||||||
|
[Key.license]: "License",
|
||||||
};
|
};
|
||||||
|
|
|
@ -26,4 +26,8 @@ export const zh_CN: Translation = {
|
||||||
[Key.primaryColor]: "主题色",
|
[Key.primaryColor]: "主题色",
|
||||||
|
|
||||||
[Key.more]: "更多",
|
[Key.more]: "更多",
|
||||||
|
|
||||||
|
[Key.author]: "作者",
|
||||||
|
[Key.publishedAt]: "发布于",
|
||||||
|
[Key.license]: "许可协议",
|
||||||
};
|
};
|
|
@ -26,4 +26,8 @@ export const zh_TW: Translation = {
|
||||||
[Key.primaryColor]: "主題色",
|
[Key.primaryColor]: "主題色",
|
||||||
|
|
||||||
[Key.more]: "更多",
|
[Key.more]: "更多",
|
||||||
|
|
||||||
|
[Key.author]: "作者",
|
||||||
|
[Key.publishedAt]: "發佈於",
|
||||||
|
[Key.license]: "許可協議",
|
||||||
};
|
};
|
||||||
|
|
|
@ -8,7 +8,8 @@ import Button from "../../components/control/Button.astro";
|
||||||
import {i18n} from "../../i18n/translation";
|
import {i18n} from "../../i18n/translation";
|
||||||
import I18nKey from "../../i18n/i18nKey";
|
import I18nKey from "../../i18n/i18nKey";
|
||||||
import {getPostUrlBySlug} from "../../utils/url-utils";
|
import {getPostUrlBySlug} from "../../utils/url-utils";
|
||||||
import CommentLayout from "../../components/comment/CommentLayout.astro";
|
import License from "../../components/misc/License.astro";
|
||||||
|
import {licenseConfig} from "../../config";
|
||||||
|
|
||||||
export async function getStaticPaths() {
|
export async function getStaticPaths() {
|
||||||
const blogEntries = await getCollection('posts');
|
const blogEntries = await getCollection('posts');
|
||||||
|
@ -25,7 +26,7 @@ const { remarkPluginFrontmatter } = await entry.render();
|
||||||
---
|
---
|
||||||
<MainGridLayout banner={entry.data.image} title={entry.data.title}>
|
<MainGridLayout banner={entry.data.image} title={entry.data.title}>
|
||||||
<div class="flex w-full rounded-[var(--radius-large)] overflow-hidden relative mb-4">
|
<div class="flex w-full rounded-[var(--radius-large)] overflow-hidden relative mb-4">
|
||||||
<div class:list={["card-base z-10 px-4 md:px-9 pt-6 pb-10 relative w-full ",
|
<div class:list={["card-base z-10 px-4 md:px-9 pt-6 pb-4 relative w-full ",
|
||||||
{}
|
{}
|
||||||
]}>
|
]}>
|
||||||
<!-- word count and reading time -->
|
<!-- word count and reading time -->
|
||||||
|
@ -73,13 +74,15 @@ const { remarkPluginFrontmatter } = await entry.render();
|
||||||
|
|
||||||
{!entry.data.image && <div class="border-[var(--line-divider)] border-dashed border-b-[1px] mb-5"></div>}
|
{!entry.data.image && <div class="border-[var(--line-divider)] border-dashed border-b-[1px] mb-5"></div>}
|
||||||
|
|
||||||
<div class="prose dark:prose-invert prose-sm md:prose-base max-w-none custom-md
|
<div class="mb-6 prose dark:prose-invert prose-sm md:prose-base max-w-none custom-md
|
||||||
">
|
">
|
||||||
<!--<div class="prose dark:prose-invert max-w-none custom-md">-->
|
<!--<div class="prose dark:prose-invert max-w-none custom-md">-->
|
||||||
<!--<div class="max-w-none custom-md">-->
|
<!--<div class="max-w-none custom-md">-->
|
||||||
<Content />
|
<Content />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{licenseConfig.enable && <License title={entry.data.title} slug={entry.slug} pubDate={entry.data.published} class="mb-6 rounded-xl"></License>}
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@ -183,7 +186,7 @@ const { remarkPluginFrontmatter } = await entry.render();
|
||||||
&:after
|
&:after
|
||||||
content: none
|
content: none
|
||||||
img
|
img
|
||||||
border-radius: 8px
|
border-radius: 12px
|
||||||
hr
|
hr
|
||||||
border-color: var(--line-divider)
|
border-color: var(--line-divider)
|
||||||
border-style: dashed
|
border-style: dashed
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
export type SiteConfig = {
|
export type SiteConfig = {
|
||||||
title: string,
|
title: string,
|
||||||
subtitle: string,
|
subtitle: string,
|
||||||
|
url: string,
|
||||||
|
|
||||||
lang: string,
|
lang: string,
|
||||||
|
|
||||||
|
@ -37,3 +38,9 @@ export type ProfileConfig = {
|
||||||
icon: string,
|
icon: string,
|
||||||
}[],
|
}[],
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export type LicenseConfig = {
|
||||||
|
enable: boolean;
|
||||||
|
name: string,
|
||||||
|
url: string,
|
||||||
|
}
|
|
@ -1,9 +1,16 @@
|
||||||
|
import {siteConfig} from "../config.ts";
|
||||||
|
|
||||||
export function pathsEqual(path1: string, path2: string) {
|
export function pathsEqual(path1: string, path2: string) {
|
||||||
const normalizedPath1 = path1.replace(/^\/|\/$/g, '').toLowerCase();
|
const normalizedPath1 = path1.replace(/^\/|\/$/g, '').toLowerCase();
|
||||||
const normalizedPath2 = path2.replace(/^\/|\/$/g, '').toLowerCase();
|
const normalizedPath2 = path2.replace(/^\/|\/$/g, '').toLowerCase();
|
||||||
return normalizedPath1 === normalizedPath2;
|
return normalizedPath1 === normalizedPath2;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function joinUrl(...parts: string[]): string {
|
||||||
|
const joined = parts.join('/');
|
||||||
|
return joined.replace(/([^:]\/)\/+/g, '$1');
|
||||||
|
}
|
||||||
|
|
||||||
export function getPostUrlBySlug(slug: string): string | null {
|
export function getPostUrlBySlug(slug: string): string | null {
|
||||||
if (!slug)
|
if (!slug)
|
||||||
return null;
|
return null;
|
||||||
|
@ -16,3 +23,6 @@ export function getCategoryUrl(category: string): string | null {
|
||||||
return `/archive/category/${category}`;
|
return `/archive/category/${category}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function getFullUrl(path: string): string {
|
||||||
|
return joinUrl(siteConfig.url, path);
|
||||||
|
}
|
Loading…
Reference in New Issue