From ff09eee99343cfa6ee6da301428c4a0b3c790bf6 Mon Sep 17 00:00:00 2001 From: liuweiqing Date: Wed, 21 Feb 2024 15:04:02 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20pwa=E5=8F=AF=E7=A6=BB=E7=BA=BF=E8=AE=BF?= =?UTF-8?q?=E9=97=AE=20service=20worker?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/[lng]/globals.css | 162 +++++++++++++++++++++ app/layout.tsx | 13 ++ middleware.ts | 2 +- {app => public}/android-chrome-192x192.png | Bin {app => public}/android-chrome-512x512.png | Bin {app => public}/apple-touch-icon.png | Bin {app => public}/favicon-16x16.png | Bin {app => public}/favicon-32x32.png | Bin manifest.json => public/manifest.json | 12 +- public/service-worker.js | 22 +++ public/serviceregister.js | 17 +++ {app => public}/site.webmanifest | 0 12 files changed, 221 insertions(+), 7 deletions(-) create mode 100644 app/[lng]/globals.css rename {app => public}/android-chrome-192x192.png (100%) rename {app => public}/android-chrome-512x512.png (100%) rename {app => public}/apple-touch-icon.png (100%) rename {app => public}/favicon-16x16.png (100%) rename {app => public}/favicon-32x32.png (100%) rename manifest.json => public/manifest.json (78%) create mode 100644 public/service-worker.js create mode 100644 public/serviceregister.js rename {app => public}/site.webmanifest (100%) diff --git a/app/[lng]/globals.css b/app/[lng]/globals.css new file mode 100644 index 00000000..d4819a3f --- /dev/null +++ b/app/[lng]/globals.css @@ -0,0 +1,162 @@ +@tailwind base; +@tailwind components; +@tailwind utilities; + +@layer base { + :root { + --background: 200 20% 98%; + --btn-background: 200 10% 91%; + --btn-background-hover: 200 10% 89%; + --foreground: 200 50% 3%; + } + + /* @media (prefers-color-scheme: dark) { + :root { + --background: 200 50% 3%; + --btn-background: 200 10% 9%; + --btn-background-hover: 200 10% 12%; + --foreground: 200 20% 96%; + } + } */ +} + +@layer base { + * { + @apply border-foreground/20; + } +} + +.animate-in { + animation: animateIn 0.3s ease 0.15s both; +} + +@keyframes animateIn { + from { + opacity: 0; + transform: translateY(10px); + } + to { + opacity: 1; + transform: translateY(0); + } +} + +.animate-slide-in-right { + animation: slideInFromRight 0.5s ease-out forwards; +} + +@keyframes slideInFromRight { + 0% { + transform: translateX(100%); /* 从右侧外开始 */ + } + 100% { + transform: translateX(0); /* 完全进入视图 */ + } +} + +.component-container { + @apply fixed top-1/4 right-0; + transform: translateX(100%); /* 动画开始前,确保组件位于视图右侧之外 */ +} +/* 想给上标添加一个鼠标放上去变手型的效果 */ +.ql-editor .ql-super { + cursor: pointer; +} + +@keyframes flash { + 0%, + 100% { + opacity: 1; + } + 50% { + opacity: 0.5; + } +} + +.vip-icon { + animation: flash 1s linear infinite; +} + +/* 动画的基本样式 */ +.slide-enter { + opacity: 0; + transform: translateY(100%); /* 从底部滑入 */ +} +.slide-enter-active { + opacity: 1; + transform: translateY(0); + transition: opacity 300ms ease-out, transform 300ms ease-out; +} + +.slide-exit { + opacity: 1; +} +.slide-exit-active { + opacity: 0; + transform: translateY(100%); /* 向底部滑出 */ + transition: opacity 300ms ease-in, transform 300ms ease-in; +} + +.paper-management-container { + position: fixed; /* 或者使用 `absolute` 根据需要 */ + top: 50%; /* 调整到视口的垂直中心 */ + left: 50%; /* 调整到视口的水平中心 */ + background-color: rgba(255, 255, 255, 0.5); + transform: translate( + -50%, + -50% + ); /* 从中心点向上和向左偏移自身的50%,确保组件居中 */ + z-index: 1000; /* 确保悬浮层在其他内容之上 */ + /* 可以添加其他样式来美化组件,如背景色、阴影等 */ +} + +#editor { + /* width: calc(100vw - 20px); */ + min-height: 250px; + max-height: 400px; + overflow-y: auto; + border: 1px solid #ccc; +} + +/* 适配手机样式 */ +@media (max-width: 768px) { + #editor { + width: 100%; /* 适应屏幕宽度 */ + min-height: 200px; /* 调整为更适合移动设备的尺寸 */ + padding: 5px; /* 减少内边距 */ + } + + #Qtoolbar { + flex-direction: column; /* 在较小屏幕上垂直堆叠工具栏元素 */ + align-items: stretch; /* 拉伸按钮以填充容器 */ + } + + #Qtoolbar > button, + #Qtoolbar > select { + margin-bottom: 10px; /* 增加元素之间的间距 */ + } +} + +/* 输入框基本样式 */ +.textarea-focus-expand { + height: 50px; /* 默认高度 */ + flex-grow: 1; + box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); + border: 1px solid #ccc; + border-radius: 4px; + padding: 10px 15px; + margin-right: 8px; + color: #333; + transition: height 0.3s ease; /* 平滑过渡效果 */ +} + +/* 输入框获得焦点时的样式 */ +.textarea-focus-expand:focus { + height: 100px; /* 聚焦时的高度 */ + border-color: #007bff; /* 改变边框颜色以提供视觉反馈 */ +} + +.icon-hover:hover { + transform: scale(1.2); /* 放大到原大小的1.2倍 */ + transition: transform 0.3s ease; /* 平滑过渡效果 */ +} diff --git a/app/layout.tsx b/app/layout.tsx index 9a30002d..1b87dbab 100644 --- a/app/layout.tsx +++ b/app/layout.tsx @@ -54,6 +54,19 @@ export default function RootLayout({ return ( +
{children} diff --git a/middleware.ts b/middleware.ts index 171cb376..52a6094f 100644 --- a/middleware.ts +++ b/middleware.ts @@ -69,6 +69,6 @@ export const config = { * - favicon.ico (favicon file) * Feel free to modify this pattern to include more paths. */ - "/((?!_next/static|_next/image|favicon.ico|twitter-image.png|opengraph-image.png).*)", + "/((?!_next/static|_next/image|favicon.ico|twitter-image.png|opengraph-image.png|manifest.json|site.webmanifest|favicon-32x32.png|favicon-16x16.png|apple-touch-icon.png|android-chrome-512x512.png|android-chrome-192x192.png|service-worker.js|serviceregister.js).*)", ], }; diff --git a/app/android-chrome-192x192.png b/public/android-chrome-192x192.png similarity index 100% rename from app/android-chrome-192x192.png rename to public/android-chrome-192x192.png diff --git a/app/android-chrome-512x512.png b/public/android-chrome-512x512.png similarity index 100% rename from app/android-chrome-512x512.png rename to public/android-chrome-512x512.png diff --git a/app/apple-touch-icon.png b/public/apple-touch-icon.png similarity index 100% rename from app/apple-touch-icon.png rename to public/apple-touch-icon.png diff --git a/app/favicon-16x16.png b/public/favicon-16x16.png similarity index 100% rename from app/favicon-16x16.png rename to public/favicon-16x16.png diff --git a/app/favicon-32x32.png b/public/favicon-32x32.png similarity index 100% rename from app/favicon-32x32.png rename to public/favicon-32x32.png diff --git a/manifest.json b/public/manifest.json similarity index 78% rename from manifest.json rename to public/manifest.json index 1ba75bba..a67168f1 100644 --- a/manifest.json +++ b/public/manifest.json @@ -8,37 +8,37 @@ "description": "写论文最高效的方式", "icons": [ { - "src": "/app/to/android-chrome-192x192.png", + "src": "/android-chrome-192x192.png", "sizes": "192x192", "type": "image/png", "purpose": "any maskable" }, { - "src": "/app/android-chrome-512x512.png", + "src": "/android-chrome-512x512.png", "sizes": "512x512", "type": "image/png", "purpose": "any maskable" }, { - "src": "/app/apple-touch-icon.png", + "src": "/apple-touch-icon.png", "sizes": "180x180", "type": "image/png", "purpose": "any" }, { - "src": "/app/favicon-16x16.png", + "src": "/favicon-16x16.png", "sizes": "16x16", "type": "image/png", "purpose": "any" }, { - "src": "/app/favicon-32x32.png", + "src": "/favicon-32x32.png", "sizes": "32x32", "type": "image/png", "purpose": "any" }, { - "src": "/app/favicon.ico", + "src": "/favicon.ico", "sizes": "48x48", "type": "image/x-icon", "purpose": "any" diff --git a/public/service-worker.js b/public/service-worker.js new file mode 100644 index 00000000..9c9bec12 --- /dev/null +++ b/public/service-worker.js @@ -0,0 +1,22 @@ +const cacheName = "v1"; + +const cacheClone = async (e) => { + const res = await fetch(e.request); + const resClone = res.clone(); + + const cache = await caches.open(cacheName); + await cache.put(e.request, resClone); + return res; +}; + +const fetchEvent = () => { + self.addEventListener("fetch", (e) => { + e.respondWith( + cacheClone(e) + .catch(() => caches.match(e.request)) + .then((res) => res) + ); + }); +}; + +fetchEvent(); diff --git a/public/serviceregister.js b/public/serviceregister.js new file mode 100644 index 00000000..fdf21b9d --- /dev/null +++ b/public/serviceregister.js @@ -0,0 +1,17 @@ +if ("serviceWorker" in navigator) { + window.addEventListener("load", () => { + navigator.serviceWorker.register("/service-worker.js").then( + (registration) => { + // 注册成功 + console.log( + "ServiceWorker registration successful with scope: ", + registration.scope + ); + }, + (err) => { + // 注册失败 + console.log("ServiceWorker registration failed: ", err); + } + ); + }); +} diff --git a/app/site.webmanifest b/public/site.webmanifest similarity index 100% rename from app/site.webmanifest rename to public/site.webmanifest