mirror of
https://github.com/gotson/komga.git
synced 2026-02-13 10:53:55 +01:00
feat(webui): add UI setting to group series using japanese characters
Closes: #1715
This commit is contained in:
parent
7f55fe152b
commit
6c71e07a27
4 changed files with 150 additions and 8 deletions
|
|
@ -1034,10 +1034,17 @@
|
|||
"more": "More titles"
|
||||
},
|
||||
"ui_settings": {
|
||||
"general": "General",
|
||||
"label_oauth2_auto_login": "Automatic OAuth2 login",
|
||||
"label_oauth2_hide_login": "Hide login fields if OAuth2 is enabled",
|
||||
"label_poster_blur_unread": "Blur poster for unread books and series",
|
||||
"label_poster_stretch": "Stretch poster to fit card",
|
||||
"label_series_groups": "Series grouping",
|
||||
"section_oauth2": "OAuth2",
|
||||
"series_groups": {
|
||||
"alpha": "Alphabetical",
|
||||
"japanese": "Gojūon (Japanese)"
|
||||
},
|
||||
"tooltip_oauth2_auto_login": "Requires a single OAuth2 provider, and 'hide login fields' enabled"
|
||||
},
|
||||
"updates": {
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@ export enum CLIENT_SETTING {
|
|||
WEBUI_POSTER_STRETCH = 'webui.poster.stretch',
|
||||
WEBUI_POSTER_BLUR_UNREAD = 'webui.poster.blur_unread',
|
||||
WEBUI_LIBRARIES = 'webui.libraries',
|
||||
WEBUI_SERIES_GROUPS = 'webui.series_groups',
|
||||
}
|
||||
|
||||
export interface ClientSettingLibrary {
|
||||
|
|
@ -29,3 +30,85 @@ export interface ClientSettingLibraryUpdate {
|
|||
libraryId: string,
|
||||
patch: ClientSettingLibrary,
|
||||
}
|
||||
|
||||
export interface ClientSettingsSeriesGroup {
|
||||
name: string,
|
||||
groups: Record<string, string[]>
|
||||
}
|
||||
|
||||
export const SERIES_GROUP_ALPHA = {
|
||||
name: 'alpha',
|
||||
groups: {
|
||||
'A': ['A'],
|
||||
'B': ['B'],
|
||||
'C': ['C'],
|
||||
'D': ['D'],
|
||||
'E': ['E'],
|
||||
'F': ['F'],
|
||||
'G': ['G'],
|
||||
'H': ['H'],
|
||||
'I': ['I'],
|
||||
'J': ['J'],
|
||||
'K': ['K'],
|
||||
'L': ['L'],
|
||||
'M': ['M'],
|
||||
'N': ['N'],
|
||||
'O': ['O'],
|
||||
'P': ['P'],
|
||||
'Q': ['Q'],
|
||||
'R': ['R'],
|
||||
'S': ['S'],
|
||||
'T': ['T'],
|
||||
'U': ['U'],
|
||||
'V': ['V'],
|
||||
'W': ['W'],
|
||||
'X': ['X'],
|
||||
'Y': ['Y'],
|
||||
'Z': ['Z'],
|
||||
},
|
||||
} as ClientSettingsSeriesGroup
|
||||
|
||||
export const SERIES_GROUP_JAPANESE = {
|
||||
name: 'japanese',
|
||||
groups: {
|
||||
'あ': ['あ', 'ア'],
|
||||
'い': ['い', 'イ'],
|
||||
'う': ['う', 'ゔ', 'ウ', 'ヴ'],
|
||||
'え': ['え', 'エ'],
|
||||
'お': ['お', 'オ'],
|
||||
'か': ['か', 'が', 'カ', 'ガ'],
|
||||
'き': ['き', 'ぎ', 'キ', 'ギ'],
|
||||
'く': ['く', 'ぐ', 'ク', 'グ'],
|
||||
'け': ['け', 'げ', 'ケ', 'ゲ'],
|
||||
'こ': ['こ', 'ご', 'コ', 'ゴ'],
|
||||
'さ': ['さ', 'ざ', 'サ', 'ザ'],
|
||||
'し': ['し', 'じ', 'シ', 'ジ'],
|
||||
'す': ['す', 'ず', 'ス', 'ズ'],
|
||||
'せ': ['せ', 'ぜ', 'セ', 'ゼ'],
|
||||
'そ': ['そ', 'ぞ', 'ソ', 'ゾ'],
|
||||
'た': ['た', 'だ', 'タ', 'ダ'],
|
||||
'ち': ['ち', 'ぢ', 'チ', 'ヂ'],
|
||||
'つ': ['つ', 'づ', 'ツ', 'ズ'],
|
||||
'て': ['て', 'で', 'テ', 'デ'],
|
||||
'と': ['と', 'ど', 'ト', 'ド'],
|
||||
'は': ['は', 'ば', 'ぱ', 'ハ', 'バ', 'パ'],
|
||||
'ひ': ['ひ', 'び', 'ぴ', 'ヒ', 'ビ', 'ピ'],
|
||||
'ふ': ['ふ', 'ぶ', 'ぷ', 'フ', 'ブ', 'プ'],
|
||||
'へ': ['へ', 'べ', 'ぺ', 'ヘ', 'ベ', 'ベ'],
|
||||
'ほ': ['ほ', 'ぼ', 'ぽ', 'ホ', 'ボ', 'ポ'],
|
||||
'ま': ['ま', 'マ'],
|
||||
'み': ['み', 'ミ'],
|
||||
'む': ['む', 'ム'],
|
||||
'め': ['め', 'メ'],
|
||||
'も': ['も', 'モ'],
|
||||
'や': ['や', 'ヤ'],
|
||||
'ゆ': ['ゆ', 'ユ'],
|
||||
'よ': ['よ', 'ヨ'],
|
||||
'ら': ['ら', 'ラ'],
|
||||
'り': ['り', 'リ'],
|
||||
'る': ['る', 'ル'],
|
||||
'れ': ['れ', 'レ'],
|
||||
'ろ': ['ろ', 'ロ'],
|
||||
'わ': ['わ', 'ワ'],
|
||||
},
|
||||
} as ClientSettingsSeriesGroup
|
||||
|
|
|
|||
|
|
@ -74,7 +74,7 @@
|
|||
<v-container fluid>
|
||||
<alphabetical-navigation
|
||||
class="text-center"
|
||||
:symbols="alphabeticalNavigation"
|
||||
:symbols="seriesGroupingKeys"
|
||||
:selected="selectedSymbol"
|
||||
:group-count="seriesGroups"
|
||||
@clicked="filterByStarting"
|
||||
|
|
@ -209,6 +209,7 @@ import {
|
|||
NameValue,
|
||||
} from '@/types/filter'
|
||||
import LibrariesActionsMenu from '@/components/menus/LibrariesActionsMenu.vue'
|
||||
import {CLIENT_SETTING, ClientSettingsSeriesGroup, SERIES_GROUP_ALPHA} from '@/types/komga-clientsettings'
|
||||
|
||||
export default Vue.extend({
|
||||
name: 'BrowseLibraries',
|
||||
|
|
@ -231,7 +232,6 @@ export default Vue.extend({
|
|||
return {
|
||||
series: [] as SeriesDto[],
|
||||
seriesGroups: [] as GroupCountDto[],
|
||||
alphabeticalNavigation: ['ALL', '#', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z'],
|
||||
selectedSymbol: 'ALL',
|
||||
selectedSeries: [] as SeriesDto[],
|
||||
page: 1,
|
||||
|
|
@ -326,6 +326,21 @@ export default Vue.extend({
|
|||
next()
|
||||
},
|
||||
computed: {
|
||||
seriesGrouping(): Record<string, string[]> {
|
||||
let s: Record<string, string[]>
|
||||
try {
|
||||
s = (JSON.parse(this.$store.getters.getClientSettings[CLIENT_SETTING.WEBUI_SERIES_GROUPS].value) as ClientSettingsSeriesGroup).groups
|
||||
} catch (_) {
|
||||
s = SERIES_GROUP_ALPHA.groups
|
||||
}
|
||||
return s
|
||||
},
|
||||
seriesGroupingKeys(): string[] {
|
||||
return ['ALL', '#', ...this.$_.keys(this.seriesGrouping)]
|
||||
},
|
||||
seriesGroupingValues(): string[] {
|
||||
return this.$_(this.seriesGrouping).values().flatten().map(this.$_.lowerCase).toArray() as unknown as string[]
|
||||
},
|
||||
library(): LibraryDto | undefined {
|
||||
return this.getLibraryLazy(this.libraryId)
|
||||
},
|
||||
|
|
@ -337,11 +352,13 @@ export default Vue.extend({
|
|||
symbolCondition(): SearchConditionSeries | undefined {
|
||||
if (this.selectedSymbol === 'ALL') return undefined
|
||||
if (this.selectedSymbol === '#') return new SearchConditionAllOfSeries(
|
||||
this.alphabeticalNavigation
|
||||
.filter(it => it !== 'ALL' && it !== '#')
|
||||
this.seriesGroupingValues
|
||||
.map(it => new SearchConditionTitleSort(new SearchOperatorDoesNotBeginWith(it))),
|
||||
)
|
||||
return new SearchConditionTitleSort(new SearchOperatorBeginsWith(this.selectedSymbol))
|
||||
return new SearchConditionAnyOfSeries(
|
||||
this.seriesGrouping[this.selectedSymbol]
|
||||
.map(it => new SearchConditionTitleSort(new SearchOperatorBeginsWith(it))),
|
||||
)
|
||||
},
|
||||
itemContext(): ItemContext[] {
|
||||
if (this.sortActive.key === 'booksMetadata.releaseDate') return [ItemContext.RELEASE_DATE]
|
||||
|
|
@ -737,11 +754,11 @@ export default Vue.extend({
|
|||
condition: new SearchConditionAllOfSeries(groupConditions),
|
||||
} as SeriesSearch)
|
||||
const nonAlpha = seriesGroups
|
||||
.filter((g) => !(/[a-zA-Z]/).test(g.group))
|
||||
.filter((g) => !this.seriesGroupingValues.includes(g.group))
|
||||
.reduce((a, b) => a + b.count, 0)
|
||||
const all = seriesGroups.reduce((a, b) => a + b.count, 0)
|
||||
this.seriesGroups = [
|
||||
...seriesGroups.filter((g) => (/[a-zA-Z]/).test(g.group)),
|
||||
...seriesGroups.filter((g) => this.seriesGroupingValues.includes(g.group)),
|
||||
{group: '#', count: nonAlpha} as GroupCountDto,
|
||||
{group: 'ALL', count: all} as GroupCountDto,
|
||||
]
|
||||
|
|
|
|||
|
|
@ -2,6 +2,23 @@
|
|||
<v-container fluid class="pa-6">
|
||||
<v-row>
|
||||
<v-col cols="auto">
|
||||
<span class="font-weight-black text-h6">{{ $t('ui_settings.general') }}</span>
|
||||
|
||||
<v-radio-group
|
||||
v-model="form.seriesGroups"
|
||||
@change="$v.form.seriesGroups.$touch()"
|
||||
:label="$t('ui_settings.label_series_groups')"
|
||||
hide-details
|
||||
>
|
||||
<v-radio value="alpha" :label="$t('ui_settings.series_groups.alpha')"/>
|
||||
<v-radio value="japanese" :label="$t('ui_settings.series_groups.japanese')"/>
|
||||
</v-radio-group>
|
||||
</v-col>
|
||||
</v-row>
|
||||
<v-row>
|
||||
<v-col cols="auto">
|
||||
<span class="font-weight-black text-h6">{{ $t('ui_settings.section_oauth2') }}</span>
|
||||
|
||||
<v-checkbox
|
||||
v-model="form.oauth2HideLogin"
|
||||
@change="$v.form.oauth2HideLogin.$touch()"
|
||||
|
|
@ -48,7 +65,13 @@
|
|||
|
||||
<script lang="ts">
|
||||
import Vue from 'vue'
|
||||
import {CLIENT_SETTING, ClientSettingGlobalUpdateDto} from '@/types/komga-clientsettings'
|
||||
import {
|
||||
CLIENT_SETTING,
|
||||
ClientSettingGlobalUpdateDto,
|
||||
ClientSettingsSeriesGroup,
|
||||
SERIES_GROUP_ALPHA,
|
||||
SERIES_GROUP_JAPANESE,
|
||||
} from '@/types/komga-clientsettings'
|
||||
|
||||
export default Vue.extend({
|
||||
name: 'UISettings',
|
||||
|
|
@ -56,12 +79,14 @@ export default Vue.extend({
|
|||
form: {
|
||||
oauth2HideLogin: false,
|
||||
oauth2AutoLogin: false,
|
||||
seriesGroups: 'alpha',
|
||||
},
|
||||
}),
|
||||
validations: {
|
||||
form: {
|
||||
oauth2HideLogin: {},
|
||||
oauth2AutoLogin: {},
|
||||
seriesGroups: {},
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
|
|
@ -80,6 +105,10 @@ export default Vue.extend({
|
|||
await this.$store.dispatch('getClientSettingsGlobal')
|
||||
this.form.oauth2HideLogin = this.$store.state.komgaSettings.clientSettingsGlobal[CLIENT_SETTING.WEBUI_OAUTH2_HIDE_LOGIN]?.value === 'true'
|
||||
this.form.oauth2AutoLogin = this.$store.state.komgaSettings.clientSettingsGlobal[CLIENT_SETTING.WEBUI_OAUTH2_AUTO_LOGIN]?.value === 'true'
|
||||
try {
|
||||
this.form.seriesGroups = (JSON.parse(this.$store.state.komgaSettings.clientSettingsGlobal[CLIENT_SETTING.WEBUI_SERIES_GROUPS]?.value) as ClientSettingsSeriesGroup)?.name
|
||||
} catch (_) {
|
||||
}
|
||||
this.$v.form.$reset()
|
||||
},
|
||||
async saveSettings() {
|
||||
|
|
@ -96,6 +125,12 @@ export default Vue.extend({
|
|||
allowUnauthorized: true,
|
||||
}
|
||||
|
||||
if (this.$v.form?.seriesGroups?.$dirty)
|
||||
newSettings[CLIENT_SETTING.WEBUI_SERIES_GROUPS] = {
|
||||
value: JSON.stringify(this.form.seriesGroups === 'alpha' ? SERIES_GROUP_ALPHA : SERIES_GROUP_JAPANESE),
|
||||
allowUnauthorized: false,
|
||||
}
|
||||
|
||||
await this.$komgaSettings.updateClientSettingGlobal(newSettings)
|
||||
|
||||
await this.refreshSettings()
|
||||
|
|
|
|||
Loading…
Reference in a new issue