feat(vite): 资源拆分 & 样式优化
这个提交包含在:
+1
@@ -10,6 +10,7 @@ lerna-debug.log*
|
|||||||
node_modules
|
node_modules
|
||||||
dist
|
dist
|
||||||
dist-ssr
|
dist-ssr
|
||||||
|
publish
|
||||||
*.local
|
*.local
|
||||||
|
|
||||||
# Editor directories and files
|
# Editor directories and files
|
||||||
|
|||||||
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
services:
|
services:
|
||||||
halo:
|
halo:
|
||||||
image: registry.fit2cloud.com/halo/halo:2.18
|
image: registry.fit2cloud.com/halo/halo:2.20.10
|
||||||
volumes:
|
volumes:
|
||||||
- ./data:/root/.halo2
|
- ./data:/root/.halo2
|
||||||
- ../theme-terminal:/root/.halo2/themes/theme-terminal
|
- ../theme-terminal:/root/.halo2/themes/theme-terminal
|
||||||
|
|||||||
@@ -1,13 +1,14 @@
|
|||||||
{
|
{
|
||||||
"name": "theme-terminal",
|
"name": "theme-terminal",
|
||||||
"private": true,
|
"private": true,
|
||||||
"version": "1.0.0",
|
"version": "1.1.1",
|
||||||
"description": "A terminal like theme for Halo.",
|
"description": "A terminal like theme for Halo.",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "vite build --watch",
|
"dev": "vite build --watch",
|
||||||
"build": "tsc && vite build",
|
"build": "tsc && vite build",
|
||||||
"lint": "eslint ./src --ext .js,.cjs,.mjs,.ts,.cts,.mts --ignore-path .gitignore",
|
"lint": "eslint ./src --ext .js,.cjs,.mjs,.ts,.cts,.mts --ignore-path .gitignore",
|
||||||
"prettier": "prettier --write './src/**/*.{js,ts,css,json,ml,yaml,html}' './templates/**/*.html'"
|
"prettier": "prettier --write './src/**/*.{js,ts,css,json,ml,yaml,html}' './templates/**/*.html'",
|
||||||
|
"publish": "cp -r theme.yaml settings.yaml templates publish/ && zip -r theme-terminal.zip publish"
|
||||||
},
|
},
|
||||||
"keywords": [
|
"keywords": [
|
||||||
"halo",
|
"halo",
|
||||||
@@ -19,6 +20,10 @@
|
|||||||
"url": "https://dev/cm"
|
"url": "https://dev/cm"
|
||||||
},
|
},
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
"repository": {
|
||||||
|
"url": "https://git.dev.cm/dev.cm/blog/src/branch/main/theme-terminal",
|
||||||
|
"type": "git"
|
||||||
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@iconify/json": "^2.1.132",
|
"@iconify/json": "^2.1.132",
|
||||||
"@tailwindcss/aspect-ratio": "^0.4.2",
|
"@tailwindcss/aspect-ratio": "^0.4.2",
|
||||||
|
|||||||
@@ -27,6 +27,7 @@ spec:
|
|||||||
name: title
|
name: title
|
||||||
label: 站点标题
|
label: 站点标题
|
||||||
help: 配置后,将展示站点标题。
|
help: 配置后,将展示站点标题。
|
||||||
|
value: 'Terminal'
|
||||||
- group: index
|
- group: index
|
||||||
label: 首页设置
|
label: 首页设置
|
||||||
formSchema:
|
formSchema:
|
||||||
|
|||||||
@@ -0,0 +1,12 @@
|
|||||||
|
interface MenuState {
|
||||||
|
isOpen: boolean;
|
||||||
|
handleToggleMenu(): void;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const menu = (): MenuState => ({
|
||||||
|
isOpen: false,
|
||||||
|
|
||||||
|
handleToggleMenu() {
|
||||||
|
this.isOpen = !this.isOpen;
|
||||||
|
}
|
||||||
|
})
|
||||||
@@ -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);
|
||||||
|
},
|
||||||
|
});
|
||||||
@@ -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,
|
||||||
|
})
|
||||||
|
);
|
||||||
|
},
|
||||||
|
});
|
||||||
@@ -1,45 +0,0 @@
|
|||||||
// 文字打字机效果
|
|
||||||
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()
|
|
||||||
}
|
|
||||||
|
|
||||||
// 切换黑白主题
|
|
||||||
export const handleToggleThemeMode = (selectors: string) => {
|
|
||||||
const toggleButton = document.querySelector<HTMLDivElement>(selectors);
|
|
||||||
|
|
||||||
if(!toggleButton) return
|
|
||||||
|
|
||||||
const storedTheme = localStorage.getItem("theme-mode") || (window.matchMedia("(prefers-color-scheme: dark)").matches ? "dark" : "light");
|
|
||||||
|
|
||||||
if (storedTheme) document.documentElement.setAttribute("data-color-scheme", storedTheme);
|
|
||||||
|
|
||||||
toggleButton.onclick = function () {
|
|
||||||
const currentTheme = document.documentElement.getAttribute("data-color-scheme");
|
|
||||||
|
|
||||||
const targetTheme = currentTheme === "dark" ? "light" : "dark";
|
|
||||||
|
|
||||||
document.documentElement.setAttribute("data-color-scheme", targetTheme);
|
|
||||||
|
|
||||||
localStorage.setItem("theme-mode", targetTheme);
|
|
||||||
};
|
|
||||||
}
|
|
||||||
+10
-11
@@ -1,20 +1,19 @@
|
|||||||
import './styles/tailwind.css'
|
import "./styles/style.scss";
|
||||||
import './styles/style.scss'
|
import "./styles/font-hack.scss";
|
||||||
import './styles/theme.scss'
|
import "./styles/font-pixel.scss";
|
||||||
import './styles/font-hack.scss'
|
|
||||||
|
|
||||||
import Alpine from 'alpinejs'
|
import Alpine from 'alpinejs'
|
||||||
import upvote from './upvote'
|
import {upvote} from './alpine/upvote'
|
||||||
import {typewriterEffect, handleToggleThemeMode} from './custom'
|
import {themeMode} from './alpine/themeMode'
|
||||||
|
import {menu} from './alpine/menu'
|
||||||
|
import {typewriterEffect} from './utils'
|
||||||
|
|
||||||
window.Alpine = Alpine
|
window.Alpine = Alpine
|
||||||
|
|
||||||
Alpine.data('upvote', upvote)
|
Alpine.data('upvote', upvote)
|
||||||
|
Alpine.data('themeMode', themeMode)
|
||||||
|
Alpine.data('menu', menu)
|
||||||
|
|
||||||
Alpine.start()
|
Alpine.start()
|
||||||
|
|
||||||
document.addEventListener('DOMContentLoaded', () => {
|
document.addEventListener('DOMContentLoaded', () => typewriterEffect('.typed-text'))
|
||||||
typewriterEffect('.typed-text')
|
|
||||||
|
|
||||||
handleToggleThemeMode('#theme-toggle')
|
|
||||||
})
|
|
||||||
|
|||||||
@@ -7,28 +7,28 @@
|
|||||||
@font-face {
|
@font-face {
|
||||||
font-family: 'Hack';
|
font-family: 'Hack';
|
||||||
/* Use full version (not a subset) for unicode icon support */
|
/* Use full version (not a subset) for unicode icon support */
|
||||||
src: url('fonts/hack-regular.woff2?sha=3114f1256') format('woff2'), url('fonts/hack-regular.woff?sha=3114f1256') format('woff');
|
src: url('../fonts/hack-regular.woff2?sha=3114f1256') format('woff2'), url('../fonts/hack-regular.woff?sha=3114f1256') format('woff');
|
||||||
font-weight: 400;
|
font-weight: 400;
|
||||||
font-style: normal;
|
font-style: normal;
|
||||||
}
|
}
|
||||||
|
|
||||||
@font-face {
|
@font-face {
|
||||||
font-family: 'Hack';
|
font-family: 'Hack';
|
||||||
src: url('fonts/hack-bold-subset.woff2?sha=3114f1256') format('woff2'), url('fonts/hack-bold-subset.woff?sha=3114f1256') format('woff');
|
src: url('../fonts/hack-bold-subset.woff2?sha=3114f1256') format('woff2'), url('../fonts/hack-bold-subset.woff?sha=3114f1256') format('woff');
|
||||||
font-weight: 700;
|
font-weight: 700;
|
||||||
font-style: normal;
|
font-style: normal;
|
||||||
}
|
}
|
||||||
|
|
||||||
@font-face {
|
@font-face {
|
||||||
font-family: 'Hack';
|
font-family: 'Hack';
|
||||||
src: url('fonts/hack-italic-subset.woff2?sha=3114f1256') format('woff2'), url('fonts/hack-italic-webfont.woff?sha=3114f1256') format('woff');
|
src: url('../fonts/hack-italic-subset.woff2?sha=3114f1256') format('woff2'), url('../fonts/hack-italic-webfont.woff?sha=3114f1256') format('woff');
|
||||||
font-weight: 400;
|
font-weight: 400;
|
||||||
font-style: italic;
|
font-style: italic;
|
||||||
}
|
}
|
||||||
|
|
||||||
@font-face {
|
@font-face {
|
||||||
font-family: 'Hack';
|
font-family: 'Hack';
|
||||||
src: url('fonts/hack-bolditalic-subset.woff2?sha=3114f1256') format('woff2'), url('fonts/hack-bolditalic-subset.woff?sha=3114f1256') format('woff');
|
src: url('../fonts/hack-bolditalic-subset.woff2?sha=3114f1256') format('woff2'), url('../fonts/hack-bolditalic-subset.woff?sha=3114f1256') format('woff');
|
||||||
font-weight: 700;
|
font-weight: 700;
|
||||||
font-style: italic;
|
font-style: italic;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,4 @@
|
|||||||
|
@font-face {
|
||||||
|
font-family: Ark-Pixel-12-proportional-zh_cn;
|
||||||
|
src: url("../fonts/fusion-pixel-12px-proportional-zh_hans.woff2");
|
||||||
|
}
|
||||||
@@ -1,17 +1,5 @@
|
|||||||
@import "variables";
|
@import "variables";
|
||||||
|
|
||||||
@mixin menu {
|
|
||||||
position: absolute;
|
|
||||||
background: var(--background);
|
|
||||||
box-shadow: var(--shadow);
|
|
||||||
color: white;
|
|
||||||
border: 2px solid;
|
|
||||||
margin: 0;
|
|
||||||
padding: 10px;
|
|
||||||
list-style: none;
|
|
||||||
z-index: 99;
|
|
||||||
}
|
|
||||||
|
|
||||||
.header {
|
.header {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
@@ -25,7 +13,7 @@
|
|||||||
|
|
||||||
.dividing {
|
.dividing {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
background: repeating-linear-gradient(90deg, var(--foreground), var(--foreground) 2px, transparent 0, transparent 16px);
|
background: repeating-linear-gradient(90deg, var(--foreground), var(--foreground) 2px, transparent 0, transparent 10px);
|
||||||
display: block;
|
display: block;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 25px;
|
height: 25px;
|
||||||
@@ -40,46 +28,42 @@
|
|||||||
list-style: none;
|
list-style: none;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
color: var(--green);
|
|
||||||
|
|
||||||
li {
|
li {
|
||||||
|
position: relative;
|
||||||
|
flex: 0 0 auto;
|
||||||
|
padding-bottom: 10px;
|
||||||
|
|
||||||
&.active {
|
&.active {
|
||||||
color: var(--cyan);
|
color: var(--cyan);
|
||||||
}
|
}
|
||||||
|
|
||||||
&:not(:last-of-type) {
|
&:not(:last-of-type) {
|
||||||
margin-right: 20px;
|
margin-right: 20px;
|
||||||
margin-bottom: 10px;
|
|
||||||
flex: 0 0 auto;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
&__sub-inner {
|
&__sub-inner {
|
||||||
position: relative;
|
position: absolute;
|
||||||
list-style: none;
|
z-index: 99;
|
||||||
padding: 0;
|
|
||||||
margin: 0;
|
|
||||||
|
|
||||||
&:not(:only-child) {
|
|
||||||
margin-left: 20px;
|
|
||||||
}
|
|
||||||
|
|
||||||
&-more {
|
|
||||||
@include menu;
|
|
||||||
top: 35px;
|
top: 35px;
|
||||||
left: 0;
|
left: 0;
|
||||||
|
margin: 0;
|
||||||
&-trigger {
|
padding: 10px;
|
||||||
color: var(--foreground);
|
list-style: none;
|
||||||
user-select: none;
|
border: 2px solid var(--red);
|
||||||
cursor: pointer;
|
background: var(--background);
|
||||||
}
|
box-shadow: 0 10px var(--background), -10px 10px var(--background), 10px 10px var(--background);
|
||||||
|
|
||||||
li {
|
li {
|
||||||
margin: 0;
|
|
||||||
padding: 5px;
|
padding: 5px;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
|
text-decoration: underline;
|
||||||
|
color: var(--green);
|
||||||
|
|
||||||
|
&:not(:last-of-type) {
|
||||||
|
margin-right: 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,11 +10,6 @@ html {
|
|||||||
box-sizing: inherit;
|
box-sizing: inherit;
|
||||||
}
|
}
|
||||||
|
|
||||||
@font-face {
|
|
||||||
font-family: Ark-Pixel-12-proportional-zh_cn;
|
|
||||||
src: url("../fonts/fusion-pixel-12px-proportional-zh_hans.woff2");
|
|
||||||
}
|
|
||||||
|
|
||||||
body {
|
body {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
|
|||||||
@@ -52,13 +52,23 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
&-title {
|
&-title {
|
||||||
--border: 2px dashed var(--blue);
|
--border: 3px dotted var(--blue);
|
||||||
|
|
||||||
position: relative;
|
position: relative;
|
||||||
color: var(--blue);
|
color: var(--blue);
|
||||||
margin: 0 0 15px;
|
margin: 0 0 15px;
|
||||||
padding-bottom: 15px;
|
padding-bottom: 15px;
|
||||||
border-bottom: var(--border);
|
|
||||||
font-weight: normal;
|
font-weight: normal;
|
||||||
|
border-bottom: var(--border);
|
||||||
|
|
||||||
|
&::after {
|
||||||
|
content: "";
|
||||||
|
position: absolute;
|
||||||
|
bottom: 2px;
|
||||||
|
display: block;
|
||||||
|
width: 100%;
|
||||||
|
border-bottom: var(--border);
|
||||||
|
}
|
||||||
|
|
||||||
a {
|
a {
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
|
|||||||
@@ -1,3 +1,7 @@
|
|||||||
|
@tailwind base;
|
||||||
|
@tailwind utilities;
|
||||||
|
@tailwind components;
|
||||||
|
|
||||||
@import 'buttons';
|
@import 'buttons';
|
||||||
@import 'header';
|
@import 'header';
|
||||||
@import 'logo';
|
@import 'logo';
|
||||||
@@ -6,3 +10,5 @@
|
|||||||
@import 'pagination';
|
@import 'pagination';
|
||||||
@import 'footer';
|
@import 'footer';
|
||||||
@import 'typed-text';
|
@import 'typed-text';
|
||||||
|
|
||||||
|
@import 'theme';
|
||||||
@@ -1,53 +0,0 @@
|
|||||||
interface upvoteState {
|
|
||||||
upvotedNames: string[];
|
|
||||||
|
|
||||||
init(): void;
|
|
||||||
|
|
||||||
upvoted(id: string): boolean;
|
|
||||||
|
|
||||||
handleUpvote(name: string): void;
|
|
||||||
}
|
|
||||||
|
|
||||||
export default (key: string, group: string, plural: string): upvoteState => ({
|
|
||||||
upvotedNames: [],
|
|
||||||
init() {
|
|
||||||
this.upvotedNames = JSON.parse(localStorage.getItem(`walker.upvoted.${key}.names`) || '[]')
|
|
||||||
},
|
|
||||||
upvoted(id: string) {
|
|
||||||
return this.upvotedNames.includes(id)
|
|
||||||
},
|
|
||||||
async handleUpvote(name) {
|
|
||||||
if (this.upvoted(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,
|
|
||||||
}),
|
|
||||||
)
|
|
||||||
},
|
|
||||||
});
|
|
||||||
@@ -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()
|
||||||
|
}
|
||||||
@@ -25,5 +25,6 @@
|
|||||||
></a
|
></a
|
||||||
></span>
|
></span>
|
||||||
</div>
|
</div>
|
||||||
|
<halo:footer />
|
||||||
</div>
|
</div>
|
||||||
</footer>
|
</footer>
|
||||||
|
|||||||
@@ -24,7 +24,7 @@
|
|||||||
<svg xmlns="http://www.w3.org/2000/svg" width="1.5rem" height="1.5rem" viewBox="0 0 24 24"><path fill="currentColor" d="M6 2h8v2H6zM4 6V4h2v2zm0 8H2V6h2zm2 2H4v-2h2zm8 0v2H6v-2zm2-2h-2v2h2v2h2v2h2v2h2v-2h-2v-2h-2v-2h-2zm0-8h2v8h-2zm0 0V4h-2v2z"/></svg>
|
<svg xmlns="http://www.w3.org/2000/svg" width="1.5rem" height="1.5rem" viewBox="0 0 24 24"><path fill="currentColor" d="M6 2h8v2H6zM4 6V4h2v2zm0 8H2V6h2zm2 2H4v-2h2zm8 0v2H6v-2zm2-2h-2v2h2v2h2v2h2v2h2v-2h-2v-2h-2v-2h-2zm0-8h2v8h-2zm0 0V4h-2v2z"/></svg>
|
||||||
</th:block>
|
</th:block>
|
||||||
</button>
|
</button>
|
||||||
<button id="theme-toggle" type="button">
|
<button type="button" x-data="themeMode()" @click="handleToggleThemeMode()">
|
||||||
<th:block th:unless="${theme.config.basic.pixel_style}">
|
<th:block th:unless="${theme.config.basic.pixel_style}">
|
||||||
<svg
|
<svg
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
@@ -46,21 +46,24 @@
|
|||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<nav class="menu">
|
<nav class="menu">
|
||||||
<ul th:if="${menu != null} and ${not #lists.isEmpty(menu.menuItems)}" class="menu__inner menu__inner--desktop">
|
<ul th:if="${menu != null} and ${not #lists.isEmpty(menu.menuItems)}" class="menu__inner">
|
||||||
<li th:each="menuItem : ${menu.menuItems}">
|
<li th:each="menuItem : ${menu.menuItems}" x-data="menu()" @mouseenter="handleToggleMenu()" @mouseleave="handleToggleMenu()">
|
||||||
<a
|
<a
|
||||||
class="text-gray-600 hover:text-blue-600"
|
class="text-gray-600 hover:text-blue-600"
|
||||||
th:href="${menuItem.status.href}"
|
th:href="${menuItem.status.href}"
|
||||||
th:text="${menuItem.status.displayName}"
|
th:text="${menuItem.status.displayName + (not #lists.isEmpty(menuItem.children) ? '▾' : '')}"
|
||||||
></a>
|
></a>
|
||||||
<ul
|
<ul
|
||||||
th:if="${not #lists.isEmpty(menuItem.children)}"
|
th:if="${not #lists.isEmpty(menuItem.children)}"
|
||||||
@mouseenter="open()"
|
class="menu__sub-inner"
|
||||||
@mouseleave="close()"
|
:class="{'hidden': !isOpen}"
|
||||||
class="menu__sub-inner-more hidden"
|
|
||||||
>
|
>
|
||||||
<li th:each="childMenuItem : ${menuItem.children}">
|
<li th:each="childMenuItem : ${menuItem.children}">
|
||||||
<a th:href="${childMenuItem.status.href} " th:text="${childMenuItem.status.displayName} "></a>
|
<a
|
||||||
|
class="text-gray-600 hover:text-blue-600"
|
||||||
|
th:href="${childMenuItem.status.href} "
|
||||||
|
th:text="${childMenuItem.status.displayName} "
|
||||||
|
></a>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</li>
|
</li>
|
||||||
|
|||||||
@@ -6,7 +6,8 @@
|
|||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
<link rel="icon" type="image/x-icon" th:href="${theme.config.basic.favicon}">
|
<link rel="icon" type="image/x-icon" th:href="${theme.config.basic.favicon}">
|
||||||
<title th:text="${site.title}"></title>
|
<title th:text="${site.title}"></title>
|
||||||
<link rel="stylesheet" th:href="@{/assets/dist/style.css?version=v1.0.1}" href="./assets/dist/style.css" />
|
<link rel="manifest" th:href="@{/assets/dist/manifest.json}" />
|
||||||
|
<link rel="stylesheet" th:href="@{/assets/dist/main.css?version={version}(version=${theme.spec.version})}" href="./assets/dist/style.css" />
|
||||||
</head>
|
</head>
|
||||||
<!-- 根据情况判断是否添加开启像素化样式 -->
|
<!-- 根据情况判断是否添加开启像素化样式 -->
|
||||||
<body class="main" th:classappend="${theme.config.basic.pixel_style} ? 'pixel_style' : '' ">
|
<body class="main" th:classappend="${theme.config.basic.pixel_style} ? 'pixel_style' : '' ">
|
||||||
@@ -27,6 +28,6 @@
|
|||||||
<th:block th:replace="${footer}" />
|
<th:block th:replace="${footer}" />
|
||||||
</th:block>
|
</th:block>
|
||||||
</div>
|
</div>
|
||||||
<script th:src="@{/assets/dist/main.iife.js?version=v1.0.1}"></script>
|
<script th:src="@{/assets/dist/main.js?version={version}(version=${theme.spec.version})}"></script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
@@ -46,7 +46,7 @@
|
|||||||
<div class="mt-3 flex items-center gap-4">
|
<div class="mt-3 flex items-center gap-4">
|
||||||
<div
|
<div
|
||||||
class="journal-likes inline-flex cursor-pointer items-center text-sm text-gray-400 transition-all hover:text-red-700"
|
class="journal-likes inline-flex cursor-pointer items-center text-sm text-gray-400 transition-all hover:text-red-700"
|
||||||
x-bind:class="{'text-red-700': upvoted(name)}"
|
:class="{'text-red-700': getIsUpvoted(name)}"
|
||||||
@click="handleUpvote(name)"
|
@click="handleUpvote(name)"
|
||||||
>
|
>
|
||||||
<i class="!h-4 !w-4 i-pixelarticons-heart"></i>
|
<i class="!h-4 !w-4 i-pixelarticons-heart"></i>
|
||||||
@@ -60,7 +60,7 @@
|
|||||||
<div
|
<div
|
||||||
class="inline-flex cursor-pointer items-center text-sm text-gray-400 transition-all hover:text-black dark:hover:text-white"
|
class="inline-flex cursor-pointer items-center text-sm text-gray-400 transition-all hover:text-black dark:hover:text-white"
|
||||||
:class="{'!text-black':showComment && storedTheme == 'light','!text-white':showComment && storedTheme == 'dark' }"
|
:class="{'!text-black':showComment && storedTheme == 'light','!text-white':showComment && storedTheme == 'dark' }"
|
||||||
x-on:click="showComment = !showComment"
|
@click="showComment = !showComment"
|
||||||
>
|
>
|
||||||
<i class="!h-4 !w-4 i-pixelarticons-comment"></i>
|
<i class="!h-4 !w-4 i-pixelarticons-comment"></i>
|
||||||
<span class="ml-1" th:text="${moment.stats.approvedComment}"> </span>
|
<span class="ml-1" th:text="${moment.stats.approvedComment}"> </span>
|
||||||
|
|||||||
@@ -13,5 +13,5 @@ spec:
|
|||||||
repo: https://git.dev.cm/theme-terminal
|
repo: https://git.dev.cm/theme-terminal
|
||||||
settingName: "theme-terminal-setting"
|
settingName: "theme-terminal-setting"
|
||||||
configMapName: "theme-terminal-configMap"
|
configMapName: "theme-terminal-configMap"
|
||||||
version: 1.0.1
|
version: 1.1.1
|
||||||
require: ">=2.8.0"
|
require: ">=2.20.0"
|
||||||
|
|||||||
@@ -1,19 +1,25 @@
|
|||||||
import path from "path";
|
import path from "path";
|
||||||
import { fileURLToPath } from "url";
|
|
||||||
import { defineConfig } from "vite";
|
import { defineConfig } from "vite";
|
||||||
|
|
||||||
import PurgeIcons from "vite-plugin-purge-icons";
|
import PurgeIcons from "vite-plugin-purge-icons";
|
||||||
|
|
||||||
export default defineConfig({
|
export default defineConfig({
|
||||||
|
root: "./src",
|
||||||
|
base: '/themes/theme-terminal/assets/dist/',
|
||||||
plugins: [PurgeIcons()],
|
plugins: [PurgeIcons()],
|
||||||
build: {
|
build: {
|
||||||
outDir: fileURLToPath(new URL("./templates/assets/dist", import.meta.url)),
|
manifest: true,
|
||||||
emptyOutDir: true,
|
rollupOptions: {
|
||||||
lib: {
|
input: path.resolve(__dirname, "src/main.ts"),
|
||||||
entry: path.resolve(__dirname, "src/main.ts"),
|
output: {
|
||||||
name: "main",
|
entryFileNames: "[name].js",
|
||||||
fileName: "main",
|
chunkFileNames: "[name].js",
|
||||||
formats: ["iife"],
|
assetFileNames: "[name][extname]",
|
||||||
},
|
},
|
||||||
|
treeshake: false,
|
||||||
|
preserveEntrySignatures: "allow-extension",
|
||||||
|
},
|
||||||
|
outDir: path.resolve(__dirname, "templates/assets/dist"),
|
||||||
|
emptyOutDir: true,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
在新议题中引用
屏蔽一个用户