diff --git a/database/development.sqlite3-shm b/database/development.sqlite3-shm index 148c649..e623578 100644 Binary files a/database/development.sqlite3-shm and b/database/development.sqlite3-shm differ diff --git a/database/development.sqlite3-wal b/database/development.sqlite3-wal index c53355a..8052288 100644 Binary files a/database/development.sqlite3-wal and b/database/development.sqlite3-wal differ diff --git a/docs/links.md b/docs/links.md new file mode 100644 index 0000000..e0c3f8b --- /dev/null +++ b/docs/links.md @@ -0,0 +1,7 @@ +https://pkmer.cn/Pkmer-Docs/10-obsidian/obsidian%E7%A4%BE%E5%8C%BA%E6%8F%92%E4%BB%B6/readme/obsidian-local-rest-api_readme/ + +https://trix-editor.org/js/attachments.js + +https://github.com/basecamp/trix/tree/main + +https://icon-sets.iconify.design/?query=info \ No newline at end of file diff --git a/public/css/layouts/root.css b/public/css/layouts/root.css index 815ff25..dd80da7 100644 --- a/public/css/layouts/root.css +++ b/public/css/layouts/root.css @@ -5,6 +5,7 @@ body { height: 100%; font-family: Arial, sans-serif; color: #333; + scroll-behavior: smooth; } body { diff --git a/public/css/page/index.css b/public/css/page/index.css index b42d0d4..77f4e86 100644 --- a/public/css/page/index.css +++ b/public/css/page/index.css @@ -52,4 +52,18 @@ .list a:hover { text-decoration: underline; +} + +.material-symbols-light--info-rounded { + display: inline-block; + width: 24px; + height: 24px; + --svg: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath fill='%23000' d='M12 16.5q.214 0 .357-.144T12.5 16v-4.5q0-.213-.144-.356T11.999 11t-.356.144t-.143.356V16q0 .213.144.356t.357.144M12 9.577q.262 0 .439-.177t.176-.438t-.177-.439T12 8.346t-.438.177t-.177.439t.177.438t.438.177M12.003 21q-1.867 0-3.51-.708q-1.643-.709-2.859-1.924t-1.925-2.856T3 12.003t.709-3.51Q4.417 6.85 5.63 5.634t2.857-1.925T11.997 3t3.51.709q1.643.708 2.859 1.922t1.925 2.857t.709 3.509t-.708 3.51t-1.924 2.859t-2.856 1.925t-3.509.709'/%3E%3C/svg%3E"); + background-color: currentColor; + -webkit-mask-image: var(--svg); + mask-image: var(--svg); + -webkit-mask-repeat: no-repeat; + mask-repeat: no-repeat; + -webkit-mask-size: 100% 100%; + mask-size: 100% 100%; } \ No newline at end of file diff --git a/src/controllers/Api/ApiController.js b/src/controllers/Api/ApiController.js new file mode 100644 index 0000000..73f5fb3 --- /dev/null +++ b/src/controllers/Api/ApiController.js @@ -0,0 +1,58 @@ +import { formatResponse } from "utils/helper.js" +import Router from "utils/router.js" + +class AuthController { + constructor() {} + + /** + * 通用请求函数:依次请求网址数组,返回第一个成功的响应及其类型 + * @param {string[]} urls + * @returns {Promise<{type: string, data: any}>} + */ + async fetchFirstSuccess(urls) { + for (const url of urls) { + try { + const res = await fetch(url, { method: "get", mode: "cors", redirect: "follow" }) + if (!res.ok) continue + const contentType = res.headers.get("content-type") || "" + let data, type + if (contentType.includes("application/json")) { + data = await res.json() + type = "json" + } else if (contentType.includes("text/")) { + data = await res.text() + type = "text" + } else { + data = await res.blob() + type = "blob" + } + return { type, data } + } catch (e) { + // ignore and try next url + } + } + throw new Error("All requests failed") + } + + async random(ctx) { + const { type, data } = await this.fetchFirstSuccess(["https://api.miaomc.cn/image/get"]) + if (type === "blob") { + ctx.set("Content-Type", "image/jpeg") + ctx.body = data + } else { + ctx.body = formatResponse(false, "Failed to fetch image") + } + } + + /** + * 路由注册 + */ + static createRoutes() { + const controller = new AuthController() + const router = new Router({ prefix: "/api/pics" }) + router.get("/random", controller.random.bind(controller), { auth: false }) + return router + } +} + +export default AuthController diff --git a/src/controllers/Page/PageController.js b/src/controllers/Page/PageController.js index c361c50..b667d1f 100644 --- a/src/controllers/Page/PageController.js +++ b/src/controllers/Page/PageController.js @@ -171,10 +171,11 @@ class PageController { router.get("/articles", controller.pageGet("page/articles/index"), { auth: false }) router.get("/about", controller.pageGet("page/about/index"), { auth: false }) - router.get("/terms", controller.pageGet("page/index/terms"), { auth: false }) - router.get("/privacy", controller.pageGet("page/index/privacy"), { auth: false }) - router.get("/faq", controller.pageGet("page/index/faq"), { auth: false }) - // router.get("/feedback", controller.pageGet("page/index/feedback"), { auth: false }) + router.get("/terms", controller.pageGet("page/extra/terms"), { auth: false }) + router.get("/privacy", controller.pageGet("page/extra/privacy"), { auth: false }) + router.get("/faq", controller.pageGet("page/extra/faq"), { auth: false }) + router.get("/feedback", controller.pageGet("page/extra/feedback"), { auth: false }) + router.get("/profile", controller.pageGet("page/profile/index"), { auth: true }) router.get("/login", controller.loginGet.bind(controller), { auth: "try" }) router.post("/login", controller.loginPost.bind(controller), { auth: false }) router.get("/captcha", controller.captchaGet.bind(controller), { auth: false }) diff --git a/src/views/layouts/empty.pug b/src/views/layouts/empty.pug index 43cf7ae..5bacb35 100644 --- a/src/views/layouts/empty.pug +++ b/src/views/layouts/empty.pug @@ -24,7 +24,7 @@ block $$content else .right.menu.desktop-only a.menu-item(hx-post="/logout") 退出 - a.menu-item() 欢迎您 , #{$user.username} + a.menu-item(href="/profile") 欢迎您 , #{$user.username} // 移动端:汉堡按钮 button.menu-toggle(type="button" aria-label="打开菜单") span.bar diff --git a/src/views/layouts/root.pug b/src/views/layouts/root.pug index 371d4e6..ba4c10e 100644 --- a/src/views/layouts/root.pug +++ b/src/views/layouts/root.pug @@ -38,9 +38,9 @@ html(lang="zh-CN") block $$scripts script. //- 处理滚动条位置 + const el = document.querySelector('.simplebar-content-wrapper') + const scrollTop = sessionStorage.getItem('scrollTop-'+location.pathname) window.onload = function() { - const el = document.querySelector('.simplebar-content-wrapper') - const scrollTop = sessionStorage.getItem('scrollTop-'+location.pathname) el.scrollTop = scrollTop el.addEventListener("scroll", function(e) { sessionStorage.setItem('scrollTop-'+location.pathname, e.target.scrollTop) diff --git a/src/views/page/index/faq.pug b/src/views/page/extra/faq.pug similarity index 98% rename from src/views/page/index/faq.pug rename to src/views/page/extra/faq.pug index f9cf08a..5b0761b 100644 --- a/src/views/page/index/faq.pug +++ b/src/views/page/extra/faq.pug @@ -1,7 +1,6 @@ extends /layouts/empty.pug block pageHead - +css('css/page/index.css') block pageContent .faq.container(class="mt-[20px] bg-white rounded-[12px] shadow p-6 border border-gray-100") diff --git a/src/views/page/index/feedback.pug b/src/views/page/extra/feedback.pug similarity index 96% rename from src/views/page/index/feedback.pug rename to src/views/page/extra/feedback.pug index 8a141ee..985b18b 100644 --- a/src/views/page/index/feedback.pug +++ b/src/views/page/extra/feedback.pug @@ -1,7 +1,6 @@ extends /layouts/empty.pug block pageHead - +css('css/page/index.css') block pageContent .feedback.container(class="mt-[20px] bg-white rounded-[12px] shadow p-6 border border-gray-100") @@ -9,7 +8,7 @@ block pageContent p(class="text-gray-600 mb-6") 欢迎提出您的建议或问题,我们会尽快处理。 form(class="space-y-4" method="post" action="#" onsubmit="alert('感谢反馈!'); return false;") - .grid.grid-cols-1.md\:grid-cols-2.gap-4 + .grid.grid-cols-1(class="md:grid-cols-2 gap-4") .form-item label.block.text-sm.text-gray-600.mb-1(for="name") 您的称呼 input#name(type="text" name="name" placeholder="例如:张三" class="w-full border border-gray-200 rounded px-3 py-2 focus:outline-none focus:ring-2 focus:ring-blue-200") diff --git a/src/views/page/index/privacy.pug b/src/views/page/extra/privacy.pug similarity index 99% rename from src/views/page/index/privacy.pug rename to src/views/page/extra/privacy.pug index be9b0b1..89927f7 100644 --- a/src/views/page/index/privacy.pug +++ b/src/views/page/extra/privacy.pug @@ -1,8 +1,5 @@ extends /layouts/empty.pug -block pageHead - +css('css/page/index.css') - block pageContent .privacy.container(class="mt-[20px] bg-white rounded-[12px] shadow p-6 border border-gray-100") h1(class="text-2xl font-bold mb-4") 隐私政策 diff --git a/src/views/page/index/terms.pug b/src/views/page/extra/terms.pug similarity index 99% rename from src/views/page/index/terms.pug rename to src/views/page/extra/terms.pug index c271f07..a64d456 100644 --- a/src/views/page/index/terms.pug +++ b/src/views/page/extra/terms.pug @@ -1,8 +1,5 @@ extends /layouts/empty.pug -block pageHead - +css('css/page/index.css') - block pageContent .terms.container(class="mt-[20px] bg-white rounded-[12px] shadow p-6 border border-gray-100") h1(class="text-2xl font-bold mb-4") 服务条款 diff --git a/src/views/page/index/index.pug b/src/views/page/index/index.pug index 1438c2c..72463e7 100644 --- a/src/views/page/index/index.pug +++ b/src/views/page/index/index.pug @@ -7,8 +7,9 @@ block pageHead +js("https://unpkg.com/tippy.js@5") mixin item(url, desc) - a(href=url data-tippy-content=desc target="_blank" class="inline-block text-[16px] p-[10px] rounded-[10px] shadow") + a(href=url target="_blank" class="inline-flex items-center text-[16px] p-[10px] rounded-[10px] shadow") block + .material-symbols-light--info-rounded(data-tippy-content=desc) mixin card(blog) .article-card(class="bg-white rounded-[12px] shadow p-6 transition hover:shadow-lg border border-gray-100") diff --git a/src/views/page/profile/index.pug b/src/views/page/profile/index.pug new file mode 100644 index 0000000..b46cbad --- /dev/null +++ b/src/views/page/profile/index.pug @@ -0,0 +1,7 @@ +extends /layouts/empty.pug + +block pageHead + + +block pageContent + div sad \ No newline at end of file