diff --git a/.dockerignore b/.dockerignore
new file mode 100644
index 00000000..dacf02b3
--- /dev/null
+++ b/.dockerignore
@@ -0,0 +1,17 @@
+.git
+.github
+.idea
+.vscode
+node_modules
+.nuxt
+.output
+dist
+.data
+*.log
+.env
+Dockerfile
+.dockerignore
+README.md
+README.zh-cn.md
+developUtils
+scripts
diff --git a/.gitmodules b/.gitmodules
deleted file mode 100644
index f0fa768c..00000000
--- a/.gitmodules
+++ /dev/null
@@ -1,3 +0,0 @@
-[submodule "utils"]
- path = utils
- url = https://github.com/AOSC-Dev/website-2023-utils
diff --git a/Dockerfile b/Dockerfile
new file mode 100644
index 00000000..ce5937f9
--- /dev/null
+++ b/Dockerfile
@@ -0,0 +1,23 @@
+# syntax=docker.io/docker/dockerfile:1
+
+FROM node:lts AS builder
+
+WORKDIR /app
+
+# 结合 deploy/nginx-example.conf 配置测试用
+ENV PASTE_API=/api/paste
+
+COPY package.json package-lock.json ./
+RUN npm install
+
+COPY --exclude=deploy . .
+RUN npm run generate
+
+FROM nginx:1.24.0
+
+COPY --from=builder /app/.output/public /usr/share/nginx/html
+COPY deploy/nginx-example.conf /etc/nginx/conf.d/default.conf
+
+EXPOSE 3000
+
+CMD ["nginx", "-g", "daemon off;"]
diff --git a/README.md b/README.md
index c2b9d1b5..99c58faa 100644
--- a/README.md
+++ b/README.md
@@ -55,6 +55,12 @@ If you need to test the paste page, please set `PASTE_API=http://localhost:2334`
in your environmental variables or the `.env` file. For the deployment of
paste-server-rs, please refer to [website-utils](https://github.com/AOSC-Dev/website-utils).
+If you need to test nginx related configuration or test the complete preview in
+an independent environment, please use:
+```
+docker compose up --build
+```
+
Submitting news
---
diff --git a/README.zh-cn.md b/README.zh-cn.md
index b180151b..995f9d33 100644
--- a/README.zh-cn.md
+++ b/README.zh-cn.md
@@ -40,7 +40,12 @@ npm run generate
npm run preview
```
-如果您需要测试剪贴板页面,请创建并修改 `.env` 文件或直接设置环境变量 `PASTE_API=http://localhost:2334`。对于 paste-server-rs 的部署请参考 [website-utils](https://github.com/AOSC-Dev/website-utils)
+如果您需要测试剪贴板页面,请创建并修改 `.env` 文件或直接设置环境变量 `PASTE_API=http://localhost:2334`。对于 paste-server-rs 的部署请参考 [website-utils](https://github.com/AOSC-Dev/website-utils)。
+
+如果您需要测试 nginx 相关配置或在独立环境测试完整预览,请使用:
+```
+docker compose up --build
+```
提交新闻
---
diff --git a/app.vue b/app.vue
index 481e4380..36ef3205 100644
--- a/app.vue
+++ b/app.vue
@@ -1,51 +1,9 @@
-
+
diff --git a/components/CommonContent.vue b/components/CommonContent.vue
index cf168b5b..886f7898 100644
--- a/components/CommonContent.vue
+++ b/components/CommonContent.vue
@@ -40,7 +40,8 @@ const { data: page, error } = await useAsyncData(
if (!content)
throw createError({
- statusMessage: 'Query content failed',
+ statusCode: 404,
+ statusMessage: 'Page not found',
data: {
query: { locale: locale.value, path: contentPath.value },
fallback: fallback
@@ -69,13 +70,7 @@ const { data: page, error } = await useAsyncData(
);
useHead({ title: page.value?.title });
-if (error.value || !page.value) {
- throw createError({
- statusCode: 404,
- statusMessage: 'Page Not Found',
- fatal: true
- });
-}
+if (error.value) throw error.value;
watch(contentRef, () => {
if (route.hash) scrollStore.scrollAndClear();
diff --git a/composables/useDefaultHead.ts b/composables/useDefaultHead.ts
new file mode 100644
index 00000000..9cd29ab8
--- /dev/null
+++ b/composables/useDefaultHead.ts
@@ -0,0 +1,25 @@
+export default () => {
+ const { t } = useI18n();
+
+ useHead({
+ title: t('seo.heading.siteTitle'),
+ titleTemplate: (title) => `${title} | ${t('seo.site.siteName')}`,
+ link: [{ rel: 'icon', type: 'image/svg+xml', href: '/aosc.svg' }],
+ script: [
+ {
+ // This script will execute before the browser renders the
,
+ // ensuring the correct season class is set from the very beginning.
+ textContent:
+ 'document.documentElement.classList.add(["spring","summer","autumn","winter"][(new Date().getMonth()+10)%12/3|0])',
+ type: 'text/javascript',
+ tagPosition: 'head'
+ }
+ ]
+ });
+
+ useSeoMeta({
+ description: t('seo.seo.siteDescription'),
+ ogImage: '/aosc.svg',
+ ogSiteName: t('seo.site.siteName')
+ });
+};
diff --git a/compose.yml b/compose.yml
new file mode 100644
index 00000000..24590f14
--- /dev/null
+++ b/compose.yml
@@ -0,0 +1,7 @@
+services:
+ website:
+ build:
+ context: .
+ ports:
+ - "3000:3000"
+
diff --git a/deploy/nginx-example.conf b/deploy/nginx-example.conf
new file mode 100644
index 00000000..f75ae241
--- /dev/null
+++ b/deploy/nginx-example.conf
@@ -0,0 +1,25 @@
+server {
+ listen 3000;
+ root /usr/share/nginx/html;
+
+ rewrite ^/(.*)/$ /$1 permanent;
+ rewrite ^/(.*)\.html$ /$1 permanent;
+ rewrite ^/news/detail/(.*)\.zh-cn\.md$ /news/$1 permanent;
+
+ # https://nginx.org/en/docs/http/ngx_http_core_module.html#try_files
+ try_files $uri $uri/index.html $uri.html =404;
+
+ error_page 404 /404;
+
+ location /galleryFile {
+ proxy_pass https://aosc.io;
+ }
+ location /assets/news {
+ proxy_pass https://aosc.io;
+ }
+
+ # /api/paste 只在测试时使用,主要为了方便反代
+ location /api/paste {
+ proxy_pass https://paste.aosc.io/;
+ }
+}
diff --git a/error.vue b/error.vue
new file mode 100644
index 00000000..91f4ae43
--- /dev/null
+++ b/error.vue
@@ -0,0 +1,46 @@
+
+
+
+
+
+
+
+
{{ $t('error.cannotFindPage.title') }}
+
+ {{
+ $t('error.cannotFindPage.content.text1', {
+ url: errorData.query.path
+ })
+ }}
+
+
+ {{ $t('error.cannotFindPage.content.text2') }}
+
+ {{ $t('allUniversalLink.periodPoint') }}
+
+
+
+
+ {{ $t('error.unexpectedError', { statusCode: error?.statusCode }) }}
+
+
{{ error?.message ?? error?.statusMessage }}
+
{{ error?.data }}
+
+
+
+
diff --git a/i18n/locales/zh-cn/allUniversalLink.json b/i18n/locales/zh-cn/allUniversalLink.json
index 362c8536..d9b2ad61 100644
--- a/i18n/locales/zh-cn/allUniversalLink.json
+++ b/i18n/locales/zh-cn/allUniversalLink.json
@@ -103,7 +103,7 @@
"url": "/about"
},
"contact": {
- "title": ["各聊天群组", "联系方式", "社区聊天群组", "报告系统使用问题"],
+ "title": ["各聊天群组", "联系方式", "社区聊天群组", "报告系统使用问题", "与我们联系"],
"url": "/contact",
"hash": ["#main"]
},
diff --git a/i18n/locales/zh-cn/error.json b/i18n/locales/zh-cn/error.json
new file mode 100644
index 00000000..c6c9c9e8
--- /dev/null
+++ b/i18n/locales/zh-cn/error.json
@@ -0,0 +1,11 @@
+{
+ "cannotFindPage": {
+ "title": "找不到页面 (404)",
+ "content": {
+ "text1": "您想要访问的页面:{url} 在站点上不存在。请检查您输入的网页地址 (URL) 是否正确。",
+ "text2": "如果该页面链接是其他网页中所引用的,请"
+ }
+ },
+ "errorPage": "错误页",
+ "unexpectedError": "发生意外错误:{statusCode}"
+}
diff --git a/layouts/default.vue b/layouts/default.vue
index a1d4db0a..9d5118be 100644
--- a/layouts/default.vue
+++ b/layouts/default.vue
@@ -1,3 +1,18 @@
+
+
diff --git a/nuxt.config.ts b/nuxt.config.ts
index 35d20550..bfff1adf 100644
--- a/nuxt.config.ts
+++ b/nuxt.config.ts
@@ -90,11 +90,11 @@ export default defineNuxtConfig({
},
server: {
proxy: {
- // For test only
- '/pasteApi': {
+ // Set `PASTE_API` to `/api/paste` to use this
+ '/api/paste': {
target: 'https://paste.aosc.io',
changeOrigin: true,
- rewrite: (path) => path.replace(/^\/pasteApi/, '')
+ rewrite: (path) => path.replace(/^\/api\/paste/, '')
},
'/galleryFile': {
target: 'https://aosc.io',
diff --git a/pages/paste/index.vue b/pages/paste/index.vue
index 96375225..a5892e8b 100644
--- a/pages/paste/index.vue
+++ b/pages/paste/index.vue
@@ -59,7 +59,7 @@ const submit = async () => {
formdata.append('file', toRaw(file.raw), file.name);
});
formdata.append('expiration', Date.parse(pasteFormData.value.expDate) / 1000);
- const { data, error } = await useFetch(config.public.pasteApi + '/', {
+ const { data, error } = await useFetch(config.public.pasteApi, {
method: 'post',
timeout: 36000 + Math.ceil((formdataSize + toailFileSize) / 1048576) * 6000,
body: formdata