diff --git a/frontend_nuxt/.gitignore b/frontend_nuxt/.gitignore new file mode 100644 index 000000000..e5cf479e7 --- /dev/null +++ b/frontend_nuxt/.gitignore @@ -0,0 +1,4 @@ +node_modules +.nuxt +dist +.output diff --git a/frontend_nuxt/app.vue b/frontend_nuxt/app.vue new file mode 100644 index 000000000..9c1ff809a --- /dev/null +++ b/frontend_nuxt/app.vue @@ -0,0 +1,93 @@ + + + + + diff --git a/frontend_nuxt/assets/global.css b/frontend_nuxt/assets/global.css new file mode 100644 index 000000000..af5513209 --- /dev/null +++ b/frontend_nuxt/assets/global.css @@ -0,0 +1,276 @@ +:root { + --primary-color-hover: rgb(9, 95, 105); + --primary-color: rgb(10, 110, 120); + --primary-color-disabled: rgba(93, 152, 156, 0.5); + --header-height: 60px; + --header-background-color: white; + --header-border-color: lightgray; + --header-text-color: black; + --menu-background-color: white; + --background-color: white; + /* --background-color-blur: rgba(255, 255, 255, 0.57); */ + --background-color-blur: var(--background-color); + --menu-border-color: lightgray; + --normal-border-color: lightgray; + --menu-selected-background-color: rgba(208, 250, 255, 0.659); + --menu-text-color: black; + --scroller-background-color: rgba(130, 175, 180, 0.5); + --normal-background-color: rgb(241, 241, 241); + --login-background-color: rgb(248, 248, 248); + --login-background-color-hover: #e0e0e0; + --text-color: black; + --blockquote-text-color: #6a737d; + --menu-width: 200px; + --page-max-width: 1200px; + --page-max-width-mobile: 900px; + --article-info-background-color: #f0f0f0; + --activity-card-background-color: #fafafa; +} + +[data-theme='dark'] { + --header-background-color: #2b2b2b; + --header-border-color: #555; + --primary-color: rgb(17, 182, 197); + --primary-color-hover: rgb(13, 137, 151); + --header-text-color: white; + --menu-background-color: #333; + --background-color: #333; + /* --background-color-blur: #333333a4; */ + --background-color-blur: var(--background-color); + --menu-border-color: #555; + --normal-border-color: #555; + --menu-selected-background-color: rgba(255, 255, 255, 0.1); + --menu-text-color: white; + --normal-background-color: #000000; + --login-background-color: #575757; + --login-background-color-hover: #717171; + --text-color: #eee; + --blockquote-text-color: #999; + --article-info-background-color: #747373; + --activity-card-background-color: #585858; +} + +body { + margin: 0; + padding: 0; + font-family: 'Roboto', sans-serif; + background-color: var(--normal-background-color); + color: var(--text-color); + /* 禁止滚动 */ + /* overflow: hidden; */ +} + +/************************* + * Vditor 自定义皮肤覆写 + *************************/ +.vditor { + min-height: 200px; +} + +.vditor-toolbar--pin { + top: var(--header-height) !important; +} + +.vditor-panel { + min-width: 400px; +} + +.emoji { + width: 20px; + height: 20px; + vertical-align: middle; +} + +/* .vditor { + --textarea-background-color: transparent; + border: none !important; + box-shadow: none !important; +} + +.vditor-reset { + color: var(--text-color); +} + +.vditor-toolbar { + background: transparent !important; + border: none !important; + box-shadow: none !important; +} */ + +/* .vditor-toolbar { + position: relative !important; +} */ + +/************************* + * Markdown 渲染样式 + *************************/ +.info-content-text ul, +.info-content-text ol { + padding-left: 1.5em; +} + +.info-content-text h1, +.info-content-text h2 { + border-bottom: 1px solid var(--normal-border-color); + padding-bottom: 0.3em; + margin-bottom: 0.8em; +} + +.info-content-text { + word-break: break-word; + max-width: 100%; +} + +.info-content-text blockquote { + margin: 1em 0; + padding-left: 1em; + border-left: 4px solid #d0d7de; + color: var(--blockquote-text-color); +} + +.info-content-text pre { + background-color: var(--normal-background-color); + padding: 8px 12px; + border-radius: 4px; + line-height: 1.5; + position: relative; +} + +.copy-code-btn { + position: absolute; + top: 4px; + right: 4px; + font-size: 12px; + padding: 2px 6px; + border: none; + border-radius: 4px; + background-color: white; + opacity: 0.8; + color: black; + cursor: pointer; +} + +.copy-code-btn:hover { + opacity: 1; +} + +.info-content-text code { + font-family: 'Roboto Mono', monospace; + font-size: 13px; + border-radius: 4px; + white-space: pre-wrap; + background-color: var(--normal-background-color); + color: var(--text-color); +} + +.info-content-text a { + color: var(--primary-color); + text-decoration: none; +} + +.info-content-text a:hover { + text-decoration: underline; +} + +.info-content-text img { + max-width: 100%; + height: auto; +} + +.info-content-text table { + width: 100%; + max-width: 100%; + border-collapse: collapse; + margin: 1.2em 0; + font-size: 14px; + line-height: 1.45; + overflow-x: auto; /* 小屏可横向滚动 */ +} + +.info-content-text thead th { + background-color: var(--primary-color); + color: #fff; + padding: 10px 14px; + text-align: left; + font-weight: 600; +} + +[data-theme='dark'] .info-content-text thead th { + background-color: var(--primary-color-hover); /* 暗色稍暗一点 */ +} + +.info-content-text tbody tr:nth-child(even) { + background-color: rgba(208, 250, 255, 0.25); /* 斑马纹 */ +} + +[data-theme='dark'] .info-content-text tbody tr:nth-child(even) { + background-color: rgba(255, 255, 255, 0.05); +} + +.info-content-text th, +.info-content-text td { + border: 1px solid var(--menu-border-color); + padding: 8px 14px; + vertical-align: top; +} + +.info-content-text tbody td { + color: var(--text-color); +} + +/* 首列加粗,便于阅读 */ +.info-content-text tbody td:first-child { + font-weight: 500; +} + +/* 鼠标悬停行高亮 */ +.info-content-text tbody tr:hover { + background-color: var(--menu-selected-background-color); + transition: background-color 0.2s ease; +} + +@media (max-width: 768px) { + .vditor { + min-height: 100px; + } + + .vditor-toolbar { + overflow-x: auto; + } + + .about-content h1, + .info-content-text h1 { + font-size: 20px; + } + + .about-content h2, + .info-content-text h2 { + font-size: 18px; + } + + .about-content p, + .info-content-text p { + font-size: 14px; + margin-top: 3px; + margin-bottom: 3px; + } + + + .vditor-toolbar--pin { + top: 0 !important; + } + + .about-content li, + .info-content-text li { + font-size: 14px; + } + + .info-content-text pre { + line-height: 1.1; + } + + .vditor-panel { + position: relative; + min-width: 0; + } +} \ No newline at end of file diff --git a/frontend_nuxt/assets/icons/discord.svg b/frontend_nuxt/assets/icons/discord.svg new file mode 100644 index 000000000..9d7796b8a --- /dev/null +++ b/frontend_nuxt/assets/icons/discord.svg @@ -0,0 +1 @@ +Discord \ No newline at end of file diff --git a/frontend_nuxt/assets/icons/github.svg b/frontend_nuxt/assets/icons/github.svg new file mode 100644 index 000000000..9c3865e73 --- /dev/null +++ b/frontend_nuxt/assets/icons/github.svg @@ -0,0 +1,28 @@ + + GitHub icon + + \ No newline at end of file diff --git a/frontend_nuxt/assets/icons/google.svg b/frontend_nuxt/assets/icons/google.svg new file mode 100644 index 000000000..5c0960d17 --- /dev/null +++ b/frontend_nuxt/assets/icons/google.svg @@ -0,0 +1,28 @@ + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/frontend_nuxt/assets/icons/twitter.svg b/frontend_nuxt/assets/icons/twitter.svg new file mode 100644 index 000000000..42f23d845 --- /dev/null +++ b/frontend_nuxt/assets/icons/twitter.svg @@ -0,0 +1,4 @@ + + Twitter icon + + diff --git a/frontend_nuxt/assets/toast.css b/frontend_nuxt/assets/toast.css new file mode 100644 index 000000000..22e79415a --- /dev/null +++ b/frontend_nuxt/assets/toast.css @@ -0,0 +1,35 @@ +.Vue-Toastification__toast { + border-radius: 20px; +} + +.Vue-Toastification__toast--info { + background-color: #d0e9ff; + color: #1b6ec2; +} +.Vue-Toastification__toast--success { + background-color: #dff6dd; + color: #2b7a2b; +} +.Vue-Toastification__toast--error { + background-color: #f99a9a; + color: #b73737; +} + +@media (max-width: 768px) { + .Vue-Toastification__container.open-isle-toast-style-v1 { + width: auto; + max-width: 90vw; + right: 0.5em; + left: auto; + } + + .Vue-Toastification__toast-body { + font-size: 14px; + line-height: 20px; + } + + .Vue-Toastification__close-button { + font-size: 18px; + line-height: 18px; + } +} diff --git a/frontend_nuxt/components/ActivityPopup.vue b/frontend_nuxt/components/ActivityPopup.vue new file mode 100644 index 000000000..c6aa221e7 --- /dev/null +++ b/frontend_nuxt/components/ActivityPopup.vue @@ -0,0 +1,79 @@ + + + + + diff --git a/frontend_nuxt/components/ArticleCategory.vue b/frontend_nuxt/components/ArticleCategory.vue new file mode 100644 index 000000000..859f4a475 --- /dev/null +++ b/frontend_nuxt/components/ArticleCategory.vue @@ -0,0 +1,71 @@ + + + + + diff --git a/frontend_nuxt/components/ArticleTags.vue b/frontend_nuxt/components/ArticleTags.vue new file mode 100644 index 000000000..ed015dcf1 --- /dev/null +++ b/frontend_nuxt/components/ArticleTags.vue @@ -0,0 +1,79 @@ + + + + + + diff --git a/frontend_nuxt/components/AvatarCropper.vue b/frontend_nuxt/components/AvatarCropper.vue new file mode 100644 index 000000000..2cb0a1d62 --- /dev/null +++ b/frontend_nuxt/components/AvatarCropper.vue @@ -0,0 +1,142 @@ + + + + + + diff --git a/frontend_nuxt/components/BaseInput.vue b/frontend_nuxt/components/BaseInput.vue new file mode 100644 index 000000000..c596c86b6 --- /dev/null +++ b/frontend_nuxt/components/BaseInput.vue @@ -0,0 +1,82 @@ +