mirror of
https://github.com/gotson/komga.git
synced 2026-05-08 12:35:30 +02:00
refactor components into fragments
This commit is contained in:
parent
86e1d06280
commit
83e7c6fac3
33 changed files with 108 additions and 60 deletions
|
|
@ -10,7 +10,7 @@ The `openapi-generate` tasks will generate bindings, and should be run when the
|
|||
|
||||
## Tests
|
||||
|
||||
We use Vitest projects to separate different kind of tests:
|
||||
Vitest projects are used to specify different kind of tests:
|
||||
- `unit`: unit tests
|
||||
- `storybook`: component tests, defined in Storybook stories. Those can be run from Storybook directly or through Vitest.
|
||||
|
||||
|
|
@ -43,3 +43,17 @@ Tasks:
|
|||
- `i18n:compile`: compiles the translated files in `i18n` into `./src/i18n`. This folder is what the application uses at runtime.
|
||||
|
||||
The Vite plugin [dir2json](https://github.com/buddywang/vite-plugin-dir2json) is used to load the available translation files, see `./src/utils/locale-helper.ts` for more details.
|
||||
|
||||
## Components
|
||||
|
||||
Vue template files are segregated in different categories depending on usage:
|
||||
- `./src/components`: Pure UI components, driven by model/props. Those are reusable components.
|
||||
- `./src/fragments`: Fragments interact with other layers of the application, like API or Pinia stores. They are split into separate files for easier organization, but are not necessarily reused.
|
||||
- `./src/pages`: Pages make use of components/fragments as well as API / Pinia stores. Each Component in that folder is converted to a navigable route using [unplugin-vue-router](https://github.com/posva/unplugin-vue-router). Pages contain a special `<route>` to define the layout to use as well as other router meta attributes.
|
||||
- `./src/layouts`: Wrapper component around Pages.
|
||||
|
||||
Components and Fragments are automatically imported using [unplugin-vue-components](https://github.com/unplugin/unplugin-vue-components).
|
||||
|
||||
## Icons
|
||||
|
||||
[UnoCSS Icons preset](https://unocss.dev/presets/icons) is used for icons, with the MDI set from Iconify.
|
||||
|
|
|
|||
|
|
@ -2,9 +2,9 @@
|
|||
<v-app>
|
||||
<router-view />
|
||||
|
||||
<SnackQueue />
|
||||
<DialogInstanceConfirmEdit />
|
||||
<DialogInstanceConfirm />
|
||||
<FragmentSnackQueue />
|
||||
<FragmentDialogInstanceConfirmEdit />
|
||||
<FragmentDialogInstanceConfirm />
|
||||
</v-app>
|
||||
</template>
|
||||
|
||||
|
|
|
|||
40
next-ui/src/components.d.ts
vendored
40
next-ui/src/components.d.ts
vendored
|
|
@ -8,31 +8,31 @@ export {}
|
|||
/* prettier-ignore */
|
||||
declare module 'vue' {
|
||||
export interface GlobalComponents {
|
||||
AppBar: typeof import('./components/app/Bar.vue')['default']
|
||||
AppDrawer: typeof import('./components/app/drawer/Drawer.vue')['default']
|
||||
AppDrawerFooter: typeof import('./components/app/drawer/Footer.vue')['default']
|
||||
AppDrawerMenu: typeof import('./components/app/drawer/menu/Menu.vue')['default']
|
||||
AppDrawerMenuAccount: typeof import('./components/app/drawer/menu/Account.vue')['default']
|
||||
AppDrawerMenuHistory: typeof import('./components/app/drawer/menu/History.vue')['default']
|
||||
AppDrawerMenuImport: typeof import('./components/app/drawer/menu/Import.vue')['default']
|
||||
AppDrawerMenuLogout: typeof import('./components/app/drawer/menu/Logout.vue')['default']
|
||||
AppDrawerMenuMedia: typeof import('./components/app/drawer/menu/Media.vue')['default']
|
||||
AppDrawerMenuServer: typeof import('./components/app/drawer/menu/Server.vue')['default']
|
||||
AppFooter: typeof import('./components/AppFooter.vue')['default']
|
||||
BuildCommit: typeof import('./components/BuildCommit.vue')['default']
|
||||
BuildVersion: typeof import('./components/BuildVersion.vue')['default']
|
||||
DialogConfirm: typeof import('./components/dialog/Confirm.vue')['default']
|
||||
DialogConfirmEdit: typeof import('./components/dialog/ConfirmEdit.vue')['default']
|
||||
DialogInstanceConfirm: typeof import('./components/dialog/instance/Confirm.vue')['default']
|
||||
DialogInstanceConfirmEdit: typeof import('./components/dialog/instance/ConfirmEdit.vue')['default']
|
||||
FormUserChangePassword: typeof import('./components/form/user/ChangePassword.vue')['default']
|
||||
FormUserEdit: typeof import('./components/form/user/Edit.vue')['default']
|
||||
FragmentBuildCommit: typeof import('./fragments/fragment/BuildCommit.vue')['default']
|
||||
FragmentBuildVersion: typeof import('./fragments/fragment/BuildVersion.vue')['default']
|
||||
FragmentDialogConfirm: typeof import('./fragments/fragment/dialog/Confirm.vue')['default']
|
||||
FragmentDialogConfirmEdit: typeof import('./fragments/fragment/dialog/ConfirmEdit.vue')['default']
|
||||
FragmentLocaleSelector: typeof import('./fragments/fragment/LocaleSelector.vue')['default']
|
||||
FragmentSnackQueue: typeof import('./fragments/fragment/SnackQueue.vue')['default']
|
||||
FragmentThemeSelector: typeof import('./fragments/fragment/ThemeSelector.vue')['default']
|
||||
HelloWorld: typeof import('./components/HelloWorld.vue')['default']
|
||||
LocaleSelector: typeof import('./components/LocaleSelector.vue')['default']
|
||||
NoticeUserDeletion: typeof import('./components/notice/UserDeletion.vue')['default']
|
||||
LayoutAppBar: typeof import('./fragments/layout/app/Bar.vue')['default']
|
||||
LayoutAppDrawer: typeof import('./fragments/layout/app/drawer/Drawer.vue')['default']
|
||||
LayoutAppDrawerFooter: typeof import('./fragments/layout/app/drawer/Footer.vue')['default']
|
||||
LayoutAppDrawerMenu: typeof import('./fragments/layout/app/drawer/menu/Menu.vue')['default']
|
||||
LayoutAppDrawerMenuAccount: typeof import('./fragments/layout/app/drawer/menu/Account.vue')['default']
|
||||
LayoutAppDrawerMenuHistory: typeof import('./fragments/layout/app/drawer/menu/History.vue')['default']
|
||||
LayoutAppDrawerMenuImport: typeof import('./fragments/layout/app/drawer/menu/Import.vue')['default']
|
||||
LayoutAppDrawerMenuLogout: typeof import('./fragments/layout/app/drawer/menu/Logout.vue')['default']
|
||||
LayoutAppDrawerMenuMedia: typeof import('./fragments/layout/app/drawer/menu/Media.vue')['default']
|
||||
LayoutAppDrawerMenuServer: typeof import('./fragments/layout/app/drawer/menu/Server.vue')['default']
|
||||
RouterLink: typeof import('vue-router')['RouterLink']
|
||||
RouterView: typeof import('vue-router')['RouterView']
|
||||
SnackQueue: typeof import('./components/SnackQueue.vue')['default']
|
||||
ThemeSelector: typeof import('./components/ThemeSelector.vue')['default']
|
||||
UserDeletionWarning: typeof import('./components/user/DeletionWarning.vue')['default']
|
||||
UserFormChangePassword: typeof import('./components/user/form/ChangePassword.vue')['default']
|
||||
UserFormCreateEdit: typeof import('./components/user/form/CreateEdit.vue')['default']
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,16 +0,0 @@
|
|||
<template>
|
||||
<v-list nav>
|
||||
<AppDrawerMenuImport v-if="isAdmin" />
|
||||
<AppDrawerMenuMedia v-if="isAdmin" />
|
||||
<AppDrawerMenuHistory v-if="isAdmin" />
|
||||
<AppDrawerMenuServer v-if="isAdmin" />
|
||||
<AppDrawerMenuAccount />
|
||||
<AppDrawerMenuLogout />
|
||||
</v-list>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { useCurrentUser } from '@/colada/queries/current-user'
|
||||
|
||||
const { isAdmin } = useCurrentUser()
|
||||
</script>
|
||||
|
|
@ -1 +0,0 @@
|
|||
Simple forms that can be wrapped by a `v-form`, or used within a `DialogEditConfirm`.
|
||||
|
|
@ -1 +0,0 @@
|
|||
Components that can be used within a `DialogConfirm`.
|
||||
35
next-ui/src/fragments/README.md
Normal file
35
next-ui/src/fragments/README.md
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
# Fragments
|
||||
|
||||
Vue template files in this folder are automatically imported.
|
||||
|
||||
## 🚀 Usage
|
||||
|
||||
Importing is handled by [unplugin-vue-components](https://github.com/unplugin/unplugin-vue-components). This plugin automatically imports `.vue` files created in the `src/components` directory, and registers them as global components. This means that you can use any component in your application without having to manually import it.
|
||||
|
||||
The following example assumes a component located at `src/components/MyComponent.vue`:
|
||||
|
||||
```vue
|
||||
<template>
|
||||
<div>
|
||||
<MyComponent />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
//
|
||||
</script>
|
||||
```
|
||||
|
||||
When your template is rendered, the component's import will automatically be inlined, which renders to this:
|
||||
|
||||
```vue
|
||||
<template>
|
||||
<div>
|
||||
<MyComponent />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import MyComponent from '@/components/MyComponent.vue'
|
||||
</script>
|
||||
```
|
||||
|
|
@ -11,8 +11,8 @@
|
|||
</RouterLink>
|
||||
Komga
|
||||
</v-app-bar-title>
|
||||
<LocaleSelector />
|
||||
<ThemeSelector />
|
||||
<FragmentLocaleSelector />
|
||||
<FragmentThemeSelector />
|
||||
</v-app-bar>
|
||||
</template>
|
||||
|
||||
|
|
@ -1,9 +1,9 @@
|
|||
<template>
|
||||
<v-navigation-drawer v-model="appStore.drawer">
|
||||
<AppDrawerMenu />
|
||||
<LayoutAppDrawerMenu />
|
||||
|
||||
<template #append>
|
||||
<AppDrawerFooter />
|
||||
<LayoutAppDrawerFooter />
|
||||
</template>
|
||||
</v-navigation-drawer>
|
||||
</template>
|
||||
|
|
@ -25,8 +25,8 @@
|
|||
class="d-flex align-center text-caption text-medium-emphasis pa-2"
|
||||
>
|
||||
<div class="d-flex ms-auto">
|
||||
<BuildCommit class="me-2" />
|
||||
<BuildVersion />
|
||||
<FragmentBuildCommit class="me-2" />
|
||||
<FragmentBuildVersion />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
16
next-ui/src/fragments/layout/app/drawer/menu/Menu.vue
Normal file
16
next-ui/src/fragments/layout/app/drawer/menu/Menu.vue
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
<template>
|
||||
<v-list nav>
|
||||
<LayoutAppDrawerMenuImport v-if="isAdmin" />
|
||||
<LayoutAppDrawerMenuMedia v-if="isAdmin" />
|
||||
<LayoutAppDrawerMenuHistory v-if="isAdmin" />
|
||||
<LayoutAppDrawerMenuServer v-if="isAdmin" />
|
||||
<LayoutAppDrawerMenuAccount />
|
||||
<LayoutAppDrawerMenuLogout />
|
||||
</v-list>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { useCurrentUser } from '@/colada/queries/current-user'
|
||||
|
||||
const { isAdmin } = useCurrentUser()
|
||||
</script>
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
<template>
|
||||
<AppBar />
|
||||
<LayoutAppBar />
|
||||
|
||||
<AppDrawer />
|
||||
<LayoutAppDrawer />
|
||||
|
||||
<v-main scrollable>
|
||||
<v-container
|
||||
|
|
|
|||
|
|
@ -104,8 +104,8 @@
|
|||
<v-row justify="center">
|
||||
<v-col cols="auto">
|
||||
<div class="d-flex ga-4">
|
||||
<LocaleSelector />
|
||||
<ThemeSelector />
|
||||
<FragmentLocaleSelector />
|
||||
<FragmentThemeSelector />
|
||||
</div>
|
||||
</v-col>
|
||||
</v-row>
|
||||
|
|
|
|||
|
|
@ -91,9 +91,6 @@ import {
|
|||
useUpdateUser,
|
||||
useUpdateUserPassword,
|
||||
} from '@/colada/mutations/update-user'
|
||||
import FormUserChangePassword from '@/components/form/user/ChangePassword.vue'
|
||||
import FormUserEdit from '@/components/form/user/Edit.vue'
|
||||
import NoticeUserDeletion from '@/components/notice/UserDeletion.vue'
|
||||
import { useLibraries } from '@/colada/queries/libraries'
|
||||
import { commonMessages } from '@/utils/i18n/common-messages'
|
||||
import { storeToRefs } from 'pinia'
|
||||
|
|
@ -101,6 +98,9 @@ import { useDialogsStore } from '@/stores/dialogs'
|
|||
import { useMessagesStore } from '@/stores/messages'
|
||||
import { useIntl } from 'vue-intl'
|
||||
import { useDisplay } from 'vuetify'
|
||||
import UserDeletionWarning from '@/components/user/DeletionWarning.vue'
|
||||
import UserFormCreateEdit from '@/components/user/form/CreateEdit.vue'
|
||||
import UserFormChangePassword from '@/components/user/form/ChangePassword.vue'
|
||||
|
||||
const intl = useIntl()
|
||||
|
||||
|
|
@ -185,7 +185,7 @@ function showDialog(action: ACTION, user?: components['schemas']['UserDto']) {
|
|||
fullscreen: display.xs.value,
|
||||
}
|
||||
dialogConfirmEdit.value.slot = {
|
||||
component: markRaw(FormUserEdit),
|
||||
component: markRaw(UserFormCreateEdit),
|
||||
props: {},
|
||||
}
|
||||
dialogConfirmEdit.value.record = {
|
||||
|
|
@ -213,7 +213,7 @@ function showDialog(action: ACTION, user?: components['schemas']['UserDto']) {
|
|||
fullscreen: display.xs.value,
|
||||
}
|
||||
dialogConfirmEdit.value.slot = {
|
||||
component: markRaw(FormUserEdit),
|
||||
component: markRaw(UserFormCreateEdit),
|
||||
props: {},
|
||||
}
|
||||
dialogConfirmEdit.value.record = {
|
||||
|
|
@ -243,7 +243,7 @@ function showDialog(action: ACTION, user?: components['schemas']['UserDto']) {
|
|||
closeOnSave: false,
|
||||
}
|
||||
dialogConfirm.value.slotWarning = {
|
||||
component: markRaw(NoticeUserDeletion),
|
||||
component: markRaw(UserDeletionWarning),
|
||||
props: {},
|
||||
}
|
||||
dialogConfirm.value.callback = handleDialogConfirmation
|
||||
|
|
@ -256,7 +256,7 @@ function showDialog(action: ACTION, user?: components['schemas']['UserDto']) {
|
|||
closeOnSave: false,
|
||||
}
|
||||
dialogConfirmEdit.value.slot = {
|
||||
component: markRaw(FormUserChangePassword),
|
||||
component: markRaw(UserFormChangePassword),
|
||||
props: {},
|
||||
}
|
||||
// password change initiated with an empty string
|
||||
|
|
|
|||
|
|
@ -38,7 +38,8 @@ export default defineConfig({
|
|||
}),
|
||||
Components({
|
||||
dts: 'src/components.d.ts',
|
||||
globsExclude: ['src/components/*.stories.vue'],
|
||||
dirs: ['src/components', 'src/fragments'],
|
||||
globsExclude: ['src/**/*.stories.vue'],
|
||||
directoryAsNamespace: true,
|
||||
collapseSamePrefixes: true,
|
||||
}),
|
||||
|
|
|
|||
Loading…
Reference in a new issue