Migrate rest of inputs to new v-model
This commit is contained in:
parent
bf009440ff
commit
561c1d868c
|
@ -14,7 +14,7 @@
|
|||
<inline-search-bar
|
||||
v-if="search"
|
||||
v-model="query"
|
||||
@search="albums = []; fetchData()"
|
||||
@search="performSearch"
|
||||
/>
|
||||
<div class="ui hidden divider" />
|
||||
<div class="ui app-cards cards">
|
||||
|
@ -69,6 +69,14 @@ export default {
|
|||
search: { type: Boolean, default: false },
|
||||
limit: { type: Number, default: 12 }
|
||||
},
|
||||
setup () {
|
||||
const performSearch = () => {
|
||||
this.albums.length = 0
|
||||
this.fetchData()
|
||||
}
|
||||
|
||||
return { performSearch }
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
albums: [],
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
<inline-search-bar
|
||||
v-if="search"
|
||||
v-model="query"
|
||||
@search="objects = []; fetchData()"
|
||||
@search="performSearch"
|
||||
/>
|
||||
<div class="ui hidden divider" />
|
||||
<div class="ui five app-cards cards">
|
||||
|
@ -64,6 +64,14 @@ export default {
|
|||
header: { type: Boolean, default: true },
|
||||
search: { type: Boolean, default: false }
|
||||
},
|
||||
setup () {
|
||||
const performSearch = () => {
|
||||
this.objects.length = 0
|
||||
this.fetchData()
|
||||
}
|
||||
|
||||
return { performSearch }
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
objects: [],
|
||||
|
|
|
@ -4,11 +4,7 @@
|
|||
<inline-search-bar
|
||||
v-if="search"
|
||||
v-model="query"
|
||||
@search="
|
||||
currentPage = 1;
|
||||
additionalTracks = [];
|
||||
fetchData('tracks/');
|
||||
"
|
||||
@search="performSearch"
|
||||
/>
|
||||
|
||||
<!-- Add a header if needed -->
|
||||
|
@ -191,6 +187,16 @@ export default {
|
|||
paginateBy: { type: Number, required: false, default: 25 }
|
||||
},
|
||||
|
||||
setup () {
|
||||
const performSearch = () => {
|
||||
this.currentPage = 1
|
||||
this.additionalTracks.length = 0
|
||||
this.fetchData('tracks/')
|
||||
}
|
||||
|
||||
return { performSearch }
|
||||
},
|
||||
|
||||
data () {
|
||||
return {
|
||||
fetchDataUrl: this.nextUrl,
|
||||
|
|
|
@ -1,3 +1,44 @@
|
|||
<script setup lang="ts">
|
||||
import axios from 'axios'
|
||||
import { useVModel } from '@vueuse/core'
|
||||
import { reactive, ref, watch } from 'vue'
|
||||
import { Album, Channel } from '~/types'
|
||||
|
||||
interface Props {
|
||||
modelValue: number
|
||||
channel?: Channel
|
||||
}
|
||||
|
||||
const props = withDefaults(defineProps<Props>(), {
|
||||
channel: () => ({ id: '' })
|
||||
})
|
||||
|
||||
const emit = defineEmits(['update:modelValue'])
|
||||
const value = useVModel(props, 'modelValue', emit)
|
||||
|
||||
const albums = reactive<Album[]>([])
|
||||
|
||||
const isLoading = ref(false)
|
||||
const fetchData = async () => {
|
||||
albums.length = 0
|
||||
if (!props.channel?.artist) return
|
||||
|
||||
isLoading.value = true
|
||||
const response = await axios.get('albums/', {
|
||||
params: {
|
||||
artist: props.channel?.artist.id,
|
||||
include_channels: 'true'
|
||||
}
|
||||
})
|
||||
|
||||
albums.push(...response.data.results)
|
||||
isLoading.value = false
|
||||
}
|
||||
|
||||
watch(() => props.channel, fetchData)
|
||||
fetchData()
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<label for="album-dropdown">
|
||||
|
@ -14,9 +55,8 @@
|
|||
</label>
|
||||
<select
|
||||
id="album-dropdown"
|
||||
:value="value"
|
||||
v-model="value"
|
||||
class="ui search normal dropdown"
|
||||
@input="$emit('input', $event.target.value)"
|
||||
>
|
||||
<option value="">
|
||||
<translate translate-context="*/*/*">
|
||||
|
@ -40,39 +80,3 @@
|
|||
</select>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import axios from 'axios'
|
||||
|
||||
export default {
|
||||
props: {
|
||||
value: { type: Number, default: null },
|
||||
channel: { type: Object, default: () => ({}) }
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
albums: [],
|
||||
isLoading: false
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
async channel () {
|
||||
await this.fetchData()
|
||||
}
|
||||
},
|
||||
async created () {
|
||||
await this.fetchData()
|
||||
},
|
||||
methods: {
|
||||
async fetchData () {
|
||||
this.albums = []
|
||||
if (!this.channel || !this.channel.artist) {
|
||||
return
|
||||
}
|
||||
this.isLoading = true
|
||||
const response = await axios.get('albums/', { params: { artist: this.channel.artist.id, include_channels: 'true' } })
|
||||
this.albums = response.data.results
|
||||
this.isLoading = false
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
|
|
@ -1,3 +1,49 @@
|
|||
<script setup lang="ts">
|
||||
import axios from 'axios'
|
||||
import { useVModel } from '@vueuse/core'
|
||||
import { computed, reactive, ref } from 'vue'
|
||||
import { License } from '~/types'
|
||||
|
||||
interface Props {
|
||||
modelValue: string
|
||||
}
|
||||
|
||||
const props = defineProps<Props>()
|
||||
const emit = defineEmits(['update:modelValue'])
|
||||
const value = useVModel(props, 'modelValue', emit)
|
||||
|
||||
const availableLicenses = reactive<License[]>([])
|
||||
const featuredLicensesIds = [
|
||||
'cc0-1.0',
|
||||
'cc-by-4.0',
|
||||
'cc-by-sa-4.0',
|
||||
'cc-by-nc-4.0',
|
||||
'cc-by-nc-sa-4.0',
|
||||
'cc-by-nc-nd-4.0',
|
||||
'cc-by-nd-4.0'
|
||||
]
|
||||
|
||||
const featuredLicenses = computed(() => {
|
||||
return availableLicenses.filter(({ code }) => featuredLicensesIds.includes(code))
|
||||
})
|
||||
|
||||
const currentLicense = computed(() => {
|
||||
if (!value.value) return null
|
||||
return availableLicenses.find(({ code }) => code === value.value) ?? null
|
||||
})
|
||||
|
||||
const isLoading = ref(false)
|
||||
const fetchLicenses = async () => {
|
||||
isLoading.value = true
|
||||
const response = await axios.get('licenses/')
|
||||
availableLicenses.length = 0
|
||||
availableLicenses.push(...response.data.results)
|
||||
isLoading.value = false
|
||||
}
|
||||
|
||||
fetchLicenses()
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<label for="license-dropdown">
|
||||
|
@ -5,9 +51,8 @@
|
|||
</label>
|
||||
<select
|
||||
id="license-dropdown"
|
||||
:value="value"
|
||||
v-model="value"
|
||||
class="ui search normal dropdown"
|
||||
@input="$emit('input', $event.target.value)"
|
||||
>
|
||||
<option value="">
|
||||
<translate translate-context="*/*/*">
|
||||
|
@ -38,53 +83,3 @@
|
|||
</p>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import axios from 'axios'
|
||||
|
||||
export default {
|
||||
props: { value: { type: String, default: null } },
|
||||
data () {
|
||||
return {
|
||||
availableLicenses: [],
|
||||
featuredLicensesIds: [
|
||||
'cc0-1.0',
|
||||
'cc-by-4.0',
|
||||
'cc-by-sa-4.0',
|
||||
'cc-by-nc-4.0',
|
||||
'cc-by-nc-sa-4.0',
|
||||
'cc-by-nc-nd-4.0',
|
||||
'cc-by-nd-4.0'
|
||||
],
|
||||
isLoading: false
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
featuredLicenses () {
|
||||
const self = this
|
||||
return this.availableLicenses.filter((l) => {
|
||||
return self.featuredLicensesIds.indexOf(l.code) > -1
|
||||
})
|
||||
},
|
||||
currentLicense () {
|
||||
const self = this
|
||||
if (this.value) {
|
||||
return this.availableLicenses.filter((l) => {
|
||||
return l.code === self.value
|
||||
})[0]
|
||||
}
|
||||
return null
|
||||
}
|
||||
},
|
||||
async created () {
|
||||
await this.fetchLicenses()
|
||||
},
|
||||
methods: {
|
||||
async fetchLicenses () {
|
||||
this.isLoading = true
|
||||
const response = await axios.get('licenses/')
|
||||
this.availableLicenses = response.data.results
|
||||
this.isLoading = false
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
|
|
@ -1,8 +1,9 @@
|
|||
<script setup lang="ts">
|
||||
import axios from 'axios'
|
||||
import { useVModel } from '@vueuse/core'
|
||||
import {reactive, ref, watch, watchEffect} from 'vue'
|
||||
import { reactive, ref, watch } from 'vue'
|
||||
import { BackendError } from '~/types'
|
||||
import { useStore } from 'vuex'
|
||||
|
||||
interface Props {
|
||||
modelValue: string
|
||||
|
@ -86,6 +87,10 @@ watch(value, (to, from) => {
|
|||
}
|
||||
})
|
||||
|
||||
const store = useStore()
|
||||
const getAttachmentUrl = (uuid: string) => {
|
||||
return store.getters['instance/absoluteUrl'](`api/v1/attachments/${uuid}/proxy?next=medium_square_crop`)
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
@ -119,13 +124,13 @@ watch(value, (to, from) => {
|
|||
v-if="value && value === initialValue"
|
||||
alt=""
|
||||
:class="['ui', imageClass, 'image']"
|
||||
:src="$store.getters['instance/absoluteUrl'](`api/v1/attachments/${value}/proxy?next=medium_square_crop`)"
|
||||
:src="getAttachmentUrl(value)"
|
||||
>
|
||||
<img
|
||||
v-else-if="attachment"
|
||||
alt=""
|
||||
:class="['ui', imageClass, 'image']"
|
||||
:src="$store.getters['instance/absoluteUrl'](`api/v1/attachments/${attachment.uuid}/proxy?next=medium_square_crop`)"
|
||||
:src="getAttachmentUrl(attachment.uuid)"
|
||||
>
|
||||
<div
|
||||
v-else
|
||||
|
@ -141,7 +146,7 @@ watch(value, (to, from) => {
|
|||
:id="attachmentId"
|
||||
ref="input"
|
||||
:name="name"
|
||||
:required="required || null"
|
||||
:required="required || undefined"
|
||||
class="ui input"
|
||||
type="file"
|
||||
accept="image/png,image/jpeg"
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
<script setup lang="ts">
|
||||
import { useClipboard, useVModel } from '@vueuse/core'
|
||||
import { toRefs, useClipboard } from '@vueuse/core'
|
||||
|
||||
interface Props {
|
||||
modelValue: string
|
||||
value: string
|
||||
buttonClasses?: string
|
||||
id?: string
|
||||
}
|
||||
|
@ -12,9 +12,7 @@ const props = withDefaults(defineProps<Props>(), {
|
|||
id: 'copy-input'
|
||||
})
|
||||
|
||||
const emit = defineEmits(['update:modelValue'])
|
||||
const value = useVModel(props, 'modelValue', emit)
|
||||
|
||||
const { value } = toRefs(props)
|
||||
const { copy, isSupported: canCopy, copied } = useClipboard({ source: value, copiedDuring: 5000 })
|
||||
</script>
|
||||
|
||||
|
@ -30,7 +28,7 @@ const { copy, isSupported: canCopy, copied } = useClipboard({ source: value, cop
|
|||
</p>
|
||||
<input
|
||||
:id="id"
|
||||
v-model="value"
|
||||
:value="value"
|
||||
:name="id"
|
||||
type="text"
|
||||
readonly
|
||||
|
|
|
@ -1,9 +1,38 @@
|
|||
<script setup lang="ts">
|
||||
import { useVModel } from '@vueuse/core'
|
||||
import { computed } from 'vue'
|
||||
import { useGettext } from 'vue3-gettext'
|
||||
|
||||
interface Props {
|
||||
modelValue: string
|
||||
placeholder?: string
|
||||
}
|
||||
|
||||
const props = withDefaults(defineProps<Props>(), {
|
||||
placeholder: ''
|
||||
})
|
||||
|
||||
const emit = defineEmits(['update:modelValue', 'search'])
|
||||
const value = useVModel(props, 'modelValue', emit)
|
||||
|
||||
const { $pgettext } = useGettext()
|
||||
const labels = computed(() => ({
|
||||
searchPlaceholder: $pgettext('Content/Search/Input.Placeholder', 'Search…'),
|
||||
clear: $pgettext('Content/Library/Button.Label', 'Clear')
|
||||
}))
|
||||
|
||||
const search = () => {
|
||||
value.value = ''
|
||||
emit('search', value.value)
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<form
|
||||
class="ui inline form"
|
||||
@submit.stop.prevent="$emit('search', value)"
|
||||
@submit.stop.prevent="emit('search', value)"
|
||||
>
|
||||
<div :class="['ui', 'action', {icon: isClearable}, 'input']">
|
||||
<div :class="['ui', 'action', {icon: value}, 'input']">
|
||||
<label
|
||||
for="search-query"
|
||||
class="hidden"
|
||||
|
@ -12,17 +41,16 @@
|
|||
</label>
|
||||
<input
|
||||
id="search-query"
|
||||
v-model="value"
|
||||
name="search-query"
|
||||
type="text"
|
||||
:placeholder="placeholder || labels.searchPlaceholder"
|
||||
:value="value"
|
||||
@input="$emit('input', $event.target.value)"
|
||||
>
|
||||
<i
|
||||
v-if="isClearable"
|
||||
v-if="value"
|
||||
class="x link icon"
|
||||
:title="labels.clear"
|
||||
@click.stop.prevent="$emit('input', ''); $emit('search', value)"
|
||||
@click.stop.prevent="search"
|
||||
/>
|
||||
<button
|
||||
type="submit"
|
||||
|
@ -33,22 +61,3 @@
|
|||
</div>
|
||||
</form>
|
||||
</template>
|
||||
<script>
|
||||
export default {
|
||||
props: {
|
||||
value: { type: String, required: true },
|
||||
placeholder: { type: String, required: false, default: '' }
|
||||
},
|
||||
computed: {
|
||||
labels () {
|
||||
return {
|
||||
searchPlaceholder: this.$pgettext('Content/Search/Input.Placeholder', 'Search…'),
|
||||
clear: this.$pgettext('Content/Library/Button.Label', 'Clear')
|
||||
}
|
||||
},
|
||||
isClearable () {
|
||||
return !!this.value
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
|
|
@ -59,7 +59,7 @@ const allCategories = computed(() => {
|
|||
<select
|
||||
v-model="value"
|
||||
class="ui dropdown"
|
||||
:required="required || null"
|
||||
:required="required || undefined"
|
||||
>
|
||||
<option
|
||||
v-if="empty"
|
||||
|
|
|
@ -55,7 +55,7 @@ Promise.all(modules).finally(() => {
|
|||
// TODO (wvffle): Replace $set and $delete with reactive()
|
||||
// TODO (wvffle): Check for mixin merging: https://v3-migration.vuejs.org/breaking-changes/data-option.html#mixin-merge-behavior-change=
|
||||
// TODO (wvffle): Use emits options: https://v3-migration.vuejs.org/breaking-changes/emits-option.html
|
||||
// TODO (wvffle): Migrate to new v-model: https://v3-migration.vuejs.org/breaking-changes/v-model.html
|
||||
// TODO (wvffle): Find all array watchers and make them deep
|
||||
// TODO (wvffle): Migrate to <script setup>
|
||||
// TODO (wvffle): Replace `from '(../)+` with `from '~/`
|
||||
// TODO (wvffle): Remove `allowJs` from tsconfig.json
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import type { App } from 'vue'
|
||||
import type { Store } from 'vuex'
|
||||
import { Router } from 'vue-router'
|
||||
import {AxiosError} from "axios";
|
||||
import { AxiosError } from 'axios'
|
||||
|
||||
declare global {
|
||||
interface Window {
|
||||
|
@ -29,20 +29,33 @@ export interface ThemeEntry {
|
|||
}
|
||||
|
||||
// Track stuff
|
||||
export type ContentCategory = 'podcast'
|
||||
|
||||
export interface Artist {
|
||||
id: string
|
||||
name: string
|
||||
content_category: ContentCategory
|
||||
}
|
||||
|
||||
export interface Album {
|
||||
id: string
|
||||
artist: Artist
|
||||
tracks_count: number
|
||||
title: string
|
||||
}
|
||||
|
||||
export interface Track {
|
||||
id: string
|
||||
title: string
|
||||
album?: Album
|
||||
artist?: Artist
|
||||
}
|
||||
|
||||
export interface Channel {
|
||||
id: string
|
||||
artist?: Artist
|
||||
}
|
||||
|
||||
// API stuff
|
||||
export interface APIErrorResponse {
|
||||
[key: string]: APIErrorResponse | string[]
|
||||
|
@ -122,3 +135,9 @@ export interface Actor {
|
|||
is_local: boolean
|
||||
domain: string
|
||||
}
|
||||
|
||||
export interface License {
|
||||
code: string
|
||||
name: string
|
||||
url: string
|
||||
}
|
||||
|
|
|
@ -138,7 +138,10 @@
|
|||
If you're using Mastodon or other fediverse applications, you can subscribe to this account:
|
||||
</translate>
|
||||
</p>
|
||||
<copy-input :value="`@${object.actor.full_username}`" />
|
||||
<copy-input
|
||||
id="copy-tag"
|
||||
:value="`@${object.actor.full_username}`"
|
||||
/>
|
||||
</template>
|
||||
</div>
|
||||
</div>
|
||||
|
|
Loading…
Reference in New Issue