76 lines
1.8 KiB
Vue
76 lines
1.8 KiB
Vue
<script setup lang="ts">
|
|
import { computed } from 'vue'
|
|
import { formatMessage, messages } from '../lib/messages'
|
|
import type { PlaylistState } from '../lib/models'
|
|
|
|
const props = defineProps<{
|
|
state: PlaylistState
|
|
trackCount: number
|
|
canSave: boolean
|
|
}>()
|
|
defineEmits<{ save: [] }>()
|
|
|
|
const buttonLabel = computed(() => {
|
|
if (props.state.status === 'saving') return messages.resultActionsSaving
|
|
if (props.state.status === 'error') return messages.resultActionsTryAgain
|
|
return messages.resultActionsSavePlaylist
|
|
})
|
|
const summary = computed(() => formatMessage('resultActionsSummary', { count: props.trackCount }))
|
|
</script>
|
|
|
|
<template>
|
|
<div class="actions">
|
|
<button
|
|
v-if="canSave"
|
|
class="save"
|
|
type="button"
|
|
:disabled="state.status === 'saving'"
|
|
@click="$emit('save')"
|
|
>
|
|
{{ buttonLabel }}
|
|
</button>
|
|
<a v-else class="connect" href="/api/auth/login">{{ messages.resultActionsConnectSpotify }}</a>
|
|
<span class="summary">{{ summary }}</span>
|
|
</div>
|
|
</template>
|
|
|
|
<style scoped>
|
|
.actions {
|
|
display: flex;
|
|
flex-wrap: wrap;
|
|
gap: var(--s-5);
|
|
align-items: center;
|
|
}
|
|
|
|
.save,
|
|
.connect {
|
|
display: inline-flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
min-height: var(--tap-min);
|
|
padding: 11px var(--s-6);
|
|
color: var(--c-on-accent);
|
|
font-size: var(--t-small);
|
|
font-weight: 500;
|
|
text-decoration: none;
|
|
cursor: pointer;
|
|
background: var(--c-accent);
|
|
border: 1px solid var(--c-accent);
|
|
border-radius: var(--r-md);
|
|
transition: all var(--dur-fast) ease;
|
|
}
|
|
|
|
.save:hover,
|
|
.connect:hover {
|
|
color: var(--c-on-accent);
|
|
text-decoration: none;
|
|
background: var(--c-accent-hover);
|
|
border-color: var(--c-accent-hover);
|
|
}
|
|
|
|
.summary {
|
|
color: var(--c-text-faint);
|
|
font-family: var(--f-mono);
|
|
font-size: var(--t-micro);
|
|
}
|
|
</style>
|