Nuxt3=>4, spa-loader, css shenanigans...:
...css shenanigans: daisyui may have had a breaking change at 5.3.0, it wrecks the ui here, as tailwind forces its own styles over daisyuis overrides, for now staying at ~5.2.5, for good measure also @nuxtjs/tailwindcss stays at ^6.13.2 (6.13.2 in pnpmlock) - this may be, because (but i'm not sure) @nuxtjs/tailwind is tailwind3 and not tailwind4? Nuxt3=>4 migration: also changed nuxtimage settings, as the docs have been fixed, path changes, etc
This commit is contained in:
parent
08e2060245
commit
625c1013da
31 changed files with 3514 additions and 3150 deletions
|
|
@ -23,15 +23,16 @@ A shell script at [media-prawo-jazdy](https://git.mandarynki.eu/netman/media-pra
|
|||
- [x] exam (& results?) warning leave message on exit and timer end (and definitely on refresh)
|
||||
- [x] add keybinds:
|
||||
- S - start, D - next question, X - exam end, T/Y - yes, N - no, A - A, B - B, C - C
|
||||
- [ ] i18n - pl, en, de, ua (not all questions are available in ua, api handle)
|
||||
- [ ] i18n - pl, en, de, ua (<del>not all questions are available in ua, api handle</del> - already handled with sql)
|
||||
- [ ] UI i18n
|
||||
- [x] pl
|
||||
- [x] en
|
||||
- [x] de
|
||||
- [ ] ua
|
||||
- [ ] <b>ua</b>
|
||||
- [x] db: examstore add language field, api handle languages (questions lang)
|
||||
- [ ] nuxt3 -> nuxt4
|
||||
- [x] nuxt3 -> nuxt4 (hopefully working fine, seems to do so; so far)
|
||||
- [ ] clean up js code in exam.vue and result.vue (currently a little bit of a mess)
|
||||
- [ ] daisyui is stuck on 5.2.5 - newer versions break UI, reason unknown - consider moving to nuxtUI and another tailwind integration with nuxt than nuxtjs/tailwind
|
||||
|
||||
## Some information about the project
|
||||
|
||||
|
|
|
|||
55
app/components/LoadingScreen.vue
Normal file
55
app/components/LoadingScreen.vue
Normal file
|
|
@ -0,0 +1,55 @@
|
|||
<!-- <script setup lang="ts">
|
||||
const themeStore = useThemeStore();
|
||||
if (
|
||||
themeStore.theme != 'light' ||
|
||||
(window.matchMedia &&
|
||||
window.matchMedia('(prefers-color-scheme: dark)').matches) ||
|
||||
) {
|
||||
sheet.insertRule(
|
||||
'.spa-flex { background: #0f172b !important; color: #fff !important; }',
|
||||
sheet.cssRules.length,
|
||||
);
|
||||
}
|
||||
</script> -->
|
||||
|
||||
<template>
|
||||
<div class="min-h-dvh text-2xl w-full">
|
||||
<div class="spa-loader-flex">
|
||||
<div class="spa-loader-circle"></div>
|
||||
<div class="spa-loader-text"></div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style>
|
||||
.spa-loader-flex {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
min-height: 100dvh;
|
||||
width: 100%;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
gap: 16px;
|
||||
}
|
||||
.spa-loader-circle {
|
||||
display: block;
|
||||
width: 36px;
|
||||
height: 36px;
|
||||
box-sizing: border-box;
|
||||
border: solid 4px transparent;
|
||||
border-top-color: #000;
|
||||
border-left-color: #000;
|
||||
border-bottom-color: #efefef;
|
||||
border-right-color: #efefef;
|
||||
border-radius: 50%;
|
||||
animation: spaLoaderAnimation 400ms linear infinite;
|
||||
}
|
||||
@keyframes spaLoaderAnimation {
|
||||
0% {
|
||||
transform: rotate(0deg);
|
||||
}
|
||||
100% {
|
||||
transform: rotate(360deg);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
@ -39,10 +39,10 @@ const emit = defineEmits<{
|
|||
class="btn btn-md"
|
||||
name="chooser"
|
||||
:class="`${
|
||||
result.basic[num].chosen_answer == ''
|
||||
result.basic[num]?.chosen_answer == ''
|
||||
? 'btn-warning'
|
||||
: result.basic[num].question?.correct_answer ===
|
||||
result.basic[num].chosen_answer
|
||||
: result.basic[num]?.question?.correct_answer ===
|
||||
result.basic[num]?.chosen_answer
|
||||
? 'btn-success'
|
||||
: 'btn-error'
|
||||
} ${now === 'basic' && countBasic === num ? 'outline-set-solid outline-2' : ''}`"
|
||||
|
|
@ -69,10 +69,10 @@ const emit = defineEmits<{
|
|||
class="btn btn-md"
|
||||
name="chooser"
|
||||
:class="`${
|
||||
result.advanced[num].chosen_answer == ''
|
||||
result.advanced[num]?.chosen_answer == ''
|
||||
? 'btn-warning'
|
||||
: result.advanced[num].question?.correct_answer ===
|
||||
result.advanced[num].chosen_answer
|
||||
: result.advanced[num]?.question?.correct_answer ===
|
||||
result.advanced[num]?.chosen_answer
|
||||
? 'btn-success'
|
||||
: 'btn-error'
|
||||
} ${now === 'advanced' && countAdvanced === num ? 'outline-set-solid outline-2' : ''}`"
|
||||
|
|
@ -1,7 +1,11 @@
|
|||
<script lang="ts" setup>
|
||||
import { intervalToDuration, addMinutes, addSeconds, isAfter } from 'date-fns';
|
||||
import { useNow } from '@vueuse/core';
|
||||
import { useExamStore } from '~/store/examStore';
|
||||
import {
|
||||
useExamStore,
|
||||
useBasicStore,
|
||||
useAdvancedStore,
|
||||
} from '~/stores/examStore';
|
||||
|
||||
definePageMeta({ middleware: 'exam' });
|
||||
|
||||
|
|
@ -1,6 +1,9 @@
|
|||
<script setup lang="ts">
|
||||
import CountryFlag from 'vue-country-flag-next';
|
||||
import categories from '~/categories';
|
||||
import categories from '~~/categories';
|
||||
|
||||
import { useExamStore } from '~/stores/examStore';
|
||||
import { useThemeStore } from '~/stores/themeStore';
|
||||
|
||||
onMounted(() => {
|
||||
useHead({
|
||||
|
|
@ -95,6 +98,7 @@ function themeAuto() {
|
|||
{{ $t('auto') }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div
|
||||
class="flex flex-col flex-wrap gap-2 items-start p-4 bg-base-300 border-1 border-slate-500 rounded-xl w-fit"
|
||||
>
|
||||
60
app/spa-loading-template.html
Normal file
60
app/spa-loading-template.html
Normal file
|
|
@ -0,0 +1,60 @@
|
|||
<!doctype html>
|
||||
<html lang="pl">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>nuxt-prawo-jazdy</title>
|
||||
<style>
|
||||
.spa-loader-flex {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
min-height: 100dvh;
|
||||
width: 100%;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
gap: 16px;
|
||||
}
|
||||
.spa-loader-circle {
|
||||
display: block;
|
||||
width: 36px;
|
||||
height: 36px;
|
||||
box-sizing: border-box;
|
||||
border: solid 4px transparent;
|
||||
border-top-color: #000;
|
||||
border-left-color: #000;
|
||||
border-bottom-color: #efefef;
|
||||
border-right-color: #efefef;
|
||||
border-radius: 50%;
|
||||
animation: spaLoaderAnimation 400ms linear infinite;
|
||||
}
|
||||
@keyframes spaLoaderAnimation {
|
||||
0% {
|
||||
transform: rotate(0deg);
|
||||
}
|
||||
100% {
|
||||
transform: rotate(360deg);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
<script>
|
||||
const colorMode = localStorage.getItem('themeStore');
|
||||
const json = JSON.parse(colorMode);
|
||||
if (
|
||||
(window.matchMedia &&
|
||||
window.matchMedia('(prefers-color-scheme: dark)').matches) ||
|
||||
Object.hasOwn(colorMode, 'theme') == 'dark'
|
||||
) {
|
||||
const sheet = window.document.styleSheets[0];
|
||||
sheet.insertRule(
|
||||
'.spa-flex { background: #0f172b !important; color: #fff !important; }',
|
||||
sheet.cssRules.length,
|
||||
);
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<div class="spa-loader-flex">
|
||||
<div class="spa-loader-circle"></div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -1,8 +0,0 @@
|
|||
<template>
|
||||
<div
|
||||
class="flex min-h-dvh justify-center items-center text-5xl flex-col gap-10"
|
||||
>
|
||||
<span class="loading loading-spinner loading-xl scale-[2.5] block" />
|
||||
<span class="block">{{ $t('loading') }}</span>
|
||||
</div>
|
||||
</template>
|
||||
|
|
@ -16,7 +16,7 @@ export default defineNuxtConfig({
|
|||
dirs: ['types/*.ts', 'store/*.ts', 'types/**/*.ts'],
|
||||
},
|
||||
devtools: { enabled: true },
|
||||
css: ['~/assets/main.css'],
|
||||
css: ['~/assets/css/tailwind.css'],
|
||||
runtimeConfig: {
|
||||
public: {
|
||||
cdn_url: process.env.CDN_URL,
|
||||
|
|
@ -25,7 +25,7 @@ export default defineNuxtConfig({
|
|||
routeRules: {
|
||||
'/': { prerender: true },
|
||||
},
|
||||
compatibilityDate: '2024-11-01',
|
||||
compatibilityDate: '2025-12-17',
|
||||
eslint: {
|
||||
config: {
|
||||
stylistic: {
|
||||
|
|
@ -49,7 +49,7 @@ export default defineNuxtConfig({
|
|||
providers: {
|
||||
selfhost: {
|
||||
name: 'selfhost',
|
||||
provider: '~/providers/selfhost.ts',
|
||||
provider: '~~/providers/selfhost.ts',
|
||||
options: {
|
||||
baseUrl: process.env.CDN_URL,
|
||||
},
|
||||
|
|
@ -57,7 +57,5 @@ export default defineNuxtConfig({
|
|||
},
|
||||
provider: 'selfhost',
|
||||
},
|
||||
pinia: {
|
||||
storesDirs: ['./store/**'],
|
||||
},
|
||||
tailwindcss: { exposeConfig: true },
|
||||
});
|
||||
|
|
|
|||
44
package.json
44
package.json
|
|
@ -15,22 +15,20 @@
|
|||
},
|
||||
"dependencies": {
|
||||
"@libsql/client": "^0.15.15",
|
||||
"@nuxt/fonts": "0.11.1",
|
||||
"@nuxt/image": "1.10.0",
|
||||
"@nuxt/fonts": "0.12.1",
|
||||
"@nuxt/image": "2.0.0",
|
||||
"@nuxtjs/i18n": "10.2.1",
|
||||
"@nuxtjs/tailwindcss": "6.13.2",
|
||||
"@pinia/nuxt": "0.11.0",
|
||||
"@pinia/nuxt": "0.11.3",
|
||||
"@vueuse/core": "^14.1.0",
|
||||
"array-shuffle": "^3.0.0",
|
||||
"daisyui": "^5.0.27",
|
||||
"array-shuffle": "^4.0.0",
|
||||
"date-fns": "^4.1.0",
|
||||
"dotenv": "^16.5.0",
|
||||
"drizzle-kit": "^0.31.0",
|
||||
"drizzle-orm": "^0.42.0",
|
||||
"eslint": "^9.24.0",
|
||||
"dotenv": "^17.2.3",
|
||||
"drizzle-kit": "^0.31.8",
|
||||
"drizzle-orm": "^0.45.1",
|
||||
"eslint": "^9.39.2",
|
||||
"lodash": "^4.17.21",
|
||||
"nuxt": "~3.16.2",
|
||||
"pinia": "^3.0.2",
|
||||
"nuxt": "~4.2.2",
|
||||
"pinia": "^3.0.4",
|
||||
"pinia-plugin-persistedstate": "^4.7.1",
|
||||
"ufo": "^1.6.1",
|
||||
"vue": "latest",
|
||||
|
|
@ -39,12 +37,22 @@
|
|||
},
|
||||
"packageManager": "pnpm@10.4.1+sha512.c753b6c3ad7afa13af388fa6d808035a008e30ea9993f58c6663e2bc5ff21679aa834db094987129aa4d488b86df57f7b634981b2f827cdcacc698cc0cfb88af",
|
||||
"devDependencies": {
|
||||
"@nuxt/eslint": "1.3.0",
|
||||
"@types/lodash": "^4.17.16",
|
||||
"eslint-config-prettier": "^10.1.2",
|
||||
"prettier": "^3.5.3",
|
||||
"tsx": "^4.19.3",
|
||||
"@nuxt/eslint": "1.12.1",
|
||||
"@nuxtjs/tailwindcss": "^6.13.2",
|
||||
"@types/lodash": "^4.17.21",
|
||||
"daisyui": "~5.2.0",
|
||||
"eslint-config-prettier": "^10.1.8",
|
||||
"prettier": "^3.7.4",
|
||||
"tsx": "^4.21.0",
|
||||
"typescript": "^5.8.3",
|
||||
"vite-plugin-eslint2": "^5.0.3"
|
||||
"vite-plugin-eslint2": "^5.0.4"
|
||||
},
|
||||
"pnpm": {
|
||||
"onlyBuiltDependencies": [
|
||||
"@parcel/watcher",
|
||||
"esbuild",
|
||||
"sharp",
|
||||
"unrs-resolver"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
|
|
|||
6414
pnpm-lock.yaml
generated
6414
pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load diff
|
|
@ -1,18 +1,18 @@
|
|||
import { joinURL } from 'ufo';
|
||||
import type { ProviderGetImage } from '@nuxt/image';
|
||||
import { createOperationsGenerator } from '#image';
|
||||
import { createOperationsGenerator, defineProvider } from '@nuxt/image/runtime';
|
||||
|
||||
const operationsGenerator = createOperationsGenerator();
|
||||
|
||||
export const getImage: ProviderGetImage = (
|
||||
src,
|
||||
{ modifiers = {}, baseUrl } = {},
|
||||
) => {
|
||||
baseUrl ??= '';
|
||||
export default defineProvider<{ baseURL?: string }>({
|
||||
getImage(src, { modifiers, baseURL }) {
|
||||
if (!baseURL) {
|
||||
baseURL = useRuntimeConfig().public.cdn_url;
|
||||
}
|
||||
|
||||
const operations = operationsGenerator(modifiers);
|
||||
|
||||
return {
|
||||
url: joinURL(baseUrl, src + (operations ? '?' + operations : '')),
|
||||
};
|
||||
url: joinURL(baseURL, src + (operations ? '?' + operations : '')),
|
||||
};
|
||||
},
|
||||
});
|
||||
|
|
|
|||
|
|
@ -2,9 +2,13 @@ import 'dotenv/config';
|
|||
import { drizzle } from 'drizzle-orm/libsql';
|
||||
import { sql, eq, and } from 'drizzle-orm';
|
||||
import arrayShuffle from 'array-shuffle';
|
||||
import { tasks_advanced, questions_advanced, categories_db } from '~/db/schema';
|
||||
import type { AdvancedQuestion } from '~/types';
|
||||
import categories from '~/categories';
|
||||
import {
|
||||
tasks_advanced,
|
||||
questions_advanced,
|
||||
categories_db,
|
||||
} from '~~/db/schema';
|
||||
import type { AdvancedQuestion } from '~~/shared/types';
|
||||
import categories from '~~/categories';
|
||||
|
||||
export default defineEventHandler(async (event) => {
|
||||
const query = getQuery(event);
|
||||
|
|
|
|||
|
|
@ -2,9 +2,9 @@ import 'dotenv/config';
|
|||
import { drizzle } from 'drizzle-orm/libsql';
|
||||
import { sql, eq, and } from 'drizzle-orm';
|
||||
import arrayShuffle from 'array-shuffle';
|
||||
import { tasks, questions, categories_db } from '~/db/schema';
|
||||
import type { BasicQuestion } from '~/types';
|
||||
import categories from '~/categories';
|
||||
import { tasks, questions, categories_db } from '~~/db/schema';
|
||||
import type { BasicQuestion } from '~~/shared/types';
|
||||
import categories from '~~/categories';
|
||||
|
||||
export default defineEventHandler(async (event) => {
|
||||
const query = getQuery(event);
|
||||
|
|
|
|||
|
|
@ -1,5 +1,3 @@
|
|||
/** @type {import('tailwindcss').Config} */
|
||||
|
||||
module.exports = {
|
||||
plugins: [require('daisyui')],
|
||||
daisyui: {
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue