feat(theme): 主题结构调整 增加actions自动构建
Theme CD / cd (release) Failing after 1s

这个提交包含在:
rohow
2026-01-20 17:06:13 +08:00
未验证
父节点 4d7d4cc4e3
当前提交 dc0e443f01
修改 66 个文件,包含 52 行新增60 行删除
+12
查看文件
@@ -0,0 +1,12 @@
interface MenuState {
isOpen: boolean;
handleToggleMenu(): void;
}
export const menu = (): MenuState => ({
isOpen: false,
handleToggleMenu() {
this.isOpen = !this.isOpen;
}
})
+29
查看文件
@@ -0,0 +1,29 @@
interface ThemeModeState {
init(): void;
storedTheme: string;
handleToggleThemeMode(): void;
}
export const themeMode = ():ThemeModeState => ({
storedTheme: '',
init() {
const storedTheme = localStorage.getItem("theme-mode") || (window.matchMedia("(prefers-color-scheme: dark)").matches ? "dark" : "light");
if (!storedTheme) return;
document.documentElement.setAttribute("data-color-scheme", storedTheme);
this.storedTheme = storedTheme;
},
handleToggleThemeMode() {
const targetTheme = this.storedTheme === "dark" ? "light" : "dark";
document.documentElement.setAttribute("data-color-scheme", targetTheme);
this.storedTheme = targetTheme;
localStorage.setItem("theme-mode", targetTheme);
},
});
+51
查看文件
@@ -0,0 +1,51 @@
interface upvoteState {
init(): void;
upvotedNames: string[];
getIsUpvoted(id: string): boolean;
handleUpvote(name: string): void;
}
export const upvote = (key: string, group: string, plural: string): upvoteState => ({
upvotedNames: [],
init() {
this.upvotedNames = JSON.parse(localStorage.getItem(`walker.upvoted.${key}.names`) || "[]");
},
getIsUpvoted(id: string) {
return this.upvotedNames.includes(id);
},
async handleUpvote(name) {
if (this.getIsUpvoted(name)) return
const xhr = new XMLHttpRequest();
xhr.open("POST", "/apis/api.halo.run/v1alpha1/trackers/upvote");
xhr.setRequestHeader("Content-Type", "application/json");
xhr.onload = () => {
this.upvotedNames = [...this.upvotedNames, name];
localStorage.setItem(`walker.upvoted.${key}.names`, JSON.stringify(this.upvotedNames));
const upvoteNode = document.querySelector("[data-upvote-" + key + '-name="' + name + '"]');
if (!upvoteNode) {
return;
}
const upvoteCount = parseInt(upvoteNode.textContent || "0");
upvoteNode.textContent = upvoteCount + 1 + "";
};
xhr.onerror = function () {
alert("网络请求失败,请稍后再试");
};
xhr.send(
JSON.stringify({
group: group,
plural: plural,
name: name,
})
);
},
});
二进制文件未显示。
二进制文件未显示。
二进制文件未显示。
二进制
查看文件
二进制文件未显示。
二进制
查看文件
二进制文件未显示。
二进制文件未显示。
二进制文件未显示。
二进制
查看文件
二进制文件未显示。
二进制文件未显示。
二进制文件未显示。
二进制文件未显示。
+19
查看文件
@@ -0,0 +1,19 @@
import "./styles/style.scss";
import "./styles/font-hack.scss";
import "./styles/font-pixel.scss";
import Alpine from 'alpinejs'
import {upvote} from './alpine/upvote'
import {themeMode} from './alpine/themeMode'
import {menu} from './alpine/menu'
import {typewriterEffect} from './utils'
window.Alpine = Alpine
Alpine.data('upvote', upvote)
Alpine.data('themeMode', themeMode)
Alpine.data('menu', menu)
Alpine.start()
document.addEventListener('DOMContentLoaded', () => typewriterEffect('.typed-text'))
+92
查看文件
@@ -0,0 +1,92 @@
.button-container {
display: table;
margin-left: auto;
margin-right: auto;
}
button,
.button,
a.button {
position: relative;
display: flex;
align-items: center;
justify-content: center;
padding: 8px 18px;
margin-bottom: 5px;
text-align: center;
border-radius: 8px;
border: 1px solid transparent;
appearance: none;
cursor: pointer;
outline: none;
/* variants */
&.outline {
background: transparent;
box-shadow: none;
padding: 8px 18px;
:hover {
transform: none;
box-shadow: none;
}
}
&.primary {
box-shadow: 0 4px 6px rgba(50, 50, 93, .11), 0 1px 3px rgba(0, 0, 0, .08);
&:hover {
box-shadow: 0 2px 6px rgba(50, 50, 93, .21), 0 1px 3px rgba(0, 0, 0, .08);
}
}
&.link {
background: none;
font-size: 1rem;
}
/* sizes */
&.small {
font-size: .8rem;
}
&.wide {
min-width: 200px;
padding: 14px 24px;
}
}
a.read-more,
a.read-more:hover,
a.read-more:active {
display: inline-flex;
background: none;
box-shadow: none;
padding: 0;
margin: 20px 0;
max-width: 100%;
}
.code-toolbar {
margin-bottom: 20px;
.toolbar-item a {
position: relative;
display: inline-flex;
align-items: center;
justify-content: center;
padding: 3px 8px;
margin-bottom: 5px;
text-align: center;
font-size: 13px;
font-weight: 500;
border-radius: 8px;
border: 1px solid transparent;
appearance: none;
cursor: pointer;
outline: none;
}
}
+33
查看文件
@@ -0,0 +1,33 @@
/*!
* Hack typeface https://github.com/source-foundry/Hack
* License: https://github.com/source-foundry/Hack/blob/master/LICENSE.md
*/
/* FONT PATHS
* -------------------------- */
@font-face {
font-family: 'Hack';
src: url('../fonts/hack-regular.woff2?sha=3114f1256') format('woff2'), url('../fonts/hack-regular.woff?sha=3114f1256') format('woff');
font-weight: 400;
font-style: normal;
}
@font-face {
font-family: 'Hack';
src: url('../fonts/hack-bold.woff2?sha=3114f1256') format('woff2'), url('../fonts/hack-bold.woff?sha=3114f1256') format('woff');
font-weight: 700;
font-style: normal;
}
@font-face {
font-family: 'Hack';
src: url('../fonts/hack-italic.woff2?sha=3114f1256') format('woff2'), url('../fonts/hack-italic.woff?sha=3114f1256') format('woff');
font-weight: 400;
font-style: italic;
}
@font-face {
font-family: 'Hack';
src: url('../fonts/hack-bolditalic.woff2?sha=3114f1256') format('woff2'), url('../fonts/hack-bolditalic.woff?sha=3114f1256') format('woff');
font-weight: 700;
font-style: italic;
}
+4
查看文件
@@ -0,0 +1,4 @@
@font-face {
font-family: Pixel;
src: url("../fonts/fusion-pixel-12px-proportional-zh_hans.woff2");
}
+83
查看文件
@@ -0,0 +1,83 @@
@import "variables";
.footer {
padding: 40px 0 0 0;
flex-grow: 0;
opacity: .5;
&__inner {
display: flex;
flex-wrap: wrap;
align-items: center;
justify-content: center;
margin: 0;
width: 760px;
max-width: 100%;
@media (max-width: $tablet-max-width) {
flex-direction: column;
}
}
a {
color: inherit;
}
.copyright {
display: flex;
flex-direction: row;
align-items: center;
font-size: 1rem;
color: var(--light-color-secondary);
&--user {
margin: auto;
text-align: center;
}
& > *:first-child:not(:only-child) {
margin-right: 10px;
@media (max-width: $tablet-max-width) {
border: none;
padding: 0;
margin: 0;
}
}
@media (max-width: $tablet-max-width) {
flex-direction: column;
margin-top: 10px;
}
}
.copyright-theme-sep {
@media (max-width: $tablet-max-width) {
display: none;
}
}
.copyright-theme {
@media (max-width: $tablet-max-width) {
font-size: 0.75rem;
}
}
.beian {
display: flex;
flex-direction: row;
justify-content: center;
flex-basis: 100%;
align-items: center;
font-size: 1rem;
color: var(--light-color-secondary);
margin-top: 8px;
span {
display: inline-flex;
align-items: center;
gap: 4px;
padding: 0 8px;
}
}
}
+83
查看文件
@@ -0,0 +1,83 @@
@import "variables";
.header {
display: flex;
flex-direction: column;
position: relative;
&__inner {
display: flex;
align-items: center;
justify-content: space-between;
}
.dividing {
flex: 1;
background: repeating-linear-gradient(90deg, var(--foreground), var(--foreground) 2px, transparent 0, transparent 10px);
display: block;
width: 100%;
height: 25px;
}
.menu {
margin: 20px 0;
&__inner {
display: flex;
flex-wrap: wrap;
list-style: none;
margin: 0;
padding: 0;
li {
position: relative;
flex: 0 0 auto;
padding-bottom: 10px;
&.active {
color: var(--cyan);
}
&:not(:last-of-type) {
margin-right: 20px;
}
}
}
&__sub-inner {
position: absolute;
z-index: 99;
top: 35px;
left: 0;
display: none;
margin: 0;
padding: 10px;
list-style: none;
border: 2px solid var(--red);
background: var(--background);
box-shadow: 0 10px var(--background), -10px 10px var(--background), 10px 10px var(--background);
li {
padding: 5px;
white-space: nowrap;
text-decoration: underline;
color: var(--green);
&:not(:last-of-type) {
margin-right: 0;
}
}
&.open {
display: block;
}
}
}
.button {
background-color: transparent;
color: var(--foreground);
margin: 0 0 0 .5rem;
padding: 0;
}
}
+22
查看文件
@@ -0,0 +1,22 @@
.logo {
display: flex;
align-items: center;
.icon {
max-width: 100%;
max-height: 35px;
height: 100%;
font-size: 0;
object-fit: cover;
margin-right: 10px;
}
.text {
display: flex;
padding: 3px 10px;
color: var(--background);
background: var(--foreground);
text-decoration: none;
margin-right: 16px;
}
}
+261
查看文件
@@ -0,0 +1,261 @@
@import "variables";
html {
box-sizing: border-box;
}
*,
*:before,
*:after {
box-sizing: inherit;
}
body {
margin: 0;
padding: 0;
font-family: Hack, Monaco, Consolas, 'Ubuntu Mono', PingHei, 'PingFang SC', 'Microsoft YaHei', monospace;
font-size: 1rem;
line-height: 1.54;
background-color: var(--background);
color: var(--foreground);
text-rendering: optimizeLegibility;
-webkit-font-smoothing: antialiased;
-webkit-overflow-scrolling: touch;
-webkit-text-size-adjust: 100%;
@media (max-width: $phone-max-width) {
font-size: 1rem;
}
&.pixel_style {
font-family: Pixel, Monaco, Consolas, 'Ubuntu Mono', PingHei, 'PingFang SC', 'Microsoft YaHei', monospace;
}
}
h1, h2, h3, h4, h5, h6 {
font-weight: bold;
line-height: 1.3;
}
h1 {
font-size: 1.5rem;
margin-top: 1.5rem;
margin-bottom: .75rem;
}
h2 {
font-size: 1.3rem;
margin-top: 1.5rem;
margin-bottom: .75rem;
}
h3 {
font-size: 1.2rem;
margin-top: 1rem;
margin-bottom: .5rem;
}
h4, h5, h6 {
font-size: 1.15rem;
margin-top: .5rem;
margin-bottom: .25rem;
}
a {
color: var(--blue);
}
img {
display: block;
max-width: 100%;
&.left {
margin-right: auto;
}
&.center {
margin-left: auto;
margin-right: auto;
}
&.right {
margin-left: auto;
}
}
p {
margin-top: .75rem;
margin-bottom: .75rem;
}
figure {
display: table;
max-width: 100%;
margin: 25px 0;
&.left {
img {
margin-right: auto;
}
}
&.center {
img {
margin-left: auto;
margin-right: auto;
}
}
&.right {
img {
margin-left: auto;
}
}
figcaption {
font-size: 14px;
padding: 5px 10px;
margin-top: 5px;
background: var(--foreground);
color: var(--background);
&.left {
text-align: left;
}
&.center {
text-align: center;
}
&.right {
text-align: right;
}
}
}
code {
font-family: Hack, Monaco, Consolas, 'Ubuntu Mono', PingHei, 'PingFang SC', 'Microsoft YaHei', monospace;
font-feature-settings: normal;
background: var(--selectionBackground);
padding: 1px 4px;
margin: 0 4px;
font-size: .95rem;
}
pre {
font-family: Hack, Monaco, Consolas, 'Ubuntu Mono', PingHei, 'PingFang SC', 'Microsoft YaHei', monospace;
font-size: .95rem;
overflow: auto;
border-top: 1px solid rgba(255, 255, 255, .1);
border-bottom: 1px solid rgba(255, 255, 255, .1);
@media (max-width: $phone-max-width) {
white-space: pre-wrap;
word-wrap: break-word;
}
code {
padding: 0;
margin: 0;
background: none;
}
}
blockquote {
border-top: 1px solid var(--foreground);
border-bottom: 1px solid var(--foreground);
border-left: .5rem solid var(--foreground);
margin: 2rem 0;
padding: 1rem;
@media (max-width: $phone-max-width) {
padding-right: 0;
}
&:before {
content: '';
font-family: Georgia, serif;
font-size: 3.875rem;
position: absolute;
left: -40px;
top: -20px;
}
p:first-of-type {
margin-top: 0;
}
p:last-of-type {
margin-bottom: 0;
}
p {
position: relative;
}
}
table {
table-layout: fixed;
border-collapse: collapse;
width: 100%;
margin: 40px 0;
}
table, th, td {
border: 1px dashed var(--foreground);
padding: 10px;
}
th {
color: var(--foreground);
}
ul, ol {
margin-left: 30px;
padding: 0;
li {
position: relative;
p {
margin-top: .125rem;
margin-bottom: .125rem;
}
}
@media (max-width: $phone-max-width) {
margin-left: 20px;
}
}
ol {
list-style-type: decimal;
}
.container {
display: flex;
flex-direction: column;
padding: 40px;
max-width: 864px;
min-height: 100vh;
margin: 0 auto;
@media (max-width: $phone-max-width) {
padding: 20px;
}
}
.content {
display: flex;
flex-direction: column;
}
hr {
width: 100%;
border: none;
background: var(--foreground);
height: 1px;
}
+76
查看文件
@@ -0,0 +1,76 @@
@import 'variables';
.pagination {
&__title {
display: flex;
text-align: center;
position: relative;
margin: 100px 0 20px;
&-h {
text-align: center;
margin: 0 auto;
padding: 5px 10px;
background: var(--background);
font-size: .8rem;
text-transform: uppercase;
letter-spacing: .1em;
z-index: 1;
}
hr {
position: absolute;
left: 0;
right: 0;
width: 100%;
margin-top: 15px;
z-index: 0;
}
}
&__buttons {
display: flex;
align-items: center;
justify-content: space-between;
@media (max-width: $phone-max-width) {
flex-direction: column;
}
}
}
.button {
position: relative;
display: inline-flex;
align-items: center;
justify-content: center;
font-size: 1rem;
border-radius: 8px;
max-width: 40%;
padding: 0;
cursor: pointer;
appearance: none;
@media (max-width: $phone-max-width) {
max-width: 80%;
}
+ .button {
margin-left: 10px;
}
a {
display: flex;
padding: 8px 16px;
text-overflow: ellipsis;
white-space: nowrap;
overflow: hidden;
}
&__text {
text-overflow: ellipsis;
white-space: nowrap;
overflow: hidden;
}
}
+175
查看文件
@@ -0,0 +1,175 @@
@import "variables";
.index-content {
margin-top: 10px;
}
.framed {
border: 1px solid var(--red);
color: var(--red);
padding: 20px;
*:first-child {
margin-top: 0;
}
*:last-child {
margin-bottom: 0;
}
}
.posts {
width: 100%;
margin: 0 auto;
}
.post {
width: 100%;
text-align: left;
margin: 20px auto;
padding: 20px 0;
@media (max-width: $tablet-max-width) {
max-width: 660px;
}
&:not(:last-of-type) {
border-bottom: 1px solid var(--foreground);
}
%meta {
font-size: 1rem;
margin-bottom: 10px;
color: var(--brightBlue);
}
&-meta {
@extend %meta;
}
&-meta-inline {
@extend %meta;
display: inline;
}
&-title {
--border: 3px dotted var(--blue);
position: relative;
color: var(--blue);
margin: 0 0 15px;
padding-bottom: 15px;
font-weight: normal;
border-bottom: var(--border);
&::after {
content: "";
position: absolute;
bottom: 2px;
display: block;
width: 100%;
border-bottom: var(--border);
}
a {
text-decoration: none;
}
}
%tags {
margin-bottom: 20px;
font-size: 1rem;
}
&-tags {
@extend %tags;
display: block;
}
&-tag {
color: var(--green);
}
&-tags-inline {
@extend %tags;
display: inline;
@media (max-width: $phone-max-width) {
display: block;
}
}
&-content {
margin-top: 30px;
font-family: Hack, Monaco, Consolas, 'Ubuntu Mono', PingHei, 'PingFang SC', 'Microsoft YaHei', monospace;
}
&-cover {
border: 20px solid var(--foreground);
background: transparent;
margin: 40px 0;
padding: 20px;
@media (max-width: $phone-max-width) {
padding: 10px;
border-width: 10px;
}
}
ul {
list-style: none;
li:before {
content: '';
position: absolute;
left: -20px;
color: var(--foreground);
}
}
}
.post--regulation {
h1 {
justify-content: center;
}
h2 {
justify-content: center;
margin-bottom: 10px;
& + h2 {
margin-top: -10px;
margin-bottom: 20px;
}
}
}
.post-list {
padding: .25rem 0;
.post-date {
color: var(--foreground);
text-decoration: none;
}
a {
text-decoration: none;
}
.post-list-title {
text-decoration: underline;
}
.post-tag {
text-decoration: underline;
}
}
.comment-wrap {
position: relative;
z-index: 2;
}
+14
查看文件
@@ -0,0 +1,14 @@
@tailwind base;
@tailwind utilities;
@tailwind components;
@import 'buttons';
@import 'header';
@import 'logo';
@import 'main';
@import 'post';
@import 'pagination';
@import 'footer';
@import 'typed-text';
@import 'theme';
+3
查看文件
@@ -0,0 +1,3 @@
@tailwind base;
@tailwind utilities;
@tailwind components;
+50
查看文件
@@ -0,0 +1,50 @@
html[data-color-scheme='light'] {
--black: #3e3e3e;
--red: #970b16;
--green: #07962a;
--yellow: #f8eec7;
--blue: #003e8a;
--purple: #e94691;
--cyan: #89d1ec;
--white: #ffffff;
--brightBlack: #666666;
--brightRed: #de0000;
--brightGreen: #87d5a2;
--brightYellow: #f1d007;
--brightBlue: #2e6cba;
--brightPurple: #ffa29f;
--brightCyan: #1cfafe;
--brightWhite: #ffffff;
--background: #f4f4f4;
--foreground: #3e3e3e;
--cursorColor: #3f3f3f;
--selectionBackground: #a9c1e2;
}
html[data-color-scheme='dark'] {
--black: #000000;
--red: #f78166;
--green: #56d364;
--yellow: #e3b341;
--blue: #6ca4f8;
--purple: #db61a2;
--cyan: #2b7489;
--white: #ffffff;
--brightBlack: #4d4d4d;
--brightRed: #f78166;
--brightGreen: #56d364;
--brightYellow: #e3b341;
--brightBlue: #6ca4f8;
--brightPurple: #db61a2;
--brightCyan: #2b7489;
--brightWhite: #ffffff;
--background: #101216;
--foreground: #8b949e;
--cursorColor: #c9d1d9;
--selectionBackground: #3b5070;
}
[data-color-scheme='light'] .d-block-light,
[data-color-scheme='dark'] .d-block-dark {
display: block !important;
}
+15
查看文件
@@ -0,0 +1,15 @@
/* 光标样式 */
.typed-text::after {
content: '|';
display: inline-block;
opacity: 0;
animation: blink 0.7s infinite alternate; /* 闪烁动画 */
vertical-align: text-bottom;
}
/* 闪烁动画 */
@keyframes blink {
to {
opacity: 1;
}
}
+2
查看文件
@@ -0,0 +1,2 @@
$phone-max-width: 683px;
$tablet-max-width: 899px;
+24
查看文件
@@ -0,0 +1,24 @@
// 文字打字机效果
export const typewriterEffect = (selectors: string) => {
const typedTextContainer = document.querySelector<HTMLDivElement>(selectors)
if (!typedTextContainer) return
const text = typedTextContainer.innerText
// 清除原有的文本
typedTextContainer.innerText = ''
// 实现打字机效果
let i = 0
const typewriter = () => {
if (i >= text.length) return
typedTextContainer.innerText += text.charAt(i++)
setTimeout(typewriter, Math.random() * 200 + 50)
}
typewriter()
}