|
@@ -4,8 +4,8 @@ q-page.admin-general
|
|
|
.col-auto
|
|
|
img.admin-icon.animated.fadeInLeft(src='/_assets/icons/fluent-web.svg')
|
|
|
.col.q-pl-md
|
|
|
- .text-h5.text-primary.animated.fadeInLeft {{ $t('admin.general.title') }}
|
|
|
- .text-subtitle1.text-grey.animated.fadeInLeft.wait-p2s {{ $t('admin.general.subtitle') }}
|
|
|
+ .text-h5.text-primary.animated.fadeInLeft {{ t('admin.general.title') }}
|
|
|
+ .text-subtitle1.text-grey.animated.fadeInLeft.wait-p2s {{ t('admin.general.subtitle') }}
|
|
|
.col-auto
|
|
|
q-btn.q-mr-sm.acrylic-btn(
|
|
|
icon='las la-question-circle'
|
|
@@ -16,19 +16,19 @@ q-page.admin-general
|
|
|
type='a'
|
|
|
)
|
|
|
q-btn.q-mr-sm.acrylic-btn(
|
|
|
- icon='las la-redo-alt'
|
|
|
+ icon='fa-solid fa-rotate'
|
|
|
flat
|
|
|
color='secondary'
|
|
|
- :loading='loading > 0'
|
|
|
+ :loading='state.loading > 0'
|
|
|
@click='load'
|
|
|
)
|
|
|
q-btn(
|
|
|
unelevated
|
|
|
- icon='mdi-check'
|
|
|
- :label='$t(`common.actions.apply`)'
|
|
|
+ icon='fa-solid fa-check'
|
|
|
+ :label='t(`common.actions.apply`)'
|
|
|
color='secondary'
|
|
|
@click='save'
|
|
|
- :disabled='loading > 0'
|
|
|
+ :disabled='state.loading > 0'
|
|
|
)
|
|
|
q-separator(inset)
|
|
|
.row.q-pa-md.q-col-gutter-md
|
|
@@ -38,52 +38,48 @@ q-page.admin-general
|
|
|
//- -----------------------
|
|
|
q-card.shadow-1.q-pb-sm
|
|
|
q-card-section
|
|
|
- .text-subtitle1 {{$t('admin.general.siteInfo')}}
|
|
|
+ .text-subtitle1 {{t('admin.general.siteInfo')}}
|
|
|
q-item
|
|
|
blueprint-icon(icon='home')
|
|
|
q-item-section
|
|
|
- q-item-label {{$t(`admin.general.siteTitle`)}}
|
|
|
- q-item-label(caption) {{$t(`admin.general.siteTitleHint`)}}
|
|
|
+ q-item-label {{t(`admin.general.siteTitle`)}}
|
|
|
+ q-item-label(caption) {{t(`admin.general.siteTitleHint`)}}
|
|
|
q-item-section
|
|
|
q-input(
|
|
|
outlined
|
|
|
- v-model='config.title'
|
|
|
+ v-model='state.config.title'
|
|
|
dense
|
|
|
- :rules=`[
|
|
|
- val => /^[^<>"]+$/.test(val) || $t('admin.general.siteTitleInvalidChars')
|
|
|
- ]`
|
|
|
+ :rules='rulesTitle'
|
|
|
hide-bottom-space
|
|
|
- :aria-label='$t(`admin.general.siteTitle`)'
|
|
|
+ :aria-label='t(`admin.general.siteTitle`)'
|
|
|
)
|
|
|
q-separator.q-my-sm(inset)
|
|
|
q-item
|
|
|
blueprint-icon(icon='select-all')
|
|
|
q-item-section
|
|
|
- q-item-label {{$t(`admin.general.siteDescription`)}}
|
|
|
- q-item-label(caption) {{$t(`admin.general.siteDescriptionHint`)}}
|
|
|
+ q-item-label {{t(`admin.general.siteDescription`)}}
|
|
|
+ q-item-label(caption) {{t(`admin.general.siteDescriptionHint`)}}
|
|
|
q-item-section
|
|
|
q-input(
|
|
|
outlined
|
|
|
- v-model='config.description'
|
|
|
+ v-model='state.config.description'
|
|
|
dense
|
|
|
- :aria-label='$t(`admin.general.siteDescription`)'
|
|
|
+ :aria-label='t(`admin.general.siteDescription`)'
|
|
|
)
|
|
|
q-separator.q-my-sm(inset)
|
|
|
q-item
|
|
|
blueprint-icon(icon='dns')
|
|
|
q-item-section
|
|
|
- q-item-label {{$t(`admin.general.siteHostname`)}}
|
|
|
- q-item-label(caption) {{$t(`admin.general.siteHostnameHint`)}}
|
|
|
+ q-item-label {{t(`admin.general.siteHostname`)}}
|
|
|
+ q-item-label(caption) {{t(`admin.general.siteHostnameHint`)}}
|
|
|
q-item-section
|
|
|
q-input(
|
|
|
outlined
|
|
|
- v-model='config.hostname'
|
|
|
+ v-model='state.config.hostname'
|
|
|
dense
|
|
|
- :rules=`[
|
|
|
- val => /^(([a-z0-9.-]+)|([*]{1}))$/.test(val) || $t('admin.general.siteHostnameInvalid')
|
|
|
- ]`
|
|
|
+ :rules='rulesHostname'
|
|
|
hide-bottom-space
|
|
|
- :aria-label='$t(`admin.general.siteHostname`)'
|
|
|
+ :aria-label='t(`admin.general.siteHostname`)'
|
|
|
)
|
|
|
|
|
|
//- -----------------------
|
|
@@ -91,36 +87,36 @@ q-page.admin-general
|
|
|
//- -----------------------
|
|
|
q-card.shadow-1.q-pb-sm.q-mt-md
|
|
|
q-card-section
|
|
|
- .text-subtitle1 {{$t('admin.general.footerCopyright')}}
|
|
|
+ .text-subtitle1 {{t('admin.general.footerCopyright')}}
|
|
|
q-item
|
|
|
blueprint-icon(icon='building')
|
|
|
q-item-section
|
|
|
- q-item-label {{$t(`admin.general.companyName`)}}
|
|
|
- q-item-label(caption) {{$t(`admin.general.companyNameHint`)}}
|
|
|
+ q-item-label {{t(`admin.general.companyName`)}}
|
|
|
+ q-item-label(caption) {{t(`admin.general.companyNameHint`)}}
|
|
|
q-item-section
|
|
|
q-input(
|
|
|
outlined
|
|
|
- v-model='config.company'
|
|
|
+ v-model='state.config.company'
|
|
|
dense
|
|
|
- :aria-label='$t(`admin.general.companyName`)'
|
|
|
+ :aria-label='t(`admin.general.companyName`)'
|
|
|
)
|
|
|
q-separator.q-my-sm(inset)
|
|
|
q-item
|
|
|
blueprint-icon(icon='copyright')
|
|
|
q-item-section
|
|
|
- q-item-label {{$t(`admin.general.contentLicense`)}}
|
|
|
- q-item-label(caption) {{$t(`admin.general.contentLicenseHint`)}}
|
|
|
+ q-item-label {{t(`admin.general.contentLicense`)}}
|
|
|
+ q-item-label(caption) {{t(`admin.general.contentLicenseHint`)}}
|
|
|
q-item-section
|
|
|
q-select(
|
|
|
outlined
|
|
|
- v-model='config.contentLicense'
|
|
|
+ v-model='state.config.contentLicense'
|
|
|
:options='contentLicenses'
|
|
|
option-value='value'
|
|
|
option-label='text'
|
|
|
emit-value
|
|
|
map-options
|
|
|
dense
|
|
|
- :aria-label='$t(`admin.general.contentLicense`)'
|
|
|
+ :aria-label='t(`admin.general.contentLicense`)'
|
|
|
)
|
|
|
|
|
|
//- -----------------------
|
|
@@ -128,80 +124,76 @@ q-page.admin-general
|
|
|
//- -----------------------
|
|
|
q-card.shadow-1.q-pb-sm.q-mt-md
|
|
|
q-card-section
|
|
|
- .text-subtitle1 {{$t('admin.general.features')}}
|
|
|
+ .text-subtitle1 {{t('admin.general.features')}}
|
|
|
q-item(tag='label')
|
|
|
blueprint-icon(icon='discussion-forum')
|
|
|
q-item-section
|
|
|
- q-item-label {{$t(`admin.general.allowComments`)}}
|
|
|
- q-item-label(caption) {{$t(`admin.general.allowCommentsHint`)}}
|
|
|
+ q-item-label {{t(`admin.general.allowComments`)}}
|
|
|
+ q-item-label(caption) {{t(`admin.general.allowCommentsHint`)}}
|
|
|
q-item-section(avatar)
|
|
|
q-toggle(
|
|
|
- v-model='config.features.comments'
|
|
|
+ v-model='state.config.features.comments'
|
|
|
color='primary'
|
|
|
checked-icon='las la-check'
|
|
|
unchecked-icon='las la-times'
|
|
|
- :aria-label='$t(`admin.general.allowComments`)'
|
|
|
+ :aria-label='t(`admin.general.allowComments`)'
|
|
|
)
|
|
|
q-separator.q-my-sm(inset)
|
|
|
q-item(tag='label')
|
|
|
blueprint-icon(icon='pen')
|
|
|
q-item-section
|
|
|
- q-item-label {{$t(`admin.general.allowContributions`)}}
|
|
|
- q-item-label(caption) {{$t(`admin.general.allowContributionsHint`)}}
|
|
|
+ q-item-label {{t(`admin.general.allowContributions`)}}
|
|
|
+ q-item-label(caption) {{t(`admin.general.allowContributionsHint`)}}
|
|
|
q-item-section(avatar)
|
|
|
q-toggle(
|
|
|
- v-model='config.features.contributions'
|
|
|
+ v-model='state.config.features.contributions'
|
|
|
color='primary'
|
|
|
checked-icon='las la-check'
|
|
|
unchecked-icon='las la-times'
|
|
|
- :aria-label='$t(`admin.general.allowContributions`)'
|
|
|
+ :aria-label='t(`admin.general.allowContributions`)'
|
|
|
)
|
|
|
q-separator.q-my-sm(inset)
|
|
|
q-item(tag='label')
|
|
|
blueprint-icon(icon='administrator-male')
|
|
|
q-item-section
|
|
|
- q-item-label {{$t(`admin.general.allowProfile`)}}
|
|
|
- q-item-label(caption) {{$t(`admin.general.allowProfileHint`)}}
|
|
|
+ q-item-label {{t(`admin.general.allowProfile`)}}
|
|
|
+ q-item-label(caption) {{t(`admin.general.allowProfileHint`)}}
|
|
|
q-item-section(avatar)
|
|
|
q-toggle(
|
|
|
- v-model='config.features.profile'
|
|
|
+ v-model='state.config.features.profile'
|
|
|
color='primary'
|
|
|
checked-icon='las la-check'
|
|
|
unchecked-icon='las la-times'
|
|
|
- :aria-label='$t(`admin.general.allowProfile`)'
|
|
|
+ :aria-label='t(`admin.general.allowProfile`)'
|
|
|
)
|
|
|
q-separator.q-my-sm(inset)
|
|
|
q-item
|
|
|
blueprint-icon(icon='star-half-empty')
|
|
|
q-item-section
|
|
|
- q-item-label {{$t(`admin.general.allowRatings`)}}
|
|
|
- q-item-label(caption) {{$t(`admin.general.allowRatingsHint`)}}
|
|
|
+ q-item-label {{t(`admin.general.allowRatings`)}}
|
|
|
+ q-item-label(caption) {{t(`admin.general.allowRatingsHint`)}}
|
|
|
q-item-section.col-auto
|
|
|
q-btn-toggle(
|
|
|
- v-model='config.features.ratingsMode'
|
|
|
+ v-model='state.config.features.ratingsMode'
|
|
|
push
|
|
|
glossy
|
|
|
no-caps
|
|
|
toggle-color='primary'
|
|
|
- :options=`[
|
|
|
- { label: $t('admin.general.ratingsOff'), value: 'off' },
|
|
|
- { label: $t('admin.general.ratingsThumbs'), value: 'thumbs' },
|
|
|
- { label: $t('admin.general.ratingsStars'), value: 'stars' }
|
|
|
- ]`
|
|
|
+ :options='ratingsModes'
|
|
|
)
|
|
|
q-separator.q-my-sm(inset)
|
|
|
q-item(tag='label')
|
|
|
blueprint-icon(icon='search')
|
|
|
q-item-section
|
|
|
- q-item-label {{$t(`admin.general.allowSearch`)}}
|
|
|
- q-item-label(caption) {{$t(`admin.general.allowSearchHint`)}}
|
|
|
+ q-item-label {{t(`admin.general.allowSearch`)}}
|
|
|
+ q-item-label(caption) {{t(`admin.general.allowSearchHint`)}}
|
|
|
q-item-section(avatar)
|
|
|
q-toggle(
|
|
|
- v-model='config.features.search'
|
|
|
+ v-model='state.config.features.search'
|
|
|
color='primary'
|
|
|
checked-icon='las la-check'
|
|
|
unchecked-icon='las la-times'
|
|
|
- :aria-label='$t(`admin.general.allowSearch`)'
|
|
|
+ :aria-label='t(`admin.general.allowSearch`)'
|
|
|
)
|
|
|
|
|
|
.col-12.col-lg-5
|
|
@@ -210,14 +202,14 @@ q-page.admin-general
|
|
|
//- -----------------------
|
|
|
q-card.shadow-1.q-pb-sm
|
|
|
q-card-section
|
|
|
- .text-subtitle1 {{$t('admin.general.logo')}}
|
|
|
+ .text-subtitle1 {{t('admin.general.logo')}}
|
|
|
q-item
|
|
|
- blueprint-icon.self-start(icon='butterfly', indicator, :indicator-text='$t(`admin.extensions.requiresSharp`)')
|
|
|
+ blueprint-icon.self-start(icon='butterfly', indicator, :indicator-text='t(`admin.extensions.requiresSharp`)')
|
|
|
q-item-section
|
|
|
.flex
|
|
|
q-item-section
|
|
|
- q-item-label {{$t(`admin.general.logoUpl`)}}
|
|
|
- q-item-label(caption) {{$t(`admin.general.logoUplHint`)}}
|
|
|
+ q-item-label {{t(`admin.general.logoUpl`)}}
|
|
|
+ q-item-label(caption) {{t(`admin.general.logoUplHint`)}}
|
|
|
q-item-section.col-auto
|
|
|
q-btn(
|
|
|
label='Upload'
|
|
@@ -233,7 +225,7 @@ q-page.admin-general
|
|
|
)
|
|
|
q-btn(dense, flat, to='/')
|
|
|
q-avatar(
|
|
|
- v-if='config.logoText'
|
|
|
+ v-if='state.config.logoText'
|
|
|
size='34px'
|
|
|
square
|
|
|
)
|
|
@@ -243,29 +235,29 @@ q-page.admin-general
|
|
|
src='https://m.media-amazon.com/images/G/01/audibleweb/arya/navigation/audible_logo._V517446980_.svg'
|
|
|
style='height: 34px;'
|
|
|
)
|
|
|
- q-toolbar-title.text-h6.font-poppins(v-if='config.logoText') {{config.title}}
|
|
|
+ q-toolbar-title.text-h6.font-poppins(v-if='state.config.logoText') {{state.config.title}}
|
|
|
q-separator.q-my-sm(inset)
|
|
|
q-item(tag='label')
|
|
|
blueprint-icon(icon='information')
|
|
|
q-item-section
|
|
|
- q-item-label {{$t(`admin.general.displaySiteTitle`)}}
|
|
|
- q-item-label(caption) {{$t(`admin.general.displaySiteTitleHint`)}}
|
|
|
+ q-item-label {{t(`admin.general.displaySiteTitle`)}}
|
|
|
+ q-item-label(caption) {{t(`admin.general.displaySiteTitleHint`)}}
|
|
|
q-item-section(avatar)
|
|
|
q-toggle(
|
|
|
- v-model='config.logoText'
|
|
|
+ v-model='state.config.logoText'
|
|
|
color='primary'
|
|
|
checked-icon='las la-check'
|
|
|
unchecked-icon='las la-times'
|
|
|
- :aria-label='$t(`admin.general.displaySiteTitle`)'
|
|
|
+ :aria-label='t(`admin.general.displaySiteTitle`)'
|
|
|
)
|
|
|
q-separator.q-my-sm(inset)
|
|
|
q-item
|
|
|
- blueprint-icon.self-start(icon='starfish', indicator, :indicator-text='$t(`admin.extensions.requiresSharp`)')
|
|
|
+ blueprint-icon.self-start(icon='starfish', indicator, :indicator-text='t(`admin.extensions.requiresSharp`)')
|
|
|
q-item-section
|
|
|
.flex
|
|
|
q-item-section
|
|
|
- q-item-label {{$t(`admin.general.favicon`)}}
|
|
|
- q-item-label(caption) {{$t(`admin.general.faviconHint`)}}
|
|
|
+ q-item-label {{t(`admin.general.favicon`)}}
|
|
|
+ q-item-label(caption) {{t(`admin.general.faviconHint`)}}
|
|
|
q-item-section.col-auto
|
|
|
q-btn(
|
|
|
label='Upload'
|
|
@@ -282,7 +274,7 @@ q-page.admin-general
|
|
|
square
|
|
|
)
|
|
|
img(src='/_assets/logo-wikijs.svg')
|
|
|
- .text-caption.q-ml-sm {{config.title}}
|
|
|
+ .text-caption.q-ml-sm {{state.config.title}}
|
|
|
div
|
|
|
q-icon(name='las la-otter', size='24px', color='grey')
|
|
|
.text-caption.q-ml-sm Lorem ipsum
|
|
@@ -293,19 +285,19 @@ q-page.admin-general
|
|
|
//- -----------------------
|
|
|
//- Defaults
|
|
|
//- -----------------------
|
|
|
- q-card.shadow-1.q-pb-sm.q-mt-md(v-if='config.defaults')
|
|
|
+ q-card.shadow-1.q-pb-sm.q-mt-md(v-if='state.config.defaults')
|
|
|
q-card-section
|
|
|
- .text-subtitle1 {{$t('admin.general.defaults')}}
|
|
|
+ .text-subtitle1 {{t('admin.general.defaults')}}
|
|
|
q-item
|
|
|
blueprint-icon(icon='timezone')
|
|
|
q-item-section
|
|
|
- q-item-label {{$t(`admin.general.defaultTimezone`)}}
|
|
|
- q-item-label(caption) {{$t(`admin.general.defaultTimezoneHint`)}}
|
|
|
+ q-item-label {{t(`admin.general.defaultTimezone`)}}
|
|
|
+ q-item-label(caption) {{t(`admin.general.defaultTimezoneHint`)}}
|
|
|
q-item-section
|
|
|
q-select(
|
|
|
outlined
|
|
|
- v-model='config.defaults.timezone'
|
|
|
- :options='timezones'
|
|
|
+ v-model='state.config.defaults.timezone'
|
|
|
+ :options='dataStore.timezones'
|
|
|
option-value='value'
|
|
|
option-label='text'
|
|
|
emit-value
|
|
@@ -313,372 +305,410 @@ q-page.admin-general
|
|
|
dense
|
|
|
options-dense
|
|
|
:virtual-scroll-slice-size='1000'
|
|
|
- :aria-label='$t(`admin.general.defaultTimezone`)'
|
|
|
+ :aria-label='t(`admin.general.defaultTimezone`)'
|
|
|
)
|
|
|
q-separator.q-my-sm(inset)
|
|
|
q-item
|
|
|
blueprint-icon(icon='calendar')
|
|
|
q-item-section
|
|
|
- q-item-label {{$t(`admin.general.defaultDateFormat`)}}
|
|
|
- q-item-label(caption) {{$t(`admin.general.defaultDateFormatHint`)}}
|
|
|
+ q-item-label {{t(`admin.general.defaultDateFormat`)}}
|
|
|
+ q-item-label(caption) {{t(`admin.general.defaultDateFormatHint`)}}
|
|
|
q-item-section
|
|
|
q-select(
|
|
|
outlined
|
|
|
- v-model='config.defaults.dateFormat'
|
|
|
+ v-model='state.config.defaults.dateFormat'
|
|
|
emit-value
|
|
|
map-options
|
|
|
dense
|
|
|
- :aria-label='$t(`admin.general.defaultDateFormat`)'
|
|
|
- :options=`[
|
|
|
- { label: $t('profile.localeDefault'), value: '' },
|
|
|
- { label: 'DD/MM/YYYY', value: 'DD/MM/YYYY' },
|
|
|
- { label: 'DD.MM.YYYY', value: 'DD.MM.YYYY' },
|
|
|
- { label: 'MM/DD/YYYY', value: 'MM/DD/YYYY' },
|
|
|
- { label: 'YYYY-MM-DD', value: 'YYYY-MM-DD' },
|
|
|
- { label: 'YYYY/MM/DD', value: 'YYYY/MM/DD' }
|
|
|
- ]`
|
|
|
+ :aria-label='t(`admin.general.defaultDateFormat`)'
|
|
|
+ :options='dateFormats'
|
|
|
)
|
|
|
q-separator.q-my-sm(inset)
|
|
|
q-item
|
|
|
blueprint-icon(icon='clock')
|
|
|
q-item-section
|
|
|
- q-item-label {{$t(`admin.general.defaultTimeFormat`)}}
|
|
|
- q-item-label(caption) {{$t(`admin.general.defaultTimeFormatHint`)}}
|
|
|
+ q-item-label {{t(`admin.general.defaultTimeFormat`)}}
|
|
|
+ q-item-label(caption) {{t(`admin.general.defaultTimeFormatHint`)}}
|
|
|
q-item-section.col-auto
|
|
|
q-btn-toggle(
|
|
|
- v-model='config.defaults.timeFormat'
|
|
|
+ v-model='state.config.defaults.timeFormat'
|
|
|
push
|
|
|
glossy
|
|
|
no-caps
|
|
|
toggle-color='primary'
|
|
|
- :options=`[
|
|
|
- { label: $t('admin.general.defaultTimeFormat12h'), value: '12h' },
|
|
|
- { label: $t('admin.general.defaultTimeFormat24h'), value: '24h' }
|
|
|
- ]`
|
|
|
+ :options='timeFormats'
|
|
|
)
|
|
|
|
|
|
//- -----------------------
|
|
|
//- SEO
|
|
|
//- -----------------------
|
|
|
- q-card.shadow-1.q-pb-sm.q-mt-md(v-if='config.robots')
|
|
|
+ q-card.shadow-1.q-pb-sm.q-mt-md(v-if='state.config.robots')
|
|
|
q-card-section
|
|
|
.text-subtitle1 SEO
|
|
|
q-item(tag='label')
|
|
|
blueprint-icon(icon='bot')
|
|
|
q-item-section
|
|
|
- q-item-label {{$t(`admin.general.searchAllowIndexing`)}}
|
|
|
- q-item-label(caption) {{$t(`admin.general.searchAllowIndexingHint`)}}
|
|
|
+ q-item-label {{t(`admin.general.searchAllowIndexing`)}}
|
|
|
+ q-item-label(caption) {{t(`admin.general.searchAllowIndexingHint`)}}
|
|
|
q-item-section(avatar)
|
|
|
q-toggle(
|
|
|
- v-model='config.robots.index'
|
|
|
+ v-model='state.config.robots.index'
|
|
|
color='primary'
|
|
|
checked-icon='las la-check'
|
|
|
unchecked-icon='las la-times'
|
|
|
- :aria-label='$t(`admin.general.searchAllowIndexing`)'
|
|
|
+ :aria-label='t(`admin.general.searchAllowIndexing`)'
|
|
|
)
|
|
|
q-separator.q-my-sm(inset)
|
|
|
q-item(tag='label')
|
|
|
blueprint-icon(icon='polyline')
|
|
|
q-item-section
|
|
|
- q-item-label {{$t(`admin.general.searchAllowFollow`)}}
|
|
|
- q-item-label(caption) {{$t(`admin.general.searchAllowFollowHint`)}}
|
|
|
+ q-item-label {{t(`admin.general.searchAllowFollow`)}}
|
|
|
+ q-item-label(caption) {{t(`admin.general.searchAllowFollowHint`)}}
|
|
|
q-item-section(avatar)
|
|
|
q-toggle(
|
|
|
- v-model='config.robots.follow'
|
|
|
+ v-model='state.config.robots.follow'
|
|
|
color='primary'
|
|
|
checked-icon='las la-check'
|
|
|
unchecked-icon='las la-times'
|
|
|
- :aria-label='$t(`admin.general.searchAllowFollow`)'
|
|
|
+ :aria-label='t(`admin.general.searchAllowFollow`)'
|
|
|
)
|
|
|
|
|
|
</template>
|
|
|
|
|
|
-<script>
|
|
|
-import { get } from 'vuex-pathify'
|
|
|
+<script setup>
|
|
|
import gql from 'graphql-tag'
|
|
|
import cloneDeep from 'lodash/cloneDeep'
|
|
|
-import { createMetaMixin } from 'quasar'
|
|
|
+import { useI18n } from 'vue-i18n'
|
|
|
+import { useMeta, useQuasar } from 'quasar'
|
|
|
+import { onMounted, reactive, watch } from 'vue'
|
|
|
|
|
|
-export default {
|
|
|
- mixins: [
|
|
|
- createMetaMixin(function () {
|
|
|
- return {
|
|
|
- title: this.$t('admin.general.title')
|
|
|
- }
|
|
|
- })
|
|
|
- ],
|
|
|
- data () {
|
|
|
- return {
|
|
|
- loading: 0,
|
|
|
- config: {
|
|
|
- hostname: '',
|
|
|
- title: '',
|
|
|
- description: '',
|
|
|
- company: '',
|
|
|
- contentLicense: '',
|
|
|
- logoText: false,
|
|
|
- ratings: {
|
|
|
- index: false,
|
|
|
- follow: false
|
|
|
- },
|
|
|
- features: {
|
|
|
- ratings: false,
|
|
|
- ratingsMode: 'off',
|
|
|
- comments: false,
|
|
|
- contributions: false,
|
|
|
- profile: false
|
|
|
- },
|
|
|
- defaults: {
|
|
|
- timezone: '',
|
|
|
- dateFormat: '',
|
|
|
- timeFormat: ''
|
|
|
+import { useAdminStore } from 'src/stores/admin'
|
|
|
+import { useSiteStore } from 'src/stores/site'
|
|
|
+import { useDataStore } from 'src/stores/data'
|
|
|
+import { useRoute, useRouter } from 'vue-router'
|
|
|
+
|
|
|
+// QUASAR
|
|
|
+
|
|
|
+const $q = useQuasar()
|
|
|
+
|
|
|
+// STORES
|
|
|
+
|
|
|
+const adminStore = useAdminStore()
|
|
|
+const siteStore = useSiteStore()
|
|
|
+const dataStore = useDataStore()
|
|
|
+
|
|
|
+// ROUTER
|
|
|
+
|
|
|
+const router = useRouter()
|
|
|
+const route = useRoute()
|
|
|
+
|
|
|
+// I18N
|
|
|
+
|
|
|
+const { t } = useI18n()
|
|
|
+
|
|
|
+// META
|
|
|
+
|
|
|
+useMeta({
|
|
|
+ title: t('admin.dashboard.title')
|
|
|
+})
|
|
|
+
|
|
|
+// DATA
|
|
|
+
|
|
|
+const state = reactive({
|
|
|
+ loading: 0,
|
|
|
+ config: {
|
|
|
+ hostname: '',
|
|
|
+ title: '',
|
|
|
+ description: '',
|
|
|
+ company: '',
|
|
|
+ contentLicense: '',
|
|
|
+ logoText: false,
|
|
|
+ ratings: {
|
|
|
+ index: false,
|
|
|
+ follow: false
|
|
|
+ },
|
|
|
+ features: {
|
|
|
+ ratings: false,
|
|
|
+ ratingsMode: 'off',
|
|
|
+ comments: false,
|
|
|
+ contributions: false,
|
|
|
+ profile: false
|
|
|
+ },
|
|
|
+ defaults: {
|
|
|
+ timezone: '',
|
|
|
+ dateFormat: '',
|
|
|
+ timeFormat: ''
|
|
|
+ }
|
|
|
+ }
|
|
|
+})
|
|
|
+
|
|
|
+const contentLicenses = [
|
|
|
+ { value: '', text: t('common.license.none') },
|
|
|
+ { value: 'alr', text: t('common.license.alr') },
|
|
|
+ { value: 'cc0', text: t('common.license.cc0') },
|
|
|
+ { value: 'ccby', text: t('common.license.ccby') },
|
|
|
+ { value: 'ccbysa', text: t('common.license.ccbysa') },
|
|
|
+ { value: 'ccbynd', text: t('common.license.ccbynd') },
|
|
|
+ { value: 'ccbync', text: t('common.license.ccbync') },
|
|
|
+ { value: 'ccbyncsa', text: t('common.license.ccbyncsa') },
|
|
|
+ { value: 'ccbyncnd', text: t('common.license.ccbyncnd') }
|
|
|
+]
|
|
|
+const ratingsModes = [
|
|
|
+ { value: 'off', label: t('admin.general.ratingsOff') },
|
|
|
+ { value: 'thumbs', label: t('admin.general.ratingsThumbs') },
|
|
|
+ { value: 'stars', label: t('admin.general.ratingsStars') }
|
|
|
+]
|
|
|
+const dateFormats = [
|
|
|
+ { value: '', label: t('profile.localeDefault') },
|
|
|
+ { value: 'DD/MM/YYYY', label: 'DD/MM/YYYY' },
|
|
|
+ { value: 'DD.MM.YYYY', label: 'DD.MM.YYYY' },
|
|
|
+ { value: 'MM/DD/YYYY', label: 'MM/DD/YYYY' },
|
|
|
+ { value: 'YYYY-MM-DD', label: 'YYYY-MM-DD' },
|
|
|
+ { value: 'YYYY/MM/DD', label: 'YYYY/MM/DD' }
|
|
|
+]
|
|
|
+const timeFormats = [
|
|
|
+ { value: '12h', label: t('admin.general.defaultTimeFormat12h') },
|
|
|
+ { value: '24h', label: t('admin.general.defaultTimeFormat24h') }
|
|
|
+]
|
|
|
+
|
|
|
+const rulesTitle = [
|
|
|
+ val => /^[^<>"]+$/.test(val) || t('admin.general.siteTitleInvalidChars')
|
|
|
+]
|
|
|
+const rulesHostname = [
|
|
|
+ val => /^(([a-z0-9.-]+)|([*]{1}))$/.test(val) || t('admin.general.siteHostnameInvalid')
|
|
|
+]
|
|
|
+
|
|
|
+// WATCHERS
|
|
|
+
|
|
|
+watch(() => adminStore.currentSiteId, (newValue) => {
|
|
|
+ load()
|
|
|
+})
|
|
|
+
|
|
|
+// METHODS
|
|
|
+
|
|
|
+async function load () {
|
|
|
+ state.loading++
|
|
|
+ $q.loading.show()
|
|
|
+ const resp = await APOLLO_CLIENT.query({
|
|
|
+ query: gql`
|
|
|
+ query getSite (
|
|
|
+ $id: UUID!
|
|
|
+ ) {
|
|
|
+ siteById(
|
|
|
+ id: $id
|
|
|
+ ) {
|
|
|
+ id
|
|
|
+ hostname
|
|
|
+ isEnabled
|
|
|
+ title
|
|
|
+ description
|
|
|
+ company
|
|
|
+ contentLicense
|
|
|
+ logoText
|
|
|
+ robots {
|
|
|
+ index
|
|
|
+ follow
|
|
|
+ }
|
|
|
+ features {
|
|
|
+ comments
|
|
|
+ ratings
|
|
|
+ ratingsMode
|
|
|
+ contributions
|
|
|
+ profile
|
|
|
+ search
|
|
|
+ }
|
|
|
+ defaults {
|
|
|
+ timezone
|
|
|
+ dateFormat
|
|
|
+ timeFormat
|
|
|
+ }
|
|
|
}
|
|
|
}
|
|
|
- }
|
|
|
- },
|
|
|
- computed: {
|
|
|
- currentSiteId: get('admin/currentSiteId', false),
|
|
|
- contentLicenses () {
|
|
|
- return [
|
|
|
- { value: '', text: this.$t('common.license.none') },
|
|
|
- { value: 'alr', text: this.$t('common.license.alr') },
|
|
|
- { value: 'cc0', text: this.$t('common.license.cc0') },
|
|
|
- { value: 'ccby', text: this.$t('common.license.ccby') },
|
|
|
- { value: 'ccbysa', text: this.$t('common.license.ccbysa') },
|
|
|
- { value: 'ccbynd', text: this.$t('common.license.ccbynd') },
|
|
|
- { value: 'ccbync', text: this.$t('common.license.ccbync') },
|
|
|
- { value: 'ccbyncsa', text: this.$t('common.license.ccbyncsa') },
|
|
|
- { value: 'ccbyncnd', text: this.$t('common.license.ccbyncnd') }
|
|
|
- ]
|
|
|
+ `,
|
|
|
+ variables: {
|
|
|
+ id: adminStore.currentSiteId
|
|
|
},
|
|
|
- timezones: get('data/timezones', false)
|
|
|
- },
|
|
|
- watch: {
|
|
|
- currentSiteId (newValue) {
|
|
|
- this.load()
|
|
|
- }
|
|
|
- },
|
|
|
- mounted () {
|
|
|
- if (this.currentSiteId) {
|
|
|
- this.load()
|
|
|
+ fetchPolicy: 'network-only'
|
|
|
+ })
|
|
|
+ state.config = cloneDeep(resp?.data?.siteById)
|
|
|
+ $q.loading.hide()
|
|
|
+ state.loading--
|
|
|
+}
|
|
|
+
|
|
|
+async function save () {
|
|
|
+ state.loading++
|
|
|
+ try {
|
|
|
+ await APOLLO_CLIENT.mutate({
|
|
|
+ mutation: gql`
|
|
|
+ mutation saveSite (
|
|
|
+ $id: UUID!
|
|
|
+ $patch: SiteUpdateInput!
|
|
|
+ ) {
|
|
|
+ updateSite (
|
|
|
+ id: $id
|
|
|
+ patch: $patch
|
|
|
+ ) {
|
|
|
+ operation {
|
|
|
+ succeeded
|
|
|
+ slug
|
|
|
+ message
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ `,
|
|
|
+ variables: {
|
|
|
+ id: adminStore.currentSiteId,
|
|
|
+ patch: {
|
|
|
+ hostname: state.config.hostname ?? '',
|
|
|
+ title: state.config.title ?? '',
|
|
|
+ description: state.config.description ?? '',
|
|
|
+ company: state.config.company ?? '',
|
|
|
+ contentLicense: state.config.contentLicense ?? '',
|
|
|
+ logoText: state.config.logoText ?? false,
|
|
|
+ robots: {
|
|
|
+ index: state.config.robots?.index ?? false,
|
|
|
+ follow: state.config.robots?.follow ?? false
|
|
|
+ },
|
|
|
+ features: {
|
|
|
+ comments: state.config.features?.comments ?? false,
|
|
|
+ ratings: (state.config.features?.ratings || 'off') !== 'off',
|
|
|
+ ratingsMode: state.config.features?.ratingsMode ?? 'off',
|
|
|
+ contributions: state.config.features?.contributions ?? false,
|
|
|
+ profile: state.config.features?.profile ?? false,
|
|
|
+ search: state.config.features?.search ?? false
|
|
|
+ },
|
|
|
+ defaults: {
|
|
|
+ timezone: state.config.defaults?.timezone ?? 'America/New_York',
|
|
|
+ dateFormat: state.config.defaults?.dateFormat ?? 'YYYY-MM-DD',
|
|
|
+ timeFormat: state.config.defaults?.timeFormat ?? '12h'
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ })
|
|
|
+ $q.notify({
|
|
|
+ type: 'positive',
|
|
|
+ message: t('admin.general.saveSuccess')
|
|
|
+ })
|
|
|
+ if (adminStore.currentSiteId === siteStore.id) {
|
|
|
+ await adminStore.fetchSites()
|
|
|
+ siteStore.$patch({
|
|
|
+ title: state.config.title,
|
|
|
+ description: state.config.description,
|
|
|
+ company: state.config.company,
|
|
|
+ contentLicense: state.config.contentLicense
|
|
|
+ })
|
|
|
}
|
|
|
- },
|
|
|
- methods: {
|
|
|
- async load () {
|
|
|
- this.loading++
|
|
|
- this.$q.loading.show()
|
|
|
- const resp = await this.$apollo.query({
|
|
|
- query: gql`
|
|
|
- query getSite (
|
|
|
+ } catch (err) {
|
|
|
+ $q.notify({
|
|
|
+ type: 'negative',
|
|
|
+ message: 'Failed to save site configuration.',
|
|
|
+ caption: err.message
|
|
|
+ })
|
|
|
+ }
|
|
|
+ state.loading--
|
|
|
+}
|
|
|
+
|
|
|
+async function uploadLogo () {
|
|
|
+ const input = document.createElement('input')
|
|
|
+ input.type = 'file'
|
|
|
+
|
|
|
+ input.onchange = async e => {
|
|
|
+ state.loading++
|
|
|
+ try {
|
|
|
+ await APOLLO_CLIENT.mutate({
|
|
|
+ mutation: gql`
|
|
|
+ mutation uploadLogo (
|
|
|
$id: UUID!
|
|
|
+ $image: Upload!
|
|
|
) {
|
|
|
- siteById(
|
|
|
+ uploadSiteLogo (
|
|
|
id: $id
|
|
|
+ image: $image
|
|
|
) {
|
|
|
- id
|
|
|
- hostname
|
|
|
- isEnabled
|
|
|
- title
|
|
|
- description
|
|
|
- company
|
|
|
- contentLicense
|
|
|
- logoText
|
|
|
- robots {
|
|
|
- index
|
|
|
- follow
|
|
|
- }
|
|
|
- features {
|
|
|
- comments
|
|
|
- ratings
|
|
|
- ratingsMode
|
|
|
- contributions
|
|
|
- profile
|
|
|
- search
|
|
|
- }
|
|
|
- defaults {
|
|
|
- timezone
|
|
|
- dateFormat
|
|
|
- timeFormat
|
|
|
+ status {
|
|
|
+ succeeded
|
|
|
+ slug
|
|
|
+ message
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
`,
|
|
|
variables: {
|
|
|
- id: this.currentSiteId
|
|
|
- },
|
|
|
- fetchPolicy: 'network-only'
|
|
|
+ id: adminStore.currentSiteId,
|
|
|
+ image: e.target.files[0]
|
|
|
+ }
|
|
|
})
|
|
|
- this.config = cloneDeep(resp?.data?.siteById)
|
|
|
- this.$q.loading.hide()
|
|
|
- this.loading--
|
|
|
- },
|
|
|
- async save () {
|
|
|
- this.loading++
|
|
|
- try {
|
|
|
- await this.$apollo.mutate({
|
|
|
- mutation: gql`
|
|
|
- mutation saveSite (
|
|
|
- $id: UUID!
|
|
|
- $patch: SiteUpdateInput!
|
|
|
+ $q.notify({
|
|
|
+ type: 'positive',
|
|
|
+ message: t('admin.general.logoUploadSuccess')
|
|
|
+ })
|
|
|
+ } catch (err) {
|
|
|
+ $q.notify({
|
|
|
+ type: 'negative',
|
|
|
+ message: 'Failed to upload site logo.',
|
|
|
+ caption: err.message
|
|
|
+ })
|
|
|
+ }
|
|
|
+ state.loading--
|
|
|
+ }
|
|
|
+
|
|
|
+ input.click()
|
|
|
+}
|
|
|
+
|
|
|
+async function uploadFavicon () {
|
|
|
+ const input = document.createElement('input')
|
|
|
+ input.type = 'file'
|
|
|
+
|
|
|
+ input.onchange = async e => {
|
|
|
+ state.loading++
|
|
|
+ try {
|
|
|
+ await APOLLO_CLIENT.mutate({
|
|
|
+ mutation: gql`
|
|
|
+ mutation uploadFavicon (
|
|
|
+ $id: UUID!
|
|
|
+ $image: Upload!
|
|
|
+ ) {
|
|
|
+ uploadSiteFavicon (
|
|
|
+ id: $id
|
|
|
+ image: $image
|
|
|
) {
|
|
|
- updateSite (
|
|
|
- id: $id
|
|
|
- patch: $patch
|
|
|
- ) {
|
|
|
- status {
|
|
|
- succeeded
|
|
|
- slug
|
|
|
- message
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
- `,
|
|
|
- variables: {
|
|
|
- id: this.currentSiteId,
|
|
|
- patch: {
|
|
|
- hostname: this.config.hostname ?? '',
|
|
|
- title: this.config.title ?? '',
|
|
|
- description: this.config.description ?? '',
|
|
|
- company: this.config.company ?? '',
|
|
|
- contentLicense: this.config.contentLicense ?? '',
|
|
|
- logoText: this.config.logoText ?? false,
|
|
|
- robots: {
|
|
|
- index: this.config.robots?.index ?? false,
|
|
|
- follow: this.config.robots?.follow ?? false
|
|
|
- },
|
|
|
- features: {
|
|
|
- comments: this.config.features?.comments ?? false,
|
|
|
- ratings: (this.config.features?.ratings || 'off') !== 'off',
|
|
|
- ratingsMode: this.config.features?.ratingsMode ?? 'off',
|
|
|
- contributions: this.config.features?.contributions ?? false,
|
|
|
- profile: this.config.features?.profile ?? false,
|
|
|
- search: this.config.features?.search ?? false
|
|
|
- },
|
|
|
- defaults: {
|
|
|
- timezone: this.config.defaults?.timezone ?? 'America/New_York',
|
|
|
- dateFormat: this.config.defaults?.dateFormat ?? 'YYYY-MM-DD',
|
|
|
- timeFormat: this.config.defaults?.timeFormat ?? '12h'
|
|
|
+ status {
|
|
|
+ succeeded
|
|
|
+ slug
|
|
|
+ message
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
- })
|
|
|
- this.$q.notify({
|
|
|
- type: 'positive',
|
|
|
- message: this.$t('admin.general.saveSuccess')
|
|
|
- })
|
|
|
- if (this.currentSiteId === this.$store.get('site/id')) {
|
|
|
- await this.$store.dispatch('admin/fetchSites')
|
|
|
- this.$store.set('site/title', this.config.title)
|
|
|
- this.$store.set('site/description', this.config.description)
|
|
|
- this.$store.set('site/company', this.config.company)
|
|
|
- this.$store.set('site/contentLicense', this.config.contentLicense)
|
|
|
- }
|
|
|
- } catch (err) {
|
|
|
- this.$q.notify({
|
|
|
- type: 'negative',
|
|
|
- message: 'Failed to save site configuration.',
|
|
|
- caption: err.message
|
|
|
- })
|
|
|
- }
|
|
|
- this.loading--
|
|
|
- },
|
|
|
- async uploadLogo () {
|
|
|
- const input = document.createElement('input')
|
|
|
- input.type = 'file'
|
|
|
-
|
|
|
- input.onchange = async e => {
|
|
|
- this.loading++
|
|
|
- try {
|
|
|
- await this.$apollo.mutate({
|
|
|
- mutation: gql`
|
|
|
- mutation uploadLogo (
|
|
|
- $id: UUID!
|
|
|
- $image: Upload!
|
|
|
- ) {
|
|
|
- uploadSiteLogo (
|
|
|
- id: $id
|
|
|
- image: $image
|
|
|
- ) {
|
|
|
- status {
|
|
|
- succeeded
|
|
|
- slug
|
|
|
- message
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
- `,
|
|
|
- variables: {
|
|
|
- id: this.currentSiteId,
|
|
|
- image: e.target.files[0]
|
|
|
- }
|
|
|
- })
|
|
|
- this.$q.notify({
|
|
|
- type: 'positive',
|
|
|
- message: this.$t('admin.general.logoUploadSuccess')
|
|
|
- })
|
|
|
- } catch (err) {
|
|
|
- this.$q.notify({
|
|
|
- type: 'negative',
|
|
|
- message: 'Failed to upload site logo.',
|
|
|
- caption: err.message
|
|
|
- })
|
|
|
- }
|
|
|
- this.loading--
|
|
|
- }
|
|
|
-
|
|
|
- input.click()
|
|
|
- },
|
|
|
- refreshLogo () {
|
|
|
- this.$forceUpdate()
|
|
|
- },
|
|
|
- async uploadFavicon () {
|
|
|
- const input = document.createElement('input')
|
|
|
- input.type = 'file'
|
|
|
-
|
|
|
- input.onchange = async e => {
|
|
|
- this.loading++
|
|
|
- try {
|
|
|
- await this.$apollo.mutate({
|
|
|
- mutation: gql`
|
|
|
- mutation uploadFavicon (
|
|
|
- $id: UUID!
|
|
|
- $image: Upload!
|
|
|
- ) {
|
|
|
- uploadSiteFavicon (
|
|
|
- id: $id
|
|
|
- image: $image
|
|
|
- ) {
|
|
|
- status {
|
|
|
- succeeded
|
|
|
- slug
|
|
|
- message
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
- `,
|
|
|
- variables: {
|
|
|
- id: this.currentSiteId,
|
|
|
- image: e.target.files[0]
|
|
|
- }
|
|
|
- })
|
|
|
- this.$q.notify({
|
|
|
- type: 'positive',
|
|
|
- message: this.$t('admin.general.faviconUploadSuccess')
|
|
|
- })
|
|
|
- } catch (err) {
|
|
|
- this.$q.notify({
|
|
|
- type: 'negative',
|
|
|
- message: 'Failed to upload site favicon.',
|
|
|
- caption: err.message
|
|
|
- })
|
|
|
+ `,
|
|
|
+ variables: {
|
|
|
+ id: adminStore.currentSiteId,
|
|
|
+ image: e.target.files[0]
|
|
|
}
|
|
|
- this.loading--
|
|
|
- }
|
|
|
-
|
|
|
- input.click()
|
|
|
+ })
|
|
|
+ $q.notify({
|
|
|
+ type: 'positive',
|
|
|
+ message: t('admin.general.faviconUploadSuccess')
|
|
|
+ })
|
|
|
+ } catch (err) {
|
|
|
+ $q.notify({
|
|
|
+ type: 'negative',
|
|
|
+ message: 'Failed to upload site favicon.',
|
|
|
+ caption: err.message
|
|
|
+ })
|
|
|
}
|
|
|
+ state.loading--
|
|
|
}
|
|
|
+
|
|
|
+ input.click()
|
|
|
}
|
|
|
+
|
|
|
+// MOUNTED
|
|
|
+
|
|
|
+onMounted(() => {
|
|
|
+ if (adminStore.currentSiteId) {
|
|
|
+ load()
|
|
|
+ }
|
|
|
+})
|
|
|
</script>
|
|
|
|
|
|
<style lang='scss'>
|