diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..bdb388c --- /dev/null +++ b/.dockerignore @@ -0,0 +1,9 @@ +.nuxt/** +.vscode/** +.output/** +node_modules/** +db/** +nginx/** +supabase/** +.git/** +README.md \ No newline at end of file diff --git a/.env.example b/.env.example deleted file mode 100644 index 0ef68e4..0000000 --- a/.env.example +++ /dev/null @@ -1,18 +0,0 @@ -# unstorage driver used as primary database -KV_DRIVER="vercelKV" - -KV_URL="redis://******:******@******.******.***:****" # https://unstorage.unjs.io/drivers/vercel -KV_REST_API_URL="https://*****.******.***" -KV_REST_API_TOKEN="*****" -KV_REST_API_READ_ONLY_TOKEN="*****" - -# Telegram bot username and token (used for login) -TG_BOT="******" -TG_BOT_TOKEN="******" - -# Algolia for search -ALGOLIA_API_KEY="******" -ALGOLIA_APPLICATION_ID="******" - -FILE_SERVER_URL="https://*****.******.***" -FILE_SERVER_SIGNATURE="******" \ No newline at end of file diff --git a/.gitignore b/.gitignore index e87bc73..532aedf 100644 --- a/.gitignore +++ b/.gitignore @@ -10,7 +10,7 @@ dist node_modules # Logs -logs +./logs *.log # Misc @@ -21,4 +21,7 @@ logs # Local env files .env .env.* -!.env.example \ No newline at end of file +!.env.example +bundled/README.md + +.kv \ No newline at end of file diff --git a/.prettierrc b/.prettierrc new file mode 100644 index 0000000..48ea507 --- /dev/null +++ b/.prettierrc @@ -0,0 +1,5 @@ +{ + "plugins": ["prettier-plugin-tailwindcss"], + "tabWidth": 4, + "useTabs": true +} diff --git a/.vscode/tasks.json b/.vscode/tasks.json index 61c5de3..74b1067 100644 --- a/.vscode/tasks.json +++ b/.vscode/tasks.json @@ -1,16 +1,16 @@ { - "version": "2.0.0", - "tasks": [ - { - "type": "npm", - "script": "dev", - "problemMatcher": [], - "label": "bun: dev", - "detail": "nuxt dev", - "group": { - "kind": "test", - "isDefault": true - } - } - ] + "version": "2.0.0", + "tasks": [ + { + "type": "npm", + "script": "dev", + "problemMatcher": [], + "label": "bun: dev", + "detail": "nuxt dev", + "group": { + "kind": "test", + "isDefault": true + } + } + ] } diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..eee1b65 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,21 @@ +FROM node:20 AS build +WORKDIR /usr/src/frontend + +RUN npm install -g bun +RUN npm install -g nuxi + +COPY package.json . +RUN bun install + + +COPY . . + +RUN nuxi build + +FROM node:20 AS release +WORKDIR /usr/src/frontend + +COPY --from=build /usr/src/frontend/.output .output + +# run the app +ENTRYPOINT [ "node", ".output/server/index.mjs" ] \ No newline at end of file diff --git a/README.md b/README.md index b7de16b..faf5d18 100644 --- a/README.md +++ b/README.md @@ -8,6 +8,4 @@ The official website for School 550 in Saint-Petersburg, Russia. ## Powered by: -### [](https://nuxt.com) - -### [](https://vercel.com/home) +### [](https://nuxt.com) \ No newline at end of file diff --git a/app/app.config.ts b/app/app.config.ts index 69cabe0..5ccb592 100644 --- a/app/app.config.ts +++ b/app/app.config.ts @@ -1,14 +1,14 @@ export default defineAppConfig({ - ui: { - primary: "blue", - gray: "neutral", - icons: { - dynamic: true, - }, - commandPalette: { - default: { - loadingIcon: "fluent:spinner-ios-16-filled", - }, - }, - }, + ui: { + primary: "blue", + gray: "neutral", + icons: { + dynamic: true, + }, + commandPalette: { + default: { + loadingIcon: "fluent:spinner-ios-16-filled", + }, + }, + }, }); diff --git a/app/app.vue b/app/app.vue index c6bef14..b73a9b1 100644 --- a/app/app.vue +++ b/app/app.vue @@ -1,44 +1,64 @@ + + diff --git a/app/assets/style.scss b/app/assets/style.scss index a0bd773..b6182d7 100644 --- a/app/assets/style.scss +++ b/app/assets/style.scss @@ -1,25 +1,28 @@ :root { - font-family: Raleway, sans-serif; - scroll-behavior: smooth; + font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen, + Ubuntu, Cantarell, "Open Sans", "Helvetica Neue", sans-serif; + scroll-behavior: smooth; } .page-enter-from, .page-leave-to { - opacity: 0; + opacity: 0; } .page-enter-active, .page-leave-active { - transition: opacity 0.5s; + transition: opacity 0.5s ease-in-out; } .layout-enter-from, .layout-leave-to { - opacity: 0; - transform: translateY(-50px); + opacity: 0; + transform: translateY(-50px); } .layout-enter-active, .layout-leave-active { - transition: opacity 0.5s, transform 0.5s; + transition: + opacity 0.5s, + transform 0.5s; } diff --git a/app/components/AppLogo.vue b/app/components/AppLogo.vue index c6576c9..634cc40 100644 --- a/app/components/AppLogo.vue +++ b/app/components/AppLogo.vue @@ -1,11 +1,22 @@ - + diff --git a/app/components/ArticleCard.vue b/app/components/ArticleCard.vue index b0a5ef2..509d310 100644 --- a/app/components/ArticleCard.vue +++ b/app/components/ArticleCard.vue @@ -1,5 +1,5 @@ - + diff --git a/app/components/ArticlePlaceholder.vue b/app/components/ArticlePlaceholder.vue index adda5ea..a907f0a 100644 --- a/app/components/ArticlePlaceholder.vue +++ b/app/components/ArticlePlaceholder.vue @@ -1,5 +1,5 @@ diff --git a/app/components/ClientFooter.vue b/app/components/ClientFooter.vue index d4c2a0c..e6330de 100644 --- a/app/components/ClientFooter.vue +++ b/app/components/ClientFooter.vue @@ -1,142 +1,214 @@ - - - - - + + + + + diff --git a/app/components/ClientHeader.vue b/app/components/ClientHeader.vue index 6713f8f..e8fd696 100644 --- a/app/components/ClientHeader.vue +++ b/app/components/ClientHeader.vue @@ -1,5 +1,9 @@ diff --git a/app/components/ColorSwitcher.vue b/app/components/ColorSwitcher.vue index 1b7e404..d7bbde9 100644 --- a/app/components/ColorSwitcher.vue +++ b/app/components/ColorSwitcher.vue @@ -2,44 +2,49 @@ const colorMode = useColorMode(); const modes = [ - { - key: "dark", - icon: "line-md:sunny-outline-to-moon-alt-loop-transition", - }, - { - key: "light", - icon: "line-md:moon-alt-to-sunny-outline-loop-transition", - }, + { + key: "dark", + icon: "line-md:sunny-outline-to-moon-alt-loop-transition", + }, + { + key: "light", + icon: "line-md:moon-alt-to-sunny-outline-loop-transition", + }, ]; const currentMode = computed(() => { - return modes.find((mode) => mode.key === colorMode.preference) || modes[0]; + return modes.find((mode) => mode.key === colorMode.preference) || modes[0]; }); const toggleMode = () => { - let done = false; - modes.forEach((mode, index) => { - if (currentMode.value.key === mode.key && !done) { - done = true; - colorMode.preference = modes[(index + 1) % modes.length].key; - } - }); + let done = false; + modes.forEach((mode, index) => { + if (currentMode.value && currentMode.value.key === mode.key && !done) { + done = true; + colorMode.preference = modes[(index + 1) % modes.length].key; + } + }); }; diff --git a/app/components/FeedbackForm.vue b/app/components/FeedbackForm.vue index fe6a91a..08941c9 100644 --- a/app/components/FeedbackForm.vue +++ b/app/components/FeedbackForm.vue @@ -3,18 +3,18 @@ const feedbackForm = useState("feedback_form_enabled", () => false); let msgListener: EventListener | undefined = undefined; onMounted(() => { - if (msgListener) { - return; - } - msgListener = window.addEventListener( - "message", - function (event) { - if (event.data.close) { - feedbackForm.value = false; - } - }, - false - ); + if (msgListener) { + return; + } + msgListener = window.addEventListener( + "message", + function (event) { + if (event.data.close) { + feedbackForm.value = false; + } + }, + false, + ); }); const spinner = ref(true); @@ -22,28 +22,28 @@ const hideSpinner = () => (spinner.value = false);