mirror of
https://github.com/chenasraf/nextcloud-jukebox.git
synced 2026-05-18 01:39:00 +00:00
chore: prettier fix
This commit is contained in:
12
.prettierrc
12
.prettierrc
@@ -6,6 +6,10 @@
|
||||
"semi": false,
|
||||
"singleQuote": true,
|
||||
"trailingComma": "all",
|
||||
"bracketSameLine": true,
|
||||
"vueIndentScriptAndStyle": true,
|
||||
"htmlWhitespaceSensitivity": "strict",
|
||||
"singleAttributePerLine": false,
|
||||
"overrides": [
|
||||
{
|
||||
"files": "*.md",
|
||||
@@ -13,6 +17,14 @@
|
||||
"printWidth": 100,
|
||||
"proseWrap": "always"
|
||||
}
|
||||
},
|
||||
{
|
||||
"files": "*.vue",
|
||||
"options": {
|
||||
"parser": "vue",
|
||||
"bracketSameLine": true,
|
||||
"htmlWhitespaceSensitivity": "strict"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -39,6 +39,7 @@
|
||||
"eslint": "^9.28.0",
|
||||
"husky": "^9.1.7",
|
||||
"lint-staged": "^16.1.0",
|
||||
"prettier": "^2.8.8",
|
||||
"prettier-plugin-vue": "^1.1.6",
|
||||
"sass": "^1.89.1",
|
||||
"sass-embedded": "^1.89.1",
|
||||
|
||||
3
pnpm-lock.yaml
generated
3
pnpm-lock.yaml
generated
@@ -63,6 +63,9 @@ importers:
|
||||
lint-staged:
|
||||
specifier: ^16.1.0
|
||||
version: 16.1.0
|
||||
prettier:
|
||||
specifier: ^2.8.8
|
||||
version: 2.8.8
|
||||
prettier-plugin-vue:
|
||||
specifier: ^1.1.6
|
||||
version: 1.1.6
|
||||
|
||||
211
src/App.vue
211
src/App.vue
@@ -1,134 +1,140 @@
|
||||
<template>
|
||||
<NcContent app-name="jukebox"
|
||||
> <NcAppNavigation
|
||||
> <template #search
|
||||
> <NcAppNavigationSearch v-model="searchValue" label="Search…" /> </template
|
||||
> <template #list
|
||||
> <NcAppNavigationItem name="Tracks" :to="{ path: '/tracks' }"
|
||||
> <template #icon> <Music :size="20" /> </template> </NcAppNavigationItem
|
||||
> <NcAppNavigationItem name="Albums" :to="{ path: '/albums' }"
|
||||
> <template #icon> <Album :size="20" /> </template> </NcAppNavigationItem
|
||||
> <NcAppNavigationItem name="Artists" :to="{ path: '/artists' }"
|
||||
> <template #icon> <AccountMusic :size="20" /> </template> </NcAppNavigationItem
|
||||
> <NcAppNavigationItem name="Podcasts" :to="{ path: '/podcasts' }"
|
||||
> <template #icon> <Podcast :size="20" /> </template> </NcAppNavigationItem
|
||||
> <NcAppNavigationItem name="Audiobooks" :to="{ path: '/audiobooks' }"
|
||||
> <template #icon> <Book :size="20" /> </template> </NcAppNavigationItem
|
||||
> <NcAppNavigationItem name="Videos" :to="{ path: '/videos' }"
|
||||
> <template #icon> <Filmstrip :size="20" /> </template> </NcAppNavigationItem
|
||||
> <NcAppNavigationItem name="Genres" :to="{ path: '/genres' }"
|
||||
> <template #icon> <Tag :size="20" /> </template> </NcAppNavigationItem
|
||||
> </template
|
||||
> <template #footer> <!-- Add footer controls if needed --> </template> </NcAppNavigation
|
||||
> <NcAppContent id="jukebox-main"
|
||||
>
|
||||
<NcContent app-name="jukebox">
|
||||
<NcAppNavigation>
|
||||
<template #search> <NcAppNavigationSearch v-model="searchValue" label="Search…" /> </template>
|
||||
<template #list>
|
||||
<NcAppNavigationItem name="Tracks" :to="{ path: '/tracks' }">
|
||||
<template #icon> <Music :size="20" /> </template>
|
||||
</NcAppNavigationItem>
|
||||
<NcAppNavigationItem name="Albums" :to="{ path: '/albums' }">
|
||||
<template #icon> <Album :size="20" /> </template>
|
||||
</NcAppNavigationItem>
|
||||
<NcAppNavigationItem name="Artists" :to="{ path: '/artists' }">
|
||||
<template #icon> <AccountMusic :size="20" /> </template>
|
||||
</NcAppNavigationItem>
|
||||
<NcAppNavigationItem name="Podcasts" :to="{ path: '/podcasts' }">
|
||||
<template #icon> <Podcast :size="20" /> </template>
|
||||
</NcAppNavigationItem>
|
||||
<NcAppNavigationItem name="Audiobooks" :to="{ path: '/audiobooks' }">
|
||||
<template #icon> <Book :size="20" /> </template>
|
||||
</NcAppNavigationItem>
|
||||
<NcAppNavigationItem name="Videos" :to="{ path: '/videos' }">
|
||||
<template #icon> <Filmstrip :size="20" /> </template>
|
||||
</NcAppNavigationItem>
|
||||
<NcAppNavigationItem name="Genres" :to="{ path: '/genres' }">
|
||||
<template #icon> <Tag :size="20" /> </template>
|
||||
</NcAppNavigationItem>
|
||||
</template>
|
||||
<template #footer> <!-- Add footer controls if needed --> </template>
|
||||
</NcAppNavigation>
|
||||
<NcAppContent id="jukebox-main">
|
||||
<div id="jukebox-router"> <router-view /> </div>
|
||||
<!-- Media Player -->
|
||||
<!-- Media Player -->
|
||||
<footer class="jukebox-player">
|
||||
|
||||
<div class="controls">
|
||||
<NcButton
|
||||
<NcButton
|
||||
:disabled="false"
|
||||
variant="tertiary"
|
||||
aria-label="Previous"
|
||||
size="normal"
|
||||
@click="prev"
|
||||
> <template #icon> <SkipPrevious :size="20" /> </template> </NcButton
|
||||
> <NcButton
|
||||
@click="prev">
|
||||
<template #icon> <SkipPrevious :size="20" /> </template>
|
||||
</NcButton>
|
||||
<NcButton
|
||||
:disabled="false"
|
||||
variant="primary"
|
||||
aria-label="Play/Pause"
|
||||
size="normal"
|
||||
@click="togglePlay"
|
||||
> <template #icon
|
||||
> <Play :size="20" v-if="!isPlaying" /> <Pause :size="20" v-else /> </template
|
||||
> </NcButton
|
||||
> <NcButton
|
||||
@click="togglePlay">
|
||||
<template #icon>
|
||||
<Play :size="20" v-if="!isPlaying" /> <Pause :size="20" v-else />
|
||||
</template>
|
||||
</NcButton>
|
||||
<NcButton
|
||||
:disabled="false"
|
||||
variant="tertiary"
|
||||
aria-label="Next"
|
||||
size="normal"
|
||||
@click="next"
|
||||
> <template #icon> <SkipNext :size="20" /> </template> </NcButton
|
||||
>
|
||||
@click="next">
|
||||
<template #icon> <SkipNext :size="20" /> </template>
|
||||
</NcButton>
|
||||
</div>
|
||||
<input type="range" min="0" max="100" v-model="seek" class="seekbar" />
|
||||
<input type="range" min="0" max="100" v-model="seek" class="seekbar" />
|
||||
</footer>
|
||||
</NcAppContent
|
||||
> </NcContent
|
||||
>
|
||||
</NcAppContent>
|
||||
</NcContent>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent } from 'vue'
|
||||
import NcAppNavigation from '@nextcloud/vue/components/NcAppNavigation'
|
||||
import NcAppNavigationItem from '@nextcloud/vue/components/NcAppNavigationItem'
|
||||
import NcAppNavigationSearch from '@nextcloud/vue/components/NcAppNavigationSearch'
|
||||
import NcAppContent from '@nextcloud/vue/components/NcAppContent'
|
||||
import NcContent from '@nextcloud/vue/components/NcContent'
|
||||
import NcButton from '@nextcloud/vue/components/NcButton'
|
||||
import { defineComponent } from 'vue'
|
||||
import NcAppNavigation from '@nextcloud/vue/components/NcAppNavigation'
|
||||
import NcAppNavigationItem from '@nextcloud/vue/components/NcAppNavigationItem'
|
||||
import NcAppNavigationSearch from '@nextcloud/vue/components/NcAppNavigationSearch'
|
||||
import NcAppContent from '@nextcloud/vue/components/NcAppContent'
|
||||
import NcContent from '@nextcloud/vue/components/NcContent'
|
||||
import NcButton from '@nextcloud/vue/components/NcButton'
|
||||
|
||||
import SkipPrevious from '@icons/SkipPrevious.vue'
|
||||
import SkipNext from '@icons/SkipNext.vue'
|
||||
import Play from '@icons/Play.vue'
|
||||
import Pause from '@icons/Pause.vue'
|
||||
import Music from '@icons/Music.vue'
|
||||
import Album from '@icons/Album.vue'
|
||||
import AccountMusic from '@icons/AccountMusic.vue'
|
||||
import Podcast from '@icons/Podcast.vue'
|
||||
import Book from '@icons/Book.vue'
|
||||
import Filmstrip from '@icons/Filmstrip.vue'
|
||||
import Tag from '@icons/Tag.vue'
|
||||
import SkipPrevious from '@icons/SkipPrevious.vue'
|
||||
import SkipNext from '@icons/SkipNext.vue'
|
||||
import Play from '@icons/Play.vue'
|
||||
import Pause from '@icons/Pause.vue'
|
||||
import Music from '@icons/Music.vue'
|
||||
import Album from '@icons/Album.vue'
|
||||
import AccountMusic from '@icons/AccountMusic.vue'
|
||||
import Podcast from '@icons/Podcast.vue'
|
||||
import Book from '@icons/Book.vue'
|
||||
import Filmstrip from '@icons/Filmstrip.vue'
|
||||
import Tag from '@icons/Tag.vue'
|
||||
|
||||
export default defineComponent({
|
||||
name: 'App',
|
||||
components: {
|
||||
NcContent,
|
||||
NcAppContent,
|
||||
NcAppNavigation,
|
||||
NcAppNavigationItem,
|
||||
NcAppNavigationSearch,
|
||||
NcButton,
|
||||
SkipPrevious,
|
||||
SkipNext,
|
||||
Play,
|
||||
Pause,
|
||||
Music,
|
||||
Album,
|
||||
AccountMusic,
|
||||
Podcast,
|
||||
Book,
|
||||
Filmstrip,
|
||||
Tag,
|
||||
},
|
||||
provide() {
|
||||
return {
|
||||
'NcContent:setHasAppNavigation': () => true,
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
searchValue: '',
|
||||
isPlaying: false,
|
||||
seek: 0,
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
togglePlay() {
|
||||
this.isPlaying = !this.isPlaying
|
||||
export default defineComponent({
|
||||
name: 'App',
|
||||
components: {
|
||||
NcContent,
|
||||
NcAppContent,
|
||||
NcAppNavigation,
|
||||
NcAppNavigationItem,
|
||||
NcAppNavigationSearch,
|
||||
NcButton,
|
||||
SkipPrevious,
|
||||
SkipNext,
|
||||
Play,
|
||||
Pause,
|
||||
Music,
|
||||
Album,
|
||||
AccountMusic,
|
||||
Podcast,
|
||||
Book,
|
||||
Filmstrip,
|
||||
Tag,
|
||||
},
|
||||
next() {
|
||||
// Placeholder
|
||||
provide() {
|
||||
return {
|
||||
'NcContent:setHasAppNavigation': () => true,
|
||||
}
|
||||
},
|
||||
prev() {
|
||||
// Placeholder
|
||||
data() {
|
||||
return {
|
||||
searchValue: '',
|
||||
isPlaying: false,
|
||||
seek: 0,
|
||||
}
|
||||
},
|
||||
},
|
||||
})
|
||||
methods: {
|
||||
togglePlay() {
|
||||
this.isPlaying = !this.isPlaying
|
||||
},
|
||||
next() {
|
||||
// Placeholder
|
||||
},
|
||||
prev() {
|
||||
// Placeholder
|
||||
},
|
||||
},
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
#jukebox-main {
|
||||
#jukebox-main {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
@@ -152,4 +158,3 @@ export default defineComponent({
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
|
||||
200
src/Settings.vue
200
src/Settings.vue
@@ -1,140 +1,129 @@
|
||||
<template>
|
||||
|
||||
<div id="jukebox-user-settings" class="section">
|
||||
|
||||
<h2>{{ strings.header }}</h2>
|
||||
|
||||
<form @submit.prevent="save">
|
||||
<NcAppSettingsSection :name="strings.musicLibrarySettings"
|
||||
>
|
||||
<NcAppSettingsSection :name="strings.musicLibrarySettings">
|
||||
<div class="folder-select-wrapper">
|
||||
|
||||
<div class="input-with-button">
|
||||
<NcTextField
|
||||
<NcTextField
|
||||
v-model="musicFolder"
|
||||
:label="strings.musicFolderLabel"
|
||||
:placeholder="strings.musicFolderPlaceholder"
|
||||
:disabled="true"
|
||||
/> <NcButton
|
||||
:disabled="true" />
|
||||
<NcButton
|
||||
@click="openFolderPicker"
|
||||
icon="icon-folder"
|
||||
:aria-label="strings.pickFolder"
|
||||
:title="strings.pickFolder"
|
||||
:disabled="loading"
|
||||
class="folder-button"
|
||||
>{{ strings.pickFolder }}</NcButton
|
||||
>
|
||||
class="folder-button">
|
||||
{{ strings.pickFolder }}
|
||||
</NcButton>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</NcAppSettingsSection
|
||||
>
|
||||
</NcAppSettingsSection>
|
||||
<div class="submit-buttons">
|
||||
<NcButton type="submit" :disabled="loading">{{ strings.save }}</NcButton
|
||||
>
|
||||
<NcButton type="submit" :disabled="loading">{{ strings.save }}</NcButton>
|
||||
</div>
|
||||
|
||||
</form>
|
||||
|
||||
</div>
|
||||
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import NcAppSettingsSection from '@nextcloud/vue/components/NcAppSettingsSection'
|
||||
import NcTextField from '@nextcloud/vue/components/NcTextField'
|
||||
import NcButton from '@nextcloud/vue/components/NcButton'
|
||||
import { settingsAxios } from './axios'
|
||||
import { t } from '@nextcloud/l10n'
|
||||
import { getFilePickerBuilder } from '@nextcloud/dialogs'
|
||||
import '@nextcloud/dialogs/style.css'
|
||||
import NcAppSettingsSection from '@nextcloud/vue/components/NcAppSettingsSection'
|
||||
import NcTextField from '@nextcloud/vue/components/NcTextField'
|
||||
import NcButton from '@nextcloud/vue/components/NcButton'
|
||||
import { settingsAxios } from './axios'
|
||||
import { t } from '@nextcloud/l10n'
|
||||
import { getFilePickerBuilder } from '@nextcloud/dialogs'
|
||||
import '@nextcloud/dialogs/style.css'
|
||||
|
||||
export default {
|
||||
name: 'JukeboxUserSettings',
|
||||
components: {
|
||||
NcAppSettingsSection,
|
||||
NcTextField,
|
||||
NcButton,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
loading: false,
|
||||
musicFolder: '',
|
||||
strings: {
|
||||
header: t('jukebox', 'Jukebox'),
|
||||
musicLibrarySettings: t('jukebox', 'Music Library'),
|
||||
musicFolderLabel: t('jukebox', 'Music Folder Path'),
|
||||
musicFolderPlaceholder: t('jukebox', 'e.g. Music'),
|
||||
pickFolder: t('jukebox', 'Pick a folder'),
|
||||
save: t('jukebox', 'Save'),
|
||||
},
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.fetchSettings()
|
||||
},
|
||||
methods: {
|
||||
async fetchSettings() {
|
||||
this.loading = true
|
||||
try {
|
||||
const response = await settingsAxios.get('/settings')
|
||||
const data = response.data.ocs.data
|
||||
this.musicFolder = data.music_folder_path || ''
|
||||
} catch (e) {
|
||||
console.error('Failed to fetch settings:', e)
|
||||
} finally {
|
||||
this.loading = false
|
||||
export default {
|
||||
name: 'JukeboxUserSettings',
|
||||
components: {
|
||||
NcAppSettingsSection,
|
||||
NcTextField,
|
||||
NcButton,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
loading: false,
|
||||
musicFolder: '',
|
||||
strings: {
|
||||
header: t('jukebox', 'Jukebox'),
|
||||
musicLibrarySettings: t('jukebox', 'Music Library'),
|
||||
musicFolderLabel: t('jukebox', 'Music Folder Path'),
|
||||
musicFolderPlaceholder: t('jukebox', 'e.g. Music'),
|
||||
pickFolder: t('jukebox', 'Pick a folder'),
|
||||
save: t('jukebox', 'Save'),
|
||||
},
|
||||
}
|
||||
},
|
||||
async save() {
|
||||
this.loading = true
|
||||
try {
|
||||
const data = {
|
||||
music_folder_path: this.musicFolder,
|
||||
created() {
|
||||
this.fetchSettings()
|
||||
},
|
||||
methods: {
|
||||
async fetchSettings() {
|
||||
this.loading = true
|
||||
try {
|
||||
const response = await settingsAxios.get('/settings')
|
||||
const data = response.data.ocs.data
|
||||
this.musicFolder = data.music_folder_path || ''
|
||||
} catch (e) {
|
||||
console.error('Failed to fetch settings:', e)
|
||||
} finally {
|
||||
this.loading = false
|
||||
}
|
||||
console.log('Saving settings :', data)
|
||||
await settingsAxios.put('/settings', { data })
|
||||
} catch (e) {
|
||||
console.error('Failed to save settings:', e)
|
||||
} finally {
|
||||
this.loading = false
|
||||
}
|
||||
},
|
||||
async openFolderPicker() {
|
||||
try {
|
||||
const picker = getFilePickerBuilder(this.strings.musicFolderLabel)
|
||||
.allowDirectories(true)
|
||||
.addButton({
|
||||
label: t('jukebox', 'Select'),
|
||||
callback: (nodes) => {
|
||||
console.log('Selected nodes:', nodes)
|
||||
const node = nodes?.[0]
|
||||
if (!node || !node._data?.root || !node._data?.attributes?.filename) return
|
||||
const root = node._data.root
|
||||
const fullPath = node._data.attributes.filename
|
||||
this.musicFolder = fullPath.startsWith(root)
|
||||
? fullPath.slice(root.length) || '/'
|
||||
: fullPath
|
||||
if (this.musicFolder.startsWith('/')) {
|
||||
this.musicFolder = this.musicFolder.slice(1)
|
||||
}
|
||||
console.log('Selected folder path:', this.musicFolder)
|
||||
},
|
||||
})
|
||||
.build()
|
||||
},
|
||||
async save() {
|
||||
this.loading = true
|
||||
try {
|
||||
const data = {
|
||||
music_folder_path: this.musicFolder,
|
||||
}
|
||||
console.log('Saving settings :', data)
|
||||
await settingsAxios.put('/settings', { data })
|
||||
} catch (e) {
|
||||
console.error('Failed to save settings:', e)
|
||||
} finally {
|
||||
this.loading = false
|
||||
}
|
||||
},
|
||||
async openFolderPicker() {
|
||||
try {
|
||||
const picker = getFilePickerBuilder(this.strings.musicFolderLabel)
|
||||
.allowDirectories(true)
|
||||
.addButton({
|
||||
label: t('jukebox', 'Select'),
|
||||
callback: (nodes) => {
|
||||
console.log('Selected nodes:', nodes)
|
||||
const node = nodes?.[0]
|
||||
if (!node || !node._data?.root || !node._data?.attributes?.filename) return
|
||||
const root = node._data.root
|
||||
const fullPath = node._data.attributes.filename
|
||||
this.musicFolder = fullPath.startsWith(root)
|
||||
? fullPath.slice(root.length) || '/'
|
||||
: fullPath
|
||||
if (this.musicFolder.startsWith('/')) {
|
||||
this.musicFolder = this.musicFolder.slice(1)
|
||||
}
|
||||
console.log('Selected folder path:', this.musicFolder)
|
||||
},
|
||||
})
|
||||
.build()
|
||||
|
||||
await picker.pick()
|
||||
} catch (e) {
|
||||
if (e.message.includes('No nodes selected')) return
|
||||
console.error('Failed to open folder picker:', e)
|
||||
}
|
||||
await picker.pick()
|
||||
} catch (e) {
|
||||
if (e.message.includes('No nodes selected')) return
|
||||
console.error('Failed to open folder picker:', e)
|
||||
}
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
#jukebox-user-settings {
|
||||
#jukebox-user-settings {
|
||||
h2 {
|
||||
margin-top: 0;
|
||||
}
|
||||
@@ -154,4 +143,3 @@ export default {
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
|
||||
@@ -1,22 +1,18 @@
|
||||
<template>
|
||||
|
||||
<div>
|
||||
|
||||
<h3>Track List</h3>
|
||||
<!-- We’ll populate this with real data later -->
|
||||
<!-- We’ll populate this with real data later -->
|
||||
</div>
|
||||
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
export default {
|
||||
name: 'TracksView',
|
||||
}
|
||||
export default {
|
||||
name: 'TracksView',
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
h3 {
|
||||
h3 {
|
||||
text-align: center;
|
||||
}
|
||||
</style>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user