mirror of
https://github.com/gotson/komga.git
synced 2026-05-08 12:35:30 +02:00
selectors
This commit is contained in:
parent
47465a4ff4
commit
fbf8dcfa30
8 changed files with 270 additions and 0 deletions
2
next-ui/src/components.d.ts
vendored
2
next-ui/src/components.d.ts
vendored
|
|
@ -71,6 +71,8 @@ declare module 'vue' {
|
|||
PageHashKnownTable: typeof import('./components/pageHash/KnownTable.vue')['default']
|
||||
PageHashMatchTable: typeof import('./components/pageHash/MatchTable.vue')['default']
|
||||
PageHashUnknownTable: typeof import('./components/pageHash/UnknownTable.vue')['default']
|
||||
PageSizeSelector: typeof import('./components/PageSizeSelector.vue')['default']
|
||||
PresentationSelector: typeof import('./components/PresentationSelector.vue')['default']
|
||||
ReleaseCard: typeof import('./components/release/Card.vue')['default']
|
||||
RemoteFileList: typeof import('./components/RemoteFileList.vue')['default']
|
||||
RouterLink: typeof import('vue-router')['RouterLink']
|
||||
|
|
|
|||
11
next-ui/src/components/PageSizeSelector.mdx
Normal file
11
next-ui/src/components/PageSizeSelector.mdx
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
import { Canvas, Meta } from '@storybook/addon-docs/blocks';
|
||||
|
||||
import * as Stories from './PageSizeSelector.stories';
|
||||
|
||||
<Meta of={Stories} />
|
||||
|
||||
# PageSizeSelector
|
||||
|
||||
A button that will display a list of page sizes when clicked, optionally allowing unpaged content.
|
||||
|
||||
<Canvas of={Stories.Default} />
|
||||
62
next-ui/src/components/PageSizeSelector.stories.ts
Normal file
62
next-ui/src/components/PageSizeSelector.stories.ts
Normal file
|
|
@ -0,0 +1,62 @@
|
|||
import type { Meta, StoryObj } from '@storybook/vue3-vite'
|
||||
|
||||
import PageSizeSelector from './PageSizeSelector.vue'
|
||||
import { expect, fn } from 'storybook/test'
|
||||
|
||||
const meta = {
|
||||
component: PageSizeSelector,
|
||||
render: (args: object) => ({
|
||||
components: { PageSizeSelector },
|
||||
setup() {
|
||||
return { args }
|
||||
},
|
||||
template: '<PageSizeSelector v-model="args.modelValue" v-bind="args" />',
|
||||
}),
|
||||
parameters: {
|
||||
// More on how to position stories at: https://storybook.js.org/docs/configure/story-layout
|
||||
},
|
||||
args: {
|
||||
modelValue: 20,
|
||||
'onUpdate:modelValue': fn(),
|
||||
},
|
||||
} satisfies Meta<typeof PageSizeSelector>
|
||||
|
||||
export default meta
|
||||
type Story = StoryObj<typeof meta>
|
||||
|
||||
export const Default: Story = {
|
||||
args: {},
|
||||
}
|
||||
|
||||
export const Clicked: Story = {
|
||||
args: {},
|
||||
play: async ({ canvas, userEvent }) => {
|
||||
await expect(canvas.getByRole('button')).toBeEnabled()
|
||||
|
||||
await userEvent.click(canvas.getByRole('button'))
|
||||
},
|
||||
}
|
||||
|
||||
export const Unpaged: Story = {
|
||||
args: {
|
||||
modelValue: 'unpaged',
|
||||
allowUnpaged: true,
|
||||
},
|
||||
play: async ({ canvas, userEvent }) => {
|
||||
await expect(canvas.getByRole('button')).toBeEnabled()
|
||||
|
||||
await userEvent.click(canvas.getByRole('button'))
|
||||
},
|
||||
}
|
||||
|
||||
export const CustomSizes: Story = {
|
||||
args: {
|
||||
allowUnpaged: true,
|
||||
sizes: [1, 2, 3, 4, 5],
|
||||
},
|
||||
play: async ({ canvas, userEvent }) => {
|
||||
await expect(canvas.getByRole('button')).toBeEnabled()
|
||||
|
||||
await userEvent.click(canvas.getByRole('button'))
|
||||
},
|
||||
}
|
||||
58
next-ui/src/components/PageSizeSelector.vue
Normal file
58
next-ui/src/components/PageSizeSelector.vue
Normal file
|
|
@ -0,0 +1,58 @@
|
|||
<template>
|
||||
<v-menu>
|
||||
<template #activator="{ props }">
|
||||
<v-btn
|
||||
v-bind="props"
|
||||
icon="i-mdi:view-grid-plus"
|
||||
:aria-label="
|
||||
$formatMessage({
|
||||
description: 'Page size selector button: aria-label',
|
||||
defaultMessage: 'page size selector',
|
||||
id: '2EMvSm',
|
||||
})
|
||||
"
|
||||
/>
|
||||
</template>
|
||||
|
||||
<v-list
|
||||
:selected="[pageSize]"
|
||||
color="primary"
|
||||
>
|
||||
<v-list-item
|
||||
v-for="size in sizes"
|
||||
:key="size"
|
||||
:title="size"
|
||||
:value="size"
|
||||
@click="pageSize = size"
|
||||
/>
|
||||
|
||||
<v-list-item
|
||||
v-if="allowUnpaged"
|
||||
:title="
|
||||
$formatMessage({
|
||||
description: 'Page size selector: unpaged option',
|
||||
defaultMessage: 'All',
|
||||
id: 'MC2JtF',
|
||||
})
|
||||
"
|
||||
value="unpaged"
|
||||
@click="pageSize = 'unpaged'"
|
||||
/>
|
||||
</v-list>
|
||||
</v-menu>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import type { PageSize } from '@/types/page'
|
||||
|
||||
const pageSize = defineModel<PageSize>({ required: true })
|
||||
|
||||
const { sizes = [20, 50, 100, 200, 500], allowUnpaged = false } = defineProps<{
|
||||
sizes?: number[]
|
||||
allowUnpaged?: boolean
|
||||
}>()
|
||||
</script>
|
||||
|
||||
<script lang="ts"></script>
|
||||
|
||||
<style scoped></style>
|
||||
11
next-ui/src/components/PresentationSelector.mdx
Normal file
11
next-ui/src/components/PresentationSelector.mdx
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
import { Canvas, Meta } from '@storybook/addon-docs/blocks';
|
||||
|
||||
import * as Stories from './PresentationSelector.stories';
|
||||
|
||||
<Meta of={Stories} />
|
||||
|
||||
# PresentationSelector
|
||||
|
||||
A button that will display a list of presentation modes when clicked.
|
||||
|
||||
<Canvas of={Stories.Default} />
|
||||
50
next-ui/src/components/PresentationSelector.stories.ts
Normal file
50
next-ui/src/components/PresentationSelector.stories.ts
Normal file
|
|
@ -0,0 +1,50 @@
|
|||
import type { Meta, StoryObj } from '@storybook/vue3-vite'
|
||||
|
||||
import PresentationSelector from './PresentationSelector.vue'
|
||||
import { expect, fn } from 'storybook/test'
|
||||
|
||||
const meta = {
|
||||
component: PresentationSelector,
|
||||
render: (args: object) => ({
|
||||
components: { PresentationSelector },
|
||||
setup() {
|
||||
return { args }
|
||||
},
|
||||
template: '<PresentationSelector v-model="args.modelValue" v-bind="args" />',
|
||||
}),
|
||||
parameters: {
|
||||
// More on how to position stories at: https://storybook.js.org/docs/configure/story-layout
|
||||
},
|
||||
args: {
|
||||
modelValue: 'grid',
|
||||
modes: ['grid', 'list', 'table'],
|
||||
'onUpdate:modelValue': fn(),
|
||||
},
|
||||
} satisfies Meta<typeof PresentationSelector>
|
||||
|
||||
export default meta
|
||||
type Story = StoryObj<typeof meta>
|
||||
|
||||
export const Default: Story = {
|
||||
args: {},
|
||||
}
|
||||
|
||||
export const Clicked: Story = {
|
||||
args: {},
|
||||
play: async ({ canvas, userEvent }) => {
|
||||
await expect(canvas.getByRole('button')).toBeEnabled()
|
||||
|
||||
await userEvent.click(canvas.getByRole('button'))
|
||||
},
|
||||
}
|
||||
|
||||
export const LimitedSet: Story = {
|
||||
args: {
|
||||
modes: ['grid', 'list'],
|
||||
},
|
||||
play: async ({ canvas, userEvent }) => {
|
||||
await expect(canvas.getByRole('button')).toBeEnabled()
|
||||
|
||||
await userEvent.click(canvas.getByRole('button'))
|
||||
},
|
||||
}
|
||||
75
next-ui/src/components/PresentationSelector.vue
Normal file
75
next-ui/src/components/PresentationSelector.vue
Normal file
|
|
@ -0,0 +1,75 @@
|
|||
<template>
|
||||
<v-menu>
|
||||
<template #activator="{ props }">
|
||||
<v-btn
|
||||
v-bind="props"
|
||||
:icon="allModes[currentMode].icon"
|
||||
:aria-label="
|
||||
$formatMessage({
|
||||
description: 'Presentation selector button: aria-label',
|
||||
defaultMessage: 'presentation selector',
|
||||
id: 'sUl0GP',
|
||||
})
|
||||
"
|
||||
/>
|
||||
</template>
|
||||
|
||||
<v-list
|
||||
:selected="[currentMode]"
|
||||
color="primary"
|
||||
>
|
||||
<v-list-item
|
||||
v-for="mode in modes"
|
||||
:key="mode"
|
||||
:title="allModes[mode].title"
|
||||
:value="mode"
|
||||
:prepend-icon="allModes[mode].icon"
|
||||
@click="currentMode = mode"
|
||||
/>
|
||||
</v-list>
|
||||
</v-menu>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { useIntl } from 'vue-intl'
|
||||
import type { PresentationMode } from '@/types/libraries'
|
||||
|
||||
const intl = useIntl()
|
||||
|
||||
const allModes: Record<PresentationMode, { title: string; icon: string }> = {
|
||||
grid: {
|
||||
title: intl.formatMessage({
|
||||
description: 'Presentation mode: grid',
|
||||
defaultMessage: 'Grid',
|
||||
id: 'Hv7lqq',
|
||||
}),
|
||||
icon: 'i-mdi:view-grid',
|
||||
},
|
||||
list: {
|
||||
title: intl.formatMessage({
|
||||
description: 'Presentation mode: list',
|
||||
defaultMessage: 'List',
|
||||
id: 'JNBONk',
|
||||
}),
|
||||
icon: 'i-mdi:view-list',
|
||||
},
|
||||
table: {
|
||||
title: intl.formatMessage({
|
||||
description: 'Presentation mode: table',
|
||||
defaultMessage: 'Table',
|
||||
id: 'efspoY',
|
||||
}),
|
||||
icon: 'i-mdi:table',
|
||||
},
|
||||
}
|
||||
|
||||
const currentMode = defineModel<PresentationMode>({ required: true, default: 'grid' })
|
||||
|
||||
const { modes } = defineProps<{
|
||||
modes: PresentationMode[]
|
||||
}>()
|
||||
</script>
|
||||
|
||||
<script lang="ts"></script>
|
||||
|
||||
<style scoped></style>
|
||||
1
next-ui/src/types/page.ts
Normal file
1
next-ui/src/types/page.ts
Normal file
|
|
@ -0,0 +1 @@
|
|||
export type PageSize = 'unpaged' | number
|
||||
Loading…
Reference in a new issue