+
@@ -196,15 +201,20 @@ onMounted(() => {
class="formatted-text"
>
-
来源: 南方科技大学飞跃手册
+
南方科技大学飞跃手册
-
@@ -314,19 +324,33 @@ onMounted(() => {
font-size: 14px;
}
+.share-qrcode-container {
+ display: flex;
+ justify-content: center;
+ margin-top: 20px;
+}
+
.share-qrcode {
display: flex;
flex-direction: column;
align-items: center;
- margin-top: 20px;
- padding: 10px;
+ padding: 15px;
+ border-radius: 8px;
+ border: 1px solid;
+ box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
+ max-width: 160px;
+}
+
+.share-qrcode img {
+ display: block;
border-radius: 4px;
}
-.share-qrcode p {
+.qrcode-text {
margin-top: 10px;
font-size: 14px;
text-align: center;
+ line-height: 1.4;
}
/* 控制按钮样式 */
From 099969b70cccca4f79d1ccff7d1bccf8e9e15a78 Mon Sep 17 00:00:00 2001
From: JayBridge <12310903@mail.sustech.edu.cn>
Date: Mon, 14 Apr 2025 12:05:00 +0800
Subject: [PATCH 06/14] fix: qrcode tab-switch (#211)
---
src/components/ShareCard.vue | 62 ++++++++++++++++++++++++++++--------
1 file changed, 49 insertions(+), 13 deletions(-)
diff --git a/src/components/ShareCard.vue b/src/components/ShareCard.vue
index e0f67360..65985ef2 100644
--- a/src/components/ShareCard.vue
+++ b/src/components/ShareCard.vue
@@ -43,17 +43,26 @@ const setTheme = (themeName) => {
currentTheme.value = themeName;
// 重新生成二维码以匹配主题颜色
qrcodeGenerated.value = false;
+
+ // 清除之前的二维码
+ const qrcodeElement = document.getElementById("qrcode");
+ if (qrcodeElement) {
+ qrcodeElement.innerHTML = "";
+ }
+
setTimeout(generateQRCode, 100);
};
// Function to generate QR code
const generateQRCode = () => {
if (typeof window === "undefined" || typeof document === "undefined") return;
- if (!document.getElementById("qrcode") || qrcodeGenerated.value) return;
try {
- // 清除之前的二维码(如果有)
+ // 获取QR码容器元素
const qrcodeElement = document.getElementById("qrcode");
+ if (!qrcodeElement) return;
+
+ // 清除之前的内容
qrcodeElement.innerHTML = "";
// 获取当前主题颜色
@@ -61,27 +70,44 @@ const generateQRCode = () => {
themes.find((t) => t.name === currentTheme.value) ?? themes[0];
// 生成正确的URL
- // 在开发环境中使用当前网址,在生产环境中使用基础URL
+ // 使用绝对URL确保在任何页面都能正确生成
const baseUrl = "https://sustech-application.com";
const currentPath = window.location.pathname;
const qrUrl = `${baseUrl}${currentPath}`;
- // 使用原生方式创建二维码图片
+ // 创建图片元素
const qrCodeImg = document.createElement("img");
qrCodeImg.alt = "扫描二维码访问原文";
qrCodeImg.style.width = "128px";
qrCodeImg.style.height = "128px";
+ // 处理主题颜色
+ let bgColor = theme.background.replace("#", "");
+ let fgColor = theme.text.replace("#", "");
+
+ // 确保颜色格式正确
+ if (!bgColor) bgColor = "ffffff";
+ if (!fgColor) fgColor = "000000";
+
// 使用QR Code API生成二维码
- const bgColor = theme.background.replace("#", "");
- const fgColor = theme.text.replace("#", "");
const qrCodeUrl = `https://api.qrserver.com/v1/create-qr-code/?size=128x128&data=${encodeURIComponent(qrUrl)}&bgcolor=${bgColor}&color=${fgColor}`;
+
+ // 设置加载事件
+ qrCodeImg.onload = () => {
+ qrcodeGenerated.value = true;
+ };
+
+ qrCodeImg.onerror = (e) => {
+ console.error("Failed to load QR code image:", e);
+ // 尝试使用默认颜色
+ qrCodeImg.src = `https://api.qrserver.com/v1/create-qr-code/?size=128x128&data=${encodeURIComponent(qrUrl)}`;
+ };
+
+ // 设置图片源
qrCodeImg.src = qrCodeUrl;
// 添加到DOM
qrcodeElement.appendChild(qrCodeImg);
-
- qrcodeGenerated.value = true;
} catch (err) {
console.error("Failed to generate QRCode:", err);
}
@@ -160,17 +186,27 @@ const downloadAsImage = async () => {
watch(
() => props.visible,
(newValue) => {
- if (newValue && !qrcodeGenerated.value) {
- // Small delay to ensure DOM is ready
+ // 当组件变为可见时,重置状态并生成新的二维码
+ if (newValue) {
+ // 重置状态
+ qrcodeGenerated.value = false;
+
+ // 清除之前的二维码
+ const qrcodeElement = document.getElementById("qrcode");
+ if (qrcodeElement) {
+ qrcodeElement.innerHTML = "";
+ }
+
+ // 小延迟确保 DOM 准备就绪
setTimeout(generateQRCode, 100);
}
},
+ { immediate: true }, // 立即触发一次
);
+// 当组件挂载时,如果可见则生成二维码
onMounted(() => {
- if (props.visible) {
- setTimeout(generateQRCode, 100);
- }
+ // 组件挂载时不需要额外生成二维码,因为 watch 中的 immediate: true 会处理
});
From 4f223a94001c2f21b5ea50a2b0e54d07185a9d09 Mon Sep 17 00:00:00 2001
From: JayBridge <12310903@mail.sustech.edu.cn>
Date: Mon, 14 Apr 2025 12:08:25 +0800
Subject: [PATCH 07/14] feat: Support triple resolution (#211)
---
src/components/ShareCard.vue | 20 ++++++++++++++++----
1 file changed, 16 insertions(+), 4 deletions(-)
diff --git a/src/components/ShareCard.vue b/src/components/ShareCard.vue
index 65985ef2..0c5f4009 100644
--- a/src/components/ShareCard.vue
+++ b/src/components/ShareCard.vue
@@ -141,9 +141,19 @@ const downloadAsImage = async () => {
// 确保背景色正确应用
const theme =
themes.find((t) => t.name === currentTheme.value) || themes[0];
+
+ // 计算厚度分辨率的尺寸
+ const originalWidth = shareCardRef.value.offsetWidth;
+ const originalHeight = shareCardRef.value.offsetHeight;
+ const scale = 3; // 3倍分辨率
+ const scaledWidth = originalWidth * scale;
+ const scaledHeight = originalHeight * scale;
+
+ // 设置克隆元素的样式
+ clone.style.width = `${originalWidth}px`;
+ clone.style.height = `${originalHeight}px`;
clone.style.backgroundColor = theme.background;
clone.style.color = theme.text;
- clone.style.width = `${shareCardRef.value.offsetWidth}px`;
clone.style.padding = "20px";
clone.style.borderRadius = "8px";
clone.style.boxShadow = "0 4px 8px rgba(0, 0, 0, 0.1)";
@@ -151,18 +161,20 @@ const downloadAsImage = async () => {
// 添加到临时容器
cloneContainer.appendChild(clone);
- // 使用toPng生成图片
+ // 使用toPng生成高分辨率图片
const dataUrl = await domToImage.toPng(clone, {
quality: 1,
bgcolor: theme.background,
- width: shareCardRef.value.offsetWidth,
- height: shareCardRef.value.offsetHeight,
+ width: scaledWidth, // 使用放大后的宽度
+ height: scaledHeight, // 使用放大后的高度
style: {
margin: "0",
padding: "20px",
"border-radius": "8px",
"background-color": theme.background,
color: theme.text,
+ transform: `scale(${scale})`,
+ "transform-origin": "top left",
},
});
From f980d1d7a85c45ecaa6be696fe07a70ebf1dc078 Mon Sep 17 00:00:00 2001
From: JayBridge <12310903@mail.sustech.edu.cn>
Date: Mon, 14 Apr 2025 12:12:39 +0800
Subject: [PATCH 08/14] feat: smaller QR aligned to the right (#211)
---
src/components/ShareCard.vue | 83 +++++++++++++++++++++++++-----------
1 file changed, 57 insertions(+), 26 deletions(-)
diff --git a/src/components/ShareCard.vue b/src/components/ShareCard.vue
index 0c5f4009..141f22d4 100644
--- a/src/components/ShareCard.vue
+++ b/src/components/ShareCard.vue
@@ -77,9 +77,9 @@ const generateQRCode = () => {
// 创建图片元素
const qrCodeImg = document.createElement("img");
- qrCodeImg.alt = "扫描二维码访问原文";
- qrCodeImg.style.width = "128px";
- qrCodeImg.style.height = "128px";
+ qrCodeImg.alt = "扫码访问";
+ qrCodeImg.style.width = "80px";
+ qrCodeImg.style.height = "80px";
// 处理主题颜色
let bgColor = theme.background.replace("#", "");
@@ -90,7 +90,7 @@ const generateQRCode = () => {
if (!fgColor) fgColor = "000000";
// 使用QR Code API生成二维码
- const qrCodeUrl = `https://api.qrserver.com/v1/create-qr-code/?size=128x128&data=${encodeURIComponent(qrUrl)}&bgcolor=${bgColor}&color=${fgColor}`;
+ const qrCodeUrl = `https://api.qrserver.com/v1/create-qr-code/?size=80x80&data=${encodeURIComponent(qrUrl)}&bgcolor=${bgColor}&color=${fgColor}`;
// 设置加载事件
qrCodeImg.onload = () => {
@@ -100,7 +100,7 @@ const generateQRCode = () => {
qrCodeImg.onerror = (e) => {
console.error("Failed to load QR code image:", e);
// 尝试使用默认颜色
- qrCodeImg.src = `https://api.qrserver.com/v1/create-qr-code/?size=128x128&data=${encodeURIComponent(qrUrl)}`;
+ qrCodeImg.src = `https://api.qrserver.com/v1/create-qr-code/?size=80x80&data=${encodeURIComponent(qrUrl)}`;
};
// 设置图片源
@@ -248,20 +248,23 @@ onMounted(() => {
v-html="text"
class="formatted-text"
>
-
-
-
@@ -372,33 +375,61 @@ onMounted(() => {
font-size: 14px;
}
-.share-qrcode-container {
+.share-footer {
display: flex;
- justify-content: center;
+ justify-content: space-between;
+ align-items: center;
margin-top: 20px;
+ border-top: 1px solid rgba(0, 0, 0, 0.1);
+ padding-top: 15px;
+}
+
+.share-footer-left {
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+}
+
+.share-website {
+ font-size: 16px;
+ font-weight: bold;
+ margin: 0 0 5px 0;
+}
+
+.share-url {
+ font-size: 14px;
+ opacity: 0.8;
+ margin: 0;
+}
+
+.share-qrcode-container {
+ display: flex;
+ justify-content: flex-end;
}
.share-qrcode {
display: flex;
flex-direction: column;
align-items: center;
- padding: 15px;
+ padding: 8px;
border-radius: 8px;
border: 1px solid;
- box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
- max-width: 160px;
+ box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
+ max-width: 100px;
}
.share-qrcode img {
display: block;
border-radius: 4px;
+ width: 80px;
+ height: 80px;
}
.qrcode-text {
- margin-top: 10px;
- font-size: 14px;
+ margin-top: 5px;
+ font-size: 12px;
text-align: center;
- line-height: 1.4;
+ line-height: 1.2;
}
/* 控制按钮样式 */
From 11e50503db218a8999aca970736840a1e6c1df8a Mon Sep 17 00:00:00 2001
From: JayBridge <12310903@mail.sustech.edu.cn>
Date: Mon, 14 Apr 2025 12:16:33 +0800
Subject: [PATCH 09/14] fix: delete defineProps & defineEmits (#211)
---
src/components/ShareCard.vue | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/src/components/ShareCard.vue b/src/components/ShareCard.vue
index 141f22d4..0df28b4b 100644
--- a/src/components/ShareCard.vue
+++ b/src/components/ShareCard.vue
@@ -1,5 +1,5 @@
-
+
-
+
From e2aac5545f6988d7a485dff9a0bfef50393a1284 Mon Sep 17 00:00:00 2001
From: JayBridge <12310903@mail.sustech.edu.cn>
Date: Fri, 18 Apr 2025 07:04:42 +0800
Subject: [PATCH 14/14] fix: lint:es (#211)
---
eslint.config.ts | 18 ++++++++
src/.vitepress/theme/index.ts | 9 ++--
src/components/{Layout.vue => AppLayout.vue} | 0
src/components/SelectionShareMenu.vue | 7 +--
src/components/ShareCard.vue | 48 ++++++--------------
src/types/dom-to-image-more.d.ts | 14 ++++++
src/types/global.d.ts | 46 +++++++++++++++++++
7 files changed, 103 insertions(+), 39 deletions(-)
rename src/components/{Layout.vue => AppLayout.vue} (100%)
create mode 100644 src/types/dom-to-image-more.d.ts
create mode 100644 src/types/global.d.ts
diff --git a/eslint.config.ts b/eslint.config.ts
index 5ac0583d..4a8483a2 100644
--- a/eslint.config.ts
+++ b/eslint.config.ts
@@ -8,6 +8,11 @@ export default ts.config(
ts.configs.strictTypeChecked,
ts.configs.stylisticTypeChecked,
vue.configs["flat/recommended"],
+ {
+ rules: {
+ "vue/no-v-html": "off", // Disable v-html warning as we need it for formatted text
+ },
+ },
{
// FIXME: remove this once we no longer need the bracket fix
ignores: ["**/*.js"],
@@ -19,6 +24,19 @@ export default ts.config(
parser: ts.parser,
projectService: true,
},
+ globals: {
+ window: "readonly",
+ document: "readonly",
+ navigator: "readonly",
+ setTimeout: "readonly",
+ console: "readonly",
+ alert: "readonly",
+ fetch: "readonly",
+ ClipboardItem: "readonly",
+ },
+ // Add browser environment
+ ecmaVersion: 2022,
+ sourceType: "module",
},
},
prettier,
diff --git a/src/.vitepress/theme/index.ts b/src/.vitepress/theme/index.ts
index 1073678b..b5d3b7c9 100644
--- a/src/.vitepress/theme/index.ts
+++ b/src/.vitepress/theme/index.ts
@@ -5,14 +5,17 @@ import DefaultTheme from "vitepress/theme";
import Aura from "@primeuix/themes/aura";
import PrimeVue from "primevue/config";
-import Layout from "../../components/Layout.vue";
+// Import components
+import AppLayout from "../../components/AppLayout.vue";
import PostList from "../../components/PostList.vue";
import SelectionShareMenu from "../../components/SelectionShareMenu.vue";
import "./style.css";
+// Define the theme
export default {
extends: DefaultTheme,
- Layout,
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-assignment
+ Layout: AppLayout as any,
enhanceApp({ app, router }) {
/* redirect legacy hash path, can only be done on client side */
router.onAfterRouteChange = async (to) => {
@@ -30,4 +33,4 @@ export default {
app.component("PostList", PostList);
app.component("SelectionShareMenu", SelectionShareMenu);
},
-} satisfies Theme;
+} as Theme;
diff --git a/src/components/Layout.vue b/src/components/AppLayout.vue
similarity index 100%
rename from src/components/Layout.vue
rename to src/components/AppLayout.vue
diff --git a/src/components/SelectionShareMenu.vue b/src/components/SelectionShareMenu.vue
index 0da79984..419260d5 100644
--- a/src/components/SelectionShareMenu.vue
+++ b/src/components/SelectionShareMenu.vue
@@ -87,7 +87,8 @@ const closeShareCard = () => {
// Click outside to hide menu
const handleClickOutside = (event: MouseEvent) => {
- if (menuVisible.value && !event.target.closest(".selection-menu")) {
+ const target = event.target as HTMLElement;
+ if (menuVisible.value && !target.closest(".selection-menu")) {
hideMenu();
}
};
@@ -118,7 +119,7 @@ onUnmounted(() => {
transform: 'translate(-50%, -100%)',
}"
>
-