From adaf5b21955c263cc9dca004bd28be2fa036565f Mon Sep 17 00:00:00 2001 From: npmrun <1549469775@qq.com> Date: Thu, 23 Apr 2026 00:36:18 +0800 Subject: [PATCH] style(markdown): refine SCSS styles for markdown components and enhance code block presentation - Updated SCSS styles for markdown elements, improving visual consistency and readability. - Enhanced the appearance of code blocks with new background colors, borders, and shadows. - Introduced responsive design adjustments for better mobile compatibility. - Added new styles for headings, links, and blockquotes to improve overall aesthetics. These changes significantly enhance the user experience when interacting with markdown content, making it more visually appealing and easier to read. --- app/assets/scss/markdown/green.scss | 626 +++++++++++++-------------- app/assets/scss/markdown/highlight.scss | 54 +++ app/pages/@[publicSlug]/posts/[postSlug].vue | 2 +- app/pages/login/index.vue | 53 ++- app/pages/register/index.vue | 28 +- packages/drizzle-pkg/db.sqlite | Bin 147456 -> 147456 bytes 6 files changed, 407 insertions(+), 356 deletions(-) diff --git a/app/assets/scss/markdown/green.scss b/app/assets/scss/markdown/green.scss index a08ba4f..871f046 100644 --- a/app/assets/scss/markdown/green.scss +++ b/app/assets/scss/markdown/green.scss @@ -1,364 +1,356 @@ @mixin chinese() { - &.chinese { - text-indent: 1.5em; - font-weight: 300; - h1, - h2, - h3, - h4, - h5, - h6, - ol, - ul, - blockquote, - details, - summary, - pre, - .tabs { - text-indent: 0; - } + &.chinese { + text-indent: 1.5em; + font-weight: 300; + + h1, + h2, + h3, + h4, + h5, + h6, + ol, + ul, + blockquote, + details, + summary, + pre, + .tabs { + text-indent: 0; } + } } + .markdown-body { - --color-base: #ef4444; - --markdown-bg: transparent; - --color-bg: #ff47479c; - --color-light: #ef44441a; - --color-extra: rgba(239, 68, 68, 0.3); - --color-more: rgba(239, 68, 68, 0.4); + --color-base: var(--color-accent-fg); + --color-soft-bg: color-mix(in srgb, var(--color-base) 8%, transparent); + --color-softer-bg: color-mix(in srgb, var(--color-base) 4%, transparent); + --markdown-bg: color-mix(in srgb, var(--color-canvas-default) 92%, transparent); + --markdown-shadow: 0 2px 8px rgba(15, 23, 42, 0.08); + --markdown-radius: 10px; + --markdown-padding: 1.6em; +} + +.dark .markdown-body { + --color-fg-default: #e5e7eb; + --color-fg-muted: #c0c7d1; + --color-fg-subtle: #9ca3af; + --color-canvas-default: #111827; + --color-canvas-subtle: #1f2937; + --color-border-default: #374151; + --color-border-muted: #2c3646; + --color-neutral-muted: rgba(148, 163, 184, 0.25); + --color-accent-fg: #60a5fa; + --markdown-bg: color-mix(in srgb, var(--color-canvas-default) 86%, transparent); + --markdown-shadow: 0 10px 28px rgba(2, 6, 23, 0.28); + --code-bg: #0f172a; + --code-head-bg: #172133; + --code-border: #334155; + --code-shadow: rgba(2, 6, 23, 0.45); } .markdown-body.green { - background-color: var(--markdown-bg); - box-shadow: 0 2px 8px rgba(0,0,0,0.1); - border-radius: 10px; - padding: 1.6em; - @media screen and (max-width: 768px) { - padding: 0; - box-shadow: none; - } + background-color: var(--markdown-bg); + border-radius: var(--markdown-radius); + padding: var(--markdown-padding); + box-shadow: var(--markdown-shadow); + border: 1px solid color-mix(in srgb, var(--color-border-default) 72%, transparent); + color: var(--color-fg-default); + font-size: 1rem; + line-height: 1.9; + letter-spacing: 0.01em; - strong { - &::before{ - content: "『"; - } - &::after{ - content: "』"; - } - // color: #ff4d20; - } + @media screen and (max-width: 768px) { + background: transparent; + border: 0; + box-shadow: none; + border-radius: 0; + padding: 0; + font-size: 0.98rem; + line-height: 1.85; + } - /* 块/段落引用 */ - // blockquote { - // position: relative; - // // color: #555; - // font-weight: 400; - // border-left: 6px solid var(--color-base); - // padding-left: 1em; - // margin-left: 0; - // padding: 1em; - // background-color: var(--color-light); - // } - - blockquote { - position: relative; - z-index: 600; - padding: 20px 20px 15px 20px; - line-height: 1.4 !important; - background-color: rgba(239, 68, 68, 0.06); - border-radius: .4em; - > * { - position: relative; - &:first-child:before { - content: '\201C'; - color: var(--color-light); - font-size: 6.5em; - font-weight: 700; - transform: rotate(15deg) translateX(-10px); - opacity: 1; - position: absolute; - top: -.4em; - left: -.2em; - text-shadow: none; - z-index: -10; - } - } - } + p { + color: var(--color-fg-default); + } + + h1, + h2, + h3, + h4, + h5, + h6 { + margin-top: 1.35em; + margin-bottom: 0.65em; + line-height: 1.35; + color: var(--color-fg-default); + scroll-margin-top: 5rem; + } + + h1 { + font-size: 2em; + } + + h2 { + font-size: 1.65em; + padding-bottom: 0.25em; + border-bottom: 1px solid var(--color-border-muted); + } + + h3 { + font-size: 1.35em; + } - .tabs{ - margin-top: 0; - margin-bottom: 1em; + h4 { + font-size: 1.15em; + } + + a { + color: var(--color-base); + text-decoration: underline; + text-decoration-thickness: 1px; + text-decoration-color: color-mix(in srgb, var(--color-base) 45%, transparent); + text-underline-offset: 0.18em; + transition: color 0.2s ease, text-decoration-color 0.2s ease; + + &:hover { + color: color-mix(in srgb, var(--color-base) 78%, var(--color-fg-default)); + text-decoration-color: currentColor; } + } - /* 让链接在 hover 状态下显示下划线 */ - // a { - // color: var(--color-base); - // text-decoration: none; - // &:hover { - // text-decoration: underline; - // } - // } - a { - position: relative; - z-index: 10; - transition: color 0.3s linear; + blockquote { + margin-left: 0; + padding: 0.95em 1.05em; + border-left: 4px solid var(--color-base); + border-radius: 0.55rem; + background: var(--color-softer-bg); + color: var(--color-fg-muted); + } + + hr { + height: 1px; + margin: 1.6rem 0; + background: var(--color-border-muted); + } + + img { + border-radius: 0.8rem; + border: 1px solid var(--color-border-default); + box-shadow: 0 6px 20px rgba(15, 23, 42, 0.08); + } + + figure { + margin: 1.4em auto; + } + + figcaption { + margin-top: 0.55rem; + font-size: 0.82em; + color: var(--color-fg-subtle); + text-align: center; + } + + :not(pre) > code { + padding: 0.12em 0.48em; + margin: 0 0.12em; + border-radius: 0.4rem; + background: var(--color-soft-bg); + border: 1px solid color-mix(in srgb, var(--color-base) 26%, var(--color-border-default)); + color: color-mix(in srgb, var(--color-base) 72%, var(--color-fg-default)); + font-size: 0.92em; + } + + pre, + pre code { + font-family: "JetBrains Mono", "Fira Code", Consolas, monospace; + } + + .code-block-wrapper { + margin: 1rem 0 1.25rem; + border: 1px solid var(--color-border-default); + border-radius: 0.8rem; + overflow: hidden; + background: var(--color-canvas-subtle); + color: var(--color-fg-default); + box-shadow: 0 4px 14px rgba(15, 23, 42, 0.07); + + .code-header { + display: flex; + align-items: center; + justify-content: space-between; + gap: 0.75rem; + padding: 0.55rem 0.85rem; + border-bottom: 1px solid var(--color-border-default); + background: color-mix(in srgb, var(--color-base) 7%, var(--color-canvas-subtle)); + + .code-lang { + font-size: 0.76rem; + font-weight: 600; + letter-spacing: 0.05em; + color: var(--color-fg-subtle); + text-transform: uppercase; + } + + .copy-btn { + border: 1px solid var(--color-border-default); + background: var(--color-canvas-default); + color: var(--color-fg-muted); + border-radius: 0.45rem; + padding: 0.2rem 0.58rem; + font-size: 0.74rem; + line-height: 1.35; cursor: pointer; - font-weight: bolder; - // text-decoration: underline #c7254e; - text-decoration: none; - color: var(--color-base); - border-bottom: 1px solid currentColor; - padding: 0 4px; - &[data-footnote-backref], - &[data-footnote-ref] { - // text-decoration: none; - border: none; - &:hover { - background: none; - animation: none; - } - } + transition: all 0.18s ease; + &:hover { - content: ''; - // text-decoration: none; - border: none; - background: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 4'%3E%3Cpath fill='none' stroke='%23ff4d20' d='M0 3.5c5 0 5-3 10-3s5 3 10 3 5-3 10-3 5 3 10 3'/%3E%3C/svg%3E") - repeat-x 0 100%; - background-size: 20px auto; - animation: waveMove 1s infinite linear; + border-color: var(--color-base); + color: var(--color-base); } - @keyframes waveMove { - 0% { - background-position: 0 100%; - } - 100% { - background-position: -20px 100%; - } + + &.is-copied { + border-color: #22c55e; + color: #16a34a; + background: color-mix(in srgb, #22c55e 12%, var(--color-canvas-default)); } + } } pre { - background: #f7f7f7; - font-size: 0.95em; - // /* border: 1px solid #ddd; */ - // padding: 1em 1.5em; - display: block; - -webkit-overflow-scrolling: touch; + margin: 0; + padding: 1.05rem 1.1rem; + overflow-x: auto; + background: transparent; + box-shadow: none; } + } - pre, - pre code { - font-family: "JetBrains Mono", "Fira Code", Consolas, monospace; + table { + width: max-content; + min-width: 0; + display: block; + max-width: 100%; + overflow-x: auto; + margin: 1.2rem 0; + border: 1px solid color-mix(in srgb, var(--color-border-default) 88%, transparent); + border-radius: 0.8rem; + border-collapse: separate; + border-spacing: 0; + background: color-mix(in srgb, var(--color-canvas-default) 94%, transparent); + box-shadow: 0 6px 16px rgba(15, 23, 42, 0.08); + + caption { + padding: 0.62em 0.95em; + text-align: left; + color: var(--color-fg-subtle); + border-bottom: 1px solid color-mix(in srgb, var(--color-border-default) 84%, transparent); + background: color-mix(in srgb, var(--color-canvas-subtle) 80%, transparent); } - // /* 底部印刷体、版本等标记 */ - small, - /* 图片说明 */ - figcaption { - font-size: 0.75em; - color: #888; + thead th { + font-weight: 600; + color: var(--color-fg-default); + background: color-mix(in srgb, var(--color-base) 12%, var(--color-canvas-default)); + border-bottom: 1px solid color-mix(in srgb, var(--color-border-default) 86%, transparent); } - // .markdown-body { - legend { - color: #000; - font-weight: inherit; + + th, + td { + padding: 0.62em 0.95em; + white-space: nowrap; + border-right: 1px solid color-mix(in srgb, var(--color-border-default) 82%, transparent); + border-bottom: 1px solid color-mix(in srgb, var(--color-border-default) 82%, transparent); } - caption { - color: #000; - font-weight: inherit; + + th:last-child, + td:last-child { + border-right: 0; } - del { - text-decoration: line-through var(--color-base) 2px; + + tbody tr:last-child td { + border-bottom: 0; } - /* 行内代码:仅匹配非代码块场景,避免和 pre/code 嵌套互相覆盖 */ - :not(pre) > code { - color: #d73a49; - background-color: rgba(160, 174, 192, 0.25); - font-family: inherit; - font-size: 1em; - border-radius: 4px; - padding: 1px 6px; - margin: 0 2px; - vertical-align: bottom; + + tbody tr:nth-child(even) td { + background: color-mix(in srgb, var(--color-canvas-subtle) 52%, transparent); } - /* MarkdownIt highlight 输出的代码块容器 */ - .code-block-wrapper { - margin: 1rem 0; - border-radius: 10px; - overflow: hidden; - box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15); - background: #f7f7f7; - color: #333; - font-family: "JetBrains Mono", "Fira Code", Consolas, monospace; - font-size: 0.95em; - line-height: 1.5; - - .code-header { - display: flex; - align-items: center; - justify-content: space-between; - padding: 0.6rem 1rem; - background: #efefef; - - .code-lang { - font-size: 0.78rem; - font-weight: 600; - letter-spacing: 0.02em; - color: #64748b; - text-transform: uppercase; - } - - .copy-btn { - border: 1px solid #d0d7de; - background: #fff; - color: #475569; - border-radius: 6px; - padding: 0.2rem 0.6rem; - font-size: 0.75rem; - line-height: 1.3; - cursor: pointer; - transition: all 0.18s ease; - - &:hover { - background: #f8fafc; - border-color: #b8c2cc; - color: #334155; - } - - &.is-copied { - background: #dcfce7; - border-color: #86efac; - color: #166534; - } - } - } + tbody tr:hover td { + background: color-mix(in srgb, var(--color-base) 10%, var(--color-canvas-subtle)); + } + } - pre { - margin: 0; - padding: 1.2rem; - overflow-x: auto; - background: transparent; - box-shadow: none; - - code { - display: block; - padding: 0; - margin: 0; - color: inherit; - background: transparent; - border-radius: 0; - white-space: pre; - } + ul.toc li { + list-style-type: none; - } + a { + border: 0; + text-decoration: none; } - table { - width: fit-content; - display: block; - max-width: 100%; - overflow-x: auto; - border: 1px solid var(--color-light); - border-radius: 8px; - border-collapse: separate; - border-spacing: 0; - margin: 1rem 0; - background: #fff; - - caption { - padding: 0.6em 1em; - text-align: left; - color: var(--color-fg-subtle); - border-bottom: 1px solid var(--color-light); - background: #fff; - } + } - thead th { - background: var(--color-extra); - border-bottom: 1px solid var(--color-light); - font-weight: 600; - } + @include chinese; +} - th, - td { - padding: 0.55em 1em; - white-space: nowrap; - border-right: 1px solid var(--color-light); - border-bottom: 1px solid var(--color-light); - } +.dark .markdown-body.green { + .code-block-wrapper { + border-color: var(--code-border); + background: var(--code-bg); + box-shadow: 0 10px 26px var(--code-shadow); - th:last-child, - td:last-child { - border-right: 0; - } + .code-header { + border-bottom-color: var(--code-border); + background: var(--code-head-bg); - tbody tr:last-child td { - border-bottom: 0; + .code-lang { + color: #bfdbfe; + } + + .copy-btn { + border-color: #475569; + background: #1e293b; + color: #cbd5e1; + + &:hover { + border-color: #60a5fa; + background: #0f172a; + color: #93c5fd; } - tbody tr:hover td { - background: var(--color-light); + &.is-copied { + border-color: #22c55e; + color: #86efac; + background: #052e16; } + } } - h1, - h2, - h3, - h4, - h5, - h6 { - margin-top: 1.2em; - margin-bottom: 0.6em; - line-height: 1.35; - position: relative; - } - h1 { - font-size: 1.8em; - } - h2 { - font-size: 1.6em; - } - h3 { - font-size: 1.4em; - } - h4 { - font-size: 1.2em; - } - h5 { - font-size: 1em; + + pre { + background: transparent; } - h6 { - font-size: 1em; + } + + table { + border-color: color-mix(in srgb, var(--color-border-default) 92%, transparent); + background: color-mix(in srgb, var(--color-canvas-default) 90%, transparent); + box-shadow: 0 10px 24px rgba(2, 6, 23, 0.26); + + caption { + background: color-mix(in srgb, var(--color-canvas-subtle) 90%, transparent); + border-bottom-color: color-mix(in srgb, var(--color-border-default) 90%, transparent); } - - ::-webkit-calendar-picker-indicator { - filter: invert(50%); + + thead th { + background: color-mix(in srgb, var(--color-base) 18%, var(--color-canvas-subtle)); } - em { - // color: #000; - font-weight: inherit; - position: relative; - &:after { - position: absolute; - top: 0.65em; - left: 0; - width: 100%; - overflow: hidden; - white-space: nowrap; - pointer-events: none; - color: var(--color-base); - content: '・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・'; - } + + tbody tr:nth-child(even) td { + background: color-mix(in srgb, var(--color-canvas-subtle) 70%, transparent); } - ul.toc { - li { - list-style-type: none; - a { - text-decoration: none; - border: 0; - list-style-type: none; - } - } + + tbody tr:hover td { + background: color-mix(in srgb, var(--color-base) 16%, var(--color-canvas-subtle)); } - @include chinese; + } } diff --git a/app/assets/scss/markdown/highlight.scss b/app/assets/scss/markdown/highlight.scss index 7e5a278..8b4081b 100644 --- a/app/assets/scss/markdown/highlight.scss +++ b/app/assets/scss/markdown/highlight.scss @@ -51,3 +51,57 @@ } } } + +.dark .markdown-body { + .code-block-wrapper { + pre { + code.hljs { + color: #e5e7eb; + } + + .hljs-comment, + .hljs-quote { + color: #94a3b8; + font-style: italic; + } + + .hljs-keyword, + .hljs-selector-tag, + .hljs-literal, + .hljs-section, + .hljs-link { + color: #c084fc; + } + + .hljs-string, + .hljs-title, + .hljs-name, + .hljs-type, + .hljs-attribute, + .hljs-symbol, + .hljs-bullet, + .hljs-addition { + color: #5eead4; + } + + .hljs-number, + .hljs-variable, + .hljs-template-variable, + .hljs-regexp, + .hljs-meta .hljs-string { + color: #fbbf24; + } + + .hljs-built_in, + .hljs-function, + .hljs-class .hljs-title { + color: #60a5fa; + } + + .hljs-deletion, + .hljs-subst { + color: #f87171; + } + } + } +} diff --git a/app/pages/@[publicSlug]/posts/[postSlug].vue b/app/pages/@[publicSlug]/posts/[postSlug].vue index c8fbbac..d6a32bf 100644 --- a/app/pages/@[publicSlug]/posts/[postSlug].vue +++ b/app/pages/@[publicSlug]/posts/[postSlug].vue @@ -116,7 +116,7 @@ const editPostHref = computed(() => {{ leadSummary }}

diff --git a/app/pages/login/index.vue b/app/pages/login/index.vue index efb875a..c58fd43 100644 --- a/app/pages/login/index.vue +++ b/app/pages/login/index.vue @@ -49,9 +49,8 @@ onMounted(() => { }) const loading = ref(false) -const resultType = ref<'success' | 'error' | ''>('') -const resultMessage = ref('') const route = useRoute() +const toast = useToast() const { refresh } = useAuthSession() const { allowRegister } = useGlobalConfig() const { fetchData, getApiErrorMessage } = useClientApi() @@ -79,8 +78,6 @@ const validate = (formState: LoginFormState): FormError[] => { } const onSubmit = async (_event: FormSubmitEvent) => { - resultType.value = '' - resultMessage.value = '' loading.value = true try { @@ -97,16 +94,20 @@ const onSubmit = async (_event: FormSubmitEvent) => { await refresh(true) - resultType.value = 'success' - resultMessage.value = `登录成功,欢迎 ${res.user.username}` + toast.add({ + title: `登录成功,欢迎 ${res.user.username}`, + color: 'success', + }) const redirectCandidate = Array.isArray(route.query.redirect) ? route.query.redirect[0] : route.query.redirect const redirectTarget = normalizeSafeRedirect(redirectCandidate, DEFAULT_AUTHENTICATED_LANDING_PATH) await navigateTo(redirectTarget) } catch (error: unknown) { - resultType.value = 'error' - resultMessage.value = getApiErrorMessage(error) + toast.add({ + title: getApiErrorMessage(error), + color: 'error', + }) try { await refreshCaptcha() } catch { @@ -160,22 +161,28 @@ const onSubmit = async (_event: FormSubmitEvent) => { -
- 验证码 +
+
+ 验证码 +
+ + 看不清?换一张 + +
- - 换一张 - +

+ 请先识别图片字符再输入,不区分大小写。 +

@@ -184,14 +191,6 @@ const onSubmit = async (_event: FormSubmitEvent) => { - -
没有账号?去注册 diff --git a/app/pages/register/index.vue b/app/pages/register/index.vue index cf55bd7..9f55492 100644 --- a/app/pages/register/index.vue +++ b/app/pages/register/index.vue @@ -155,22 +155,28 @@ const onSubmit = async (_event: FormSubmitEvent) => { -
- 验证码 +
+
+ 验证码 +
+ + 看不清?换一张 + +
- - 换一张 - +

+ 请先识别图片字符再输入,不区分大小写。 +

diff --git a/packages/drizzle-pkg/db.sqlite b/packages/drizzle-pkg/db.sqlite index b1c19eadd2f76fda410bb9734ba03ac196182f6f..123b9e66ce4afa32a78563fa7fa4eb6a927254b6 100644 GIT binary patch delta 153 zcmZo@;B08%oFL8EIZ?)$v2$a>5`AV?zPFp%4c_sYnHZZH8zd*|CYxGX=$cqqB~FsnXin^Ab_XMV YWg^U(9OJ(NsNrohd%$+~0LGv10k|G60RR91