feat(comment): move comment assets to cdn

- Remove Twikoo's local style.
- Remove local package of Artalk and Waline to minify styles

This commit is because of unused comment styles in build packaged css.

https://github.com/vitejs/vite/pull/19418 might have helped, but Astro didn't use this experimental feature (https://github.com/withastro/astro/pull/13420).
This commit is contained in:
HPCesia 2025-04-05 19:07:51 +08:00
parent 28542e1a45
commit afa5bf98f4
Signed by: HPCesia
GPG Key ID: 2C107E1FD23C98DF
7 changed files with 108 additions and 766 deletions

View File

@ -32,8 +32,6 @@
"@swup/scripts-plugin": "^2.1.0",
"@swup/scroll-plugin": "^3.3.2",
"@tailwindcss/vite": "^4.1.3",
"@waline/client": "^3.5.6",
"artalk": "^2.9.1",
"astro": "^5.6.1",
"astro-compress": "2.3.5",
"astro-icon": "^1.1.5",

View File

@ -1,15 +1,29 @@
---
import 'artalk/Artalk.css';
import { commentConfig, siteConfig } from '@/config';
import { CDN } from '@constants/cdn.mjs';
const artalkConfig = commentConfig.artalk!;
---
<div id="artalk-wrapper" class="mt-6"></div>
<script>
import { commentConfig, siteConfig } from '@/config';
import Artalk from 'artalk';
<link rel="stylesheet" href={CDN.artalkCss} />
<script
type="module"
is:inline
define:vars={{
artalkConfig,
siteConfig: {
title: siteConfig.title,
lang: siteConfig.lang,
},
}}
>
import Artalk from 'https://esm.sh/artalk@2.9.1';
function setup() {
function getCurrentMode(): boolean {
function getCurrentMode() {
if (!('darkMode' in localStorage)) {
return window.matchMedia('(prefers-color-scheme: dark)').matches;
}
@ -21,13 +35,12 @@ import 'artalk/Artalk.css';
darkMode: getCurrentMode(),
pageKey: window.location.pathname,
pageTitle: document.title,
server: commentConfig.artalk?.serverURL,
server: artalkConfig.serverURL,
site: siteConfig.title,
locale: commentConfig.artalk?.locale || siteConfig.lang,
locale: artalkConfig.locale || siteConfig.lang,
});
document.addEventListener('blog:darkmode-change', (e) => {
// @ts-expect-error CustomEvent.detail is not defined in TypeScript
const { isDark } = e.detail;
artalk.setDarkMode(isDark);
});

View File

@ -1,5 +1,4 @@
---
import '@/styles/twikoo.css';
import { CDN } from '@constants/cdn.mjs';
---

View File

@ -1,24 +1,89 @@
---
import { commentConfig } from '@/config';
import { Waline as WalineComponent } from '@waline/client/component';
import '@waline/client/meta';
import '@waline/client/style';
// Need to be separated to avoid being sorted before `@waline/client/style` when formatting
import '@/styles/waline.css';
import { commentConfig, siteConfig } from '@/config';
const walineConfig = commentConfig.waline!;
const pathName = walineConfig.path ? walineConfig.path(Astro.url.pathname) : Astro.url.pathname;
---
<WalineComponent
client:visible
serverURL={walineConfig.serverURL}
path={pathName}
dark={false}
meta={walineConfig.meta || ['nick', 'mail', 'link']}
requiredMeta={walineConfig.requiredMeta || []}
login={walineConfig.login || 'enable'}
wordLimit={walineConfig.wordLimit || 500}
pageSize={walineConfig.pageSize || 10}
reaction={walineConfig.reaction || false}
/>
<div id="waline-wrapper"></div>
<script
type="module"
is:inline
define:vars={{
walineConfig,
pathName,
lang: siteConfig.lang,
}}
>
import { init } from 'https://unpkg.com/@waline/client@v3/dist/waline.js';
function setup() {
const el = document.getElementById('waline-wrapper');
if (!el) return;
init({
el,
lang,
serverURL: walineConfig.serverURL,
path: pathName,
dark: false,
meta: walineConfig.meta || ['nick', 'mail', 'link'],
requiredMeta: walineConfig.requiredMeta || [],
login: walineConfig.login || 'enable',
wordLimit: walineConfig.wordLimit || 500,
pageSize: walineConfig.pageSize || 10,
reaction: walineConfig.reaction || false,
});
}
document.addEventListener('astro:page-load', setup);
setup();
</script>
<link rel="stylesheet" href="https://unpkg.com/@waline/client@v3/dist/waline.css" />
<style is:inline>
:root {
/* 字体大小 */
--waline-font-size: 1rem;
/* 常规颜色 */
--waline-white: #fff;
--waline-light-grey: #999;
--waline-dark-grey: #666;
/* 主题色 */
--waline-theme-color: var(--color-primary);
--waline-active-color: var(--color-secondary);
/* 布局颜色 */
--waline-color: var(--color-base-content);
--waline-bg-color: var(--color-base-100);
--waline-bg-color-light: var(--color-base-200);
--waline-bg-color-hover: var(--color-base-200);
--waline-border-color: var(--color-base-200);
--waline-disable-bg-color: color-mix(in oklab, var(--color-base-200) 25%, transparent);
--waline-disable-color: color-mix(in oklab, var(--color-base-content) 75%, transparent);
--waline-code-bg-color: var(--color-base-100);
/* 特殊颜色 */
--waline-bq-color: #f0f0f0;
/* 头像 */
--waline-avatar-size: 3.25rem;
--waline-m-avatar-size: calc(var(--waline-avatar-size) * 9 / 13);
/* 徽章 */
--waline-badge-color: var(--color-accent);
--waline-badge-font-size: 0.775em;
/* 信息 */
--waline-info-bg-color: color-mix(in oklab, var(--color-base-content) 15%, transparent);
--waline-info-color: color-mix(in oklab, var(--color-base-content) 60%, transparent);
--waline-info-font-size: 0.625em;
/* 渲染选择 */
--waline-border: 1px solid var(--waline-border-color);
--waline-avatar-radius: 50%;
--waline-box-shadow: none;
}
</style>

View File

@ -1,6 +1,8 @@
export const CDN = {
twikoo: 'https://cdn.jsdelivr.net/npm/twikoo@1.6.41/dist/twikoo.nocss.js',
twikoo: 'https://cdn.jsdelivr.net/npm/twikoo@1.6.42/dist/twikoo.min.js',
giscus: 'https://giscus.app/client.js',
artalkCss: 'https://cdnjs.cloudflare.com/ajax/libs/artalk/2.9.1/Artalk.css',
walineCss: 'https://unpkg.com/@waline/client@v3/dist/waline.css',
mathjaxFont:
'https://cdnjs.cloudflare.com/ajax/libs/mathjax/3.2.2/es5/output/chtml/fonts/woff-v2',
giscus: 'https://giscus.app/client.js',
};

View File

@ -1,691 +0,0 @@
/* stylelint-disable no-descending-specificity */
/* stylelint-disable selector-class-pattern */
@reference './global.css';
.twikoo {
@apply relative flex h-fit w-full flex-col items-center;
input,
textarea,
select {
border: none;
}
}
.tk-comments {
@apply w-full;
.tk-row {
@apply flex w-full flex-row gap-2;
}
.tk-col {
@apply flex w-full flex-col gap-2;
}
/* 回复框样式 */
.tk-submit {
@apply relative my-2 w-full;
.tk-avatar {
display: none;
}
/* 输入框部分样式 */
.tk-col {
@apply flex-col-reverse;
}
/* 文本框输入样式 */
.el-textarea {
@apply border-base-300 relative w-full overflow-hidden rounded-xl border pb-9;
textarea {
@apply bg-base-200/50 w-full p-4;
resize: none;
&:focus {
outline: none;
}
&::placeholder {
@apply text-base-content/50;
}
}
.el-input__count {
@apply text-base-content/50 absolute right-10 bottom-2 text-sm;
}
}
/* 个人信息输入框样式 */
.tk-meta-input {
@apply flex w-[calc(100%-3.5rem)] flex-col items-center gap-2 md:w-[calc(100%-6.75rem)] md:flex-row;
}
.actions {
@apply relative w-full;
.tk-row-actions-start {
@apply absolute bottom-[8.15rem] ml-3 flex flex-row items-center gap-2 md:bottom-[3.15rem];
input {
display: none;
}
}
button {
@apply border-base-300 bg-primary absolute py-[0.95rem] md:py-[0.3rem];
&.tk-preview {
@apply right-0 bottom-[3.7rem] md:right-[3.35rem] md:bottom-0;
}
&.tk-send {
@apply right-0 bottom-0;
}
}
}
.__markdown {
@apply absolute right-3 bottom-[7.75rem] md:bottom-[2.75rem];
}
&:has(.tk-cancel) {
.tk-meta-input {
@apply w-[calc(100%-3.5rem)] md:w-[calc(100%-10rem)];
}
.actions button {
@apply py-[0.3rem];
&.tk-preview {
@apply bottom-[4.9rem] md:bottom-0;
}
&.tk-cancel {
@apply bg-error text-error-content right-0 bottom-[2.4rem] md:right-[6.7rem] md:bottom-0;
}
}
}
.tk-preview-container {
@apply border-base-300 bg-base-100 mt-2 w-full rounded-xl border p-2;
}
}
/* 表情框样式 */
.OwO-body {
/* stylelint-disable-next-line scss/operator-no-unspaced */
@apply border-base-300 bg-base-200/90 absolute top-9 -left-3 z-20 hidden w-[calc(100vw-3rem)] max-w-[30rem] rounded-xl border duration-300;
}
.OwO-open .OwO-body {
@apply block;
}
.OwO-items {
@apply hidden max-h-48 overflow-y-auto p-2;
&.OwO-items-show {
@apply block;
}
}
.OwO-item {
@apply inline-block cursor-pointer rounded-md px-2 py-1 text-center text-xs duration-300;
img {
@apply inline-block h-14 w-14;
}
&:hover {
@apply backdrop-brightness-150;
}
}
.OwO-bar {
@apply flex w-full flex-row flex-wrap items-center rounded-b-xl text-start text-xs;
}
.OwO-packages {
@apply flex flex-wrap items-center px-4 text-nowrap;
> li {
@apply hover:bg-primary/50 flex h-8 cursor-pointer items-center px-3 text-center duration-300;
&.OwO-package-active {
@apply bg-primary/50;
}
}
}
.tk-comments-container {
/* 评论整体样式 */
@apply mt-4 flex w-full flex-col gap-4;
.tk-comments-title {
@apply flex flex-row items-center justify-between px-2;
.tk-comments-count {
@apply text-lg font-bold;
}
.tk-icon {
@apply mx-2 cursor-pointer;
}
}
.tk-comment {
@apply relative scroll-m-20;
}
> .tk-comment {
@apply max-md:border-base-300 max-md:bg-base-200/50 p-4 max-md:rounded-xl max-md:border;
> .tk-avatar {
@apply top-3;
}
}
.tk-replies {
@apply mt-4 ml-6 flex flex-col gap-2;
&:not(.tk-replies-expand) {
@apply max-h-32 overflow-y-hidden;
}
}
/* 详细样式 */
.tk-avatar {
@apply border-base-300 absolute top-0 h-8 min-h-8 w-8 min-w-8 overflow-hidden rounded-full border;
}
.tk-main > .tk-row {
@apply mb-2 ml-[2.5rem] w-[calc(100%-3rem)] justify-between;
}
.tk-meta {
a {
@apply hover:text-primary duration-300;
}
small {
@apply text-base-content/50;
}
.tk-actions {
@apply opacity-0 duration-300;
}
}
/* 评论操作样式 */
.tk-main:not(:has(.tk-replies:hover)):hover > .tk-row .tk-meta .tk-actions {
@apply opacity-100;
}
.tk-action {
.tk-action-link {
@apply border-base-300 relative flex items-center justify-center rounded-xl border px-2 py-1 text-center duration-300;
.tk-action-icon-solid {
@apply absolute left-2 opacity-0 duration-300;
}
.tk-action-count {
@apply text-sm;
&:not(:empty) {
@apply ml-2;
}
}
&:first-child {
display: none;
}
&:hover {
@apply bg-primary;
.tk-action-icon-solid {
@apply opacity-100;
}
}
}
}
.tk-content {
@apply relative mx-2 mb-3;
}
.tk-extras {
@apply flex flex-row gap-3;
.tk-extra {
@apply border-base-300 text-base-content/50 flex flex-row items-center justify-center gap-2 rounded-md border p-1 text-center text-xs;
}
.tk-icon {
@apply hidden;
}
}
.tk-replies .tk-content > span:first-child {
/* 回复提示回复xxx样式 */
@apply text-base-content/50 text-xs;
}
.tk-expand-wrap,
.tk-collapse-wrap {
@apply mt-1 flex items-center justify-center text-center;
}
.tk-expand {
@apply bg-base-200/50 hover:bg-primary/50 w-full cursor-pointer rounded-md py-1 text-sm duration-300;
}
}
/* 图标样式 */
.tk-submit-action-icon {
@apply fill-primary inline-block max-h-6 min-h-6 max-w-6 min-w-6 cursor-pointer;
}
.tk-action-icon {
@apply fill-primary inline-block max-h-5 min-h-5 max-w-5 min-w-5 overflow-clip;
}
.tk-icon {
@apply fill-primary inline-block max-h-4 min-h-4 max-w-4 min-w-4 overflow-clip;
}
.tk-tag {
@apply border-base-300 rounded-lg border p-1 text-xs;
}
}
.tk-footer {
@apply mt-4 w-full text-right text-sm;
a {
@apply text-primary;
}
}
.tk-admin-container {
@apply absolute z-10 h-3/4 w-full overflow-hidden bg-black/30 backdrop-blur-sm;
&:not(:has(.tk-admin.__show)) {
display: none;
}
.tk-admin {
@apply relative flex h-full w-full items-center justify-center text-center;
.tk-admin-close {
@apply fill-primary absolute top-[0.65rem] right-2 z-50 h-4 w-4;
@variant md {
@apply top-4 right-3 h-8 w-8;
}
}
> div {
@apply flex h-full w-full items-center justify-center;
}
}
.tk-login {
@apply flex flex-col items-center gap-4 p-4;
.tk-login-title {
@apply text-2xl font-bold;
}
}
.tk-panel {
@apply h-full w-full overflow-y-scroll;
.tk-panel-title {
@apply top-0 left-0 z-40 flex w-full flex-row items-center justify-between p-4;
/* 管理面板标题 */
div {
@apply text-xl font-bold;
}
a {
@apply border-base-300 bg-base-200/50 hover:bg-primary mx-6 rounded-xl border px-3 py-1 text-xs duration-300;
}
}
.tk-tabs {
@apply border-base-300 flex flex-row items-center justify-between border-b-2 px-4 text-center text-lg;
.tk-tab {
@apply hover:bg-primary w-full min-w-fit cursor-pointer py-1 duration-300;
&.__active {
@apply border-primary border-b-2;
}
}
}
.tk-admin-warn {
@apply m-2 rounded-sm border-l-4 border-yellow-400 bg-yellow-100 p-4 text-start text-yellow-700;
a {
@apply font-semibold text-yellow-900;
}
}
/* 评论管理样式 */
.tk-admin-comment {
@apply p-4;
}
.tk-admin-comment-filter {
@apply flex flex-row items-center justify-between gap-2 p-4;
div {
@apply w-full;
input {
@apply border-base-300 bg-base-200/50 w-full rounded-xl border px-2 py-1;
&:focus {
outline: none;
}
}
}
select {
@apply border-base-300 bg-base-200/50 w-1/4 rounded-xl border p-2;
}
}
.tk-admin-comment-list {
@apply px-3 text-start;
}
.tk-admin-comment-item {
@apply border-base-300 border-b-2 py-1;
}
.tk-admin-comment-meta {
@apply flex flex-row flex-wrap items-center gap-2 text-start;
.tk-avatar {
@apply border-base-300 h-8 w-8 overflow-hidden rounded-full border;
}
a {
@apply hover:text-primary duration-300;
}
span:last-child,
.tk-time {
@apply text-base-content/50 text-sm;
}
}
.tk-pagination {
@apply flex flex-row flex-wrap items-center justify-between p-4;
> div {
@apply flex flex-row items-center gap-2;
}
input {
@apply border-base-300 bg-base-200/50 w-16 rounded-xl border px-2 py-1;
&::-webkit-outer-spin-button,
&::-webkit-inner-spin-button {
appearance: none;
}
&[type='number'] {
appearance: textfield;
}
&:focus {
outline: none;
}
}
}
.tk-pagination-pager {
@apply hover:bg-primary cursor-pointer rounded-md px-2 py-1;
&.__current {
@apply bg-primary;
}
}
/* 配置管理样式 */
.tk-admin-config {
@apply p-4;
}
.tk-admin-config-groups {
@apply flex flex-col items-center gap-3 px-4;
}
details {
@apply border-base-300 w-full overflow-hidden rounded-xl border duration-300;
summary {
@apply hover:bg-primary/50 w-full px-3 py-1 text-start text-2xl duration-300;
&::marker {
margin-right: 1.5rem;
}
}
&[open] {
summary {
@apply bg-primary/50;
}
}
}
.tk-admin-config-item {
@apply mt-4 grid w-full items-center gap-2 px-4;
grid-template-columns: 25% 75%;
.tk-admin-config-title {
@apply text-end text-lg;
}
input {
@apply border-base-300 bg-base-200/50 w-full rounded-xl border px-2 py-1;
&:focus {
outline: none;
}
}
.tk-admin-config-desc {
@apply text-base-content/50 text-start text-sm whitespace-pre-wrap;
}
}
/* 导入样式 */
.tk-admin-import {
@apply flex flex-col items-start gap-4 p-4;
.tk-admin-import-label {
@apply text-start text-xl font-bold;
}
select {
@apply border-base-300 bg-base-200/50 w-full rounded-xl border p-2;
}
input {
@apply border-base-300 bg-base-200/50 w-full rounded-xl border px-2 py-1;
&:focus {
outline: none;
}
}
.el-textarea {
@apply h-full w-full;
textarea {
@apply border-base-300 bg-base-200/50 h-full w-full rounded-xl border px-2 py-1;
&:focus {
outline: none;
}
}
}
}
/* 导出样式 */
.tk-admin-export {
@apply p-4;
}
}
}
.el-input-group {
@apply border-base-300 bg-base-200/50 flex w-full flex-row items-center overflow-hidden rounded-xl border text-sm;
div {
@apply bg-primary/50 w-fit px-2 py-1 whitespace-nowrap;
}
input {
@apply w-full bg-transparent px-2 py-1;
&:focus {
outline: none;
}
}
.el-button {
@apply border-none bg-none p-0;
}
}
.el-button {
@apply border-base-300 bg-primary rounded-xl border px-2 py-1 text-center text-sm text-nowrap duration-300;
&:not(.is-disabled) {
@apply hover:scale-105 hover:brightness-110 active:scale-95 active:brightness-90;
}
&.is-disabled {
@apply cursor-not-allowed brightness-75;
}
}
/* Markdown 样式 */
.tk-content,
.tk-preview-container {
/* 文本样式 */
@apply break-normal hyphens-auto whitespace-pre-wrap md:break-words md:hyphens-manual;
/* 标题通用样式 */
h1,
h2,
h3,
h4,
h5 {
display: inline;
width: 100%;
margin: 1rem 0 0.5rem;
scroll-margin-top: 4rem;
font-weight: bold;
}
/* 基础文本元素 */
p {
margin: 0.5rem 0;
}
a {
@apply text-primary underline decoration-dashed;
&[data-footnote-ref],
&[data-footnote-backref] {
scroll-margin-top: 4rem;
}
}
/* 代码样式 */
.code-toolbar {
@apply relative w-full;
.toolbar {
@apply absolute top-1 right-3 flex flex-row-reverse items-center justify-between gap-4 text-xs;
}
.copy-to-clipboard-button {
@apply border-base-300 bg-primary rounded-md border px-2 py-1 opacity-0 duration-300;
}
&:hover .copy-to-clipboard-button {
@apply opacity-100;
}
pre {
@apply rounded-md;
}
}
code:not(pre code) {
padding: 0 0.25rem;
@apply bg-primary/10 text-primary rounded-md;
}
/* 媒体元素 */
img:not(.tk-owo-emotion) {
position: relative;
margin: 1rem auto;
max-width: 75%;
max-height: 40rem;
@apply rounded-md;
}
img.tk-owo-emotion {
@apply inline-block h-[2em] self-baseline;
}
/* 分割线样式 */
hr {
margin: 1.5rem 0.25rem;
border: 1px dashed;
}
/* 引用块样式 */
blockquote {
padding: 0.25rem 0.25rem 0.25rem 0.75rem;
@apply border-primary bg-primary/10 my-2 rounded-sm border-l-4;
}
/* 折叠块样式 */
details {
@apply border-base-300 w-full overflow-hidden rounded-xl border duration-300;
summary {
@apply hover:bg-primary/50 w-full px-3 py-1 text-start text-2xl duration-300;
&::marker {
margin-right: 1.5rem;
}
}
&[open] {
summary {
@apply bg-primary/50;
}
}
}
}

View File

@ -1,44 +0,0 @@
:root {
/* 字体大小 */
--waline-font-size: 1rem;
/* 常规颜色 */
--waline-white: #fff;
--waline-light-grey: #999;
--waline-dark-grey: #666;
/* 主题色 */
--waline-theme-color: var(--color-primary);
--waline-active-color: var(--color-secondary);
/* 布局颜色 */
--waline-color: var(--color-base-content);
--waline-bg-color: var(--color-base-100);
--waline-bg-color-light: var(--color-base-200);
--waline-bg-color-hover: var(--color-base-200);
--waline-border-color: var(--color-base-200);
--waline-disable-bg-color: color-mix(in oklab, var(--color-base-200) 25%, transparent);
--waline-disable-color: color-mix(in oklab, var(--color-base-content) 75%, transparent);
--waline-code-bg-color: var(--color-base-100);
/* 特殊颜色 */
--waline-bq-color: #f0f0f0;
/* 头像 */
--waline-avatar-size: 3.25rem;
--waline-m-avatar-size: calc(var(--waline-avatar-size) * 9 / 13);
/* 徽章 */
--waline-badge-color: var(--color-accent);
--waline-badge-font-size: 0.775em;
/* 信息 */
--waline-info-bg-color: color-mix(in oklab, var(--color-base-content) 15%, transparent);
--waline-info-color: color-mix(in oklab, var(--color-base-content) 60%, transparent);
--waline-info-font-size: 0.625em;
/* 渲染选择 */
--waline-border: 1px solid var(--waline-border-color);
--waline-avatar-radius: 50%;
--waline-box-shadow: none;
}