chore(frontend): ESLint dla Vue i TypeScriptu
Konfiguracja we flat configu: zalecane zestawy js, typescript-eslint oraz eslint-plugin-vue. Bloki <script setup lang="ts"> obsługuje vue-eslint-parser przekazujący zawartość do parsera TypeScriptu. Odstępstwa od domyślnych reguł: - vue/multi-word-component-names wyłączone - kafelki panelu mają nazwy własne i nie każda jest dwuczłonowa - no-unused-vars przepuszcza nazwy z prefiksem podkreślenia - no-console wyłączone dla testu dymnego, który raportuje wynik na stdout Szablony przepuszczone przez eslint --fix, co ujednoliciło łamanie atrybutów i domykanie znaczników. Po zmianach kontrola typów, build i test dymny nadal przechodzą. Dochodzą skrypty npm: lint (z --max-warnings 0) oraz lint:fix. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
1 parent
1b5ce2109b
commit
105f3e6c6a
17 files changed
+1682
-84
No files matched your search
@@ -0,0 +1,51 @@
|
||||
import js from '@eslint/js'
|
||||
import globals from 'globals'
|
||||
import ts from 'typescript-eslint'
|
||||
import vue from 'eslint-plugin-vue'
|
||||
|
||||
// Kolejność ma znaczenie: w flat config późniejszy wpis nadpisuje wcześniejszy,
|
||||
// więc wyjątki od reguł muszą stać za blokiem, który te reguły ustawia.
|
||||
export default ts.config(
|
||||
{ ignores: ['dist/**', 'node_modules/**'] },
|
||||
|
||||
js.configs.recommended,
|
||||
ts.configs.recommended,
|
||||
vue.configs['flat/recommended'],
|
||||
|
||||
{
|
||||
// Pliki .vue parsuje vue-eslint-parser, a bloki <script setup lang="ts">
|
||||
// przekazuje dalej do parsera TypeScriptu.
|
||||
files: ['**/*.vue'],
|
||||
languageOptions: {
|
||||
parserOptions: { parser: ts.parser },
|
||||
},
|
||||
},
|
||||
|
||||
{
|
||||
files: ['src/**/*.{ts,vue}'],
|
||||
languageOptions: { globals: globals.browser },
|
||||
},
|
||||
|
||||
{
|
||||
files: ['*.mjs', '*.ts'],
|
||||
languageOptions: { globals: globals.node },
|
||||
},
|
||||
|
||||
{
|
||||
rules: {
|
||||
// Kafelki panelu mają nazwy własne, nie zawsze dwuczłonowe.
|
||||
'vue/multi-word-component-names': 'off',
|
||||
'no-console': ['warn', { allow: ['warn', 'error'] }],
|
||||
'@typescript-eslint/no-unused-vars': [
|
||||
'error',
|
||||
{ argsIgnorePattern: '^_', varsIgnorePattern: '^_' },
|
||||
],
|
||||
},
|
||||
},
|
||||
|
||||
{
|
||||
// Test dymny raportuje wynik na stdout - to jego zadanie, nie zapomniany debug.
|
||||
files: ['smoke-test.mjs'],
|
||||
rules: { 'no-console': 'off' },
|
||||
},
|
||||
)
|
||||
Generated
+1286
File diff suppressed because it is too large.
Load diff
@@ -8,6 +8,8 @@
|
||||
"dev": "vite",
|
||||
"build": "vue-tsc --noEmit && vite build",
|
||||
"preview": "vite preview",
|
||||
"lint": "eslint . --max-warnings 0",
|
||||
"lint:fix": "eslint . --fix",
|
||||
"typecheck": "vue-tsc --noEmit",
|
||||
"smoke": "node smoke-test.mjs"
|
||||
},
|
||||
@@ -16,11 +18,17 @@
|
||||
"vue": "^3.5.41"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@eslint/js": "^10.0.1",
|
||||
"@types/node": "^26.2.0",
|
||||
"@vitejs/plugin-vue": "^6.0.8",
|
||||
"eslint": "^10.8.1",
|
||||
"eslint-plugin-vue": "^10.10.0",
|
||||
"globals": "^17.11.0",
|
||||
"jsdom": "^30.0.1",
|
||||
"typescript": "^5.9.3",
|
||||
"typescript-eslint": "^8.67.0",
|
||||
"vite": "^8.2.2",
|
||||
"vue-eslint-parser": "^10.4.1",
|
||||
"vue-tsc": "^3.3.10"
|
||||
}
|
||||
}
|
||||
+20
-6
@@ -26,11 +26,14 @@ onMounted(() => {
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="background-glow bg-glow-1"></div>
|
||||
<div class="background-glow bg-glow-2"></div>
|
||||
<div class="background-glow bg-glow-1" />
|
||||
<div class="background-glow bg-glow-2" />
|
||||
|
||||
<div class="app-container">
|
||||
<AppHeader :status="status" @open-settings="settingsOpen = true" />
|
||||
<AppHeader
|
||||
:status="status"
|
||||
@open-settings="settingsOpen = true"
|
||||
/>
|
||||
|
||||
<main class="dashboard-grid">
|
||||
<section class="grid-column left-column">
|
||||
@@ -40,15 +43,26 @@ onMounted(() => {
|
||||
|
||||
<section class="grid-column right-column">
|
||||
<AddTrackPanel :status="status" />
|
||||
<UploadsPanel :status="status" @open-library="libraryOpen = true" />
|
||||
<UploadsPanel
|
||||
:status="status"
|
||||
@open-library="libraryOpen = true"
|
||||
/>
|
||||
<QueuePanel :status="status" />
|
||||
<HistoryPanel :status="status" />
|
||||
</section>
|
||||
</main>
|
||||
</div>
|
||||
|
||||
<SettingsModal v-if="settingsOpen" :status="status" @close="settingsOpen = false" />
|
||||
<UploadsLibraryModal v-if="libraryOpen" :status="status" @close="libraryOpen = false" />
|
||||
<SettingsModal
|
||||
v-if="settingsOpen"
|
||||
:status="status"
|
||||
@close="settingsOpen = false"
|
||||
/>
|
||||
<UploadsLibraryModal
|
||||
v-if="libraryOpen"
|
||||
:status="status"
|
||||
@close="libraryOpen = false"
|
||||
/>
|
||||
|
||||
<ToastHost />
|
||||
</template>
|
||||
@@ -29,8 +29,13 @@ async function submit() {
|
||||
|
||||
<template>
|
||||
<div class="glass-card add-track-panel">
|
||||
<h2 class="card-title"><PlusCircle /> Dodaj do kolejki</h2>
|
||||
<form class="add-form" @submit.prevent="submit">
|
||||
<h2 class="card-title">
|
||||
<PlusCircle /> Dodaj do kolejki
|
||||
</h2>
|
||||
<form
|
||||
class="add-form"
|
||||
@submit.prevent="submit"
|
||||
>
|
||||
<div class="input-with-icon">
|
||||
<Search class="input-icon" />
|
||||
<input
|
||||
@@ -40,10 +45,17 @@ async function submit() {
|
||||
placeholder="Wklej link YouTube lub wpisz wyszukiwanie..."
|
||||
:disabled="busy"
|
||||
required
|
||||
/>
|
||||
>
|
||||
</div>
|
||||
<button type="submit" class="btn btn-primary" :disabled="busy">
|
||||
<span v-if="busy" class="spinner"></span>
|
||||
<button
|
||||
type="submit"
|
||||
class="btn btn-primary"
|
||||
:disabled="busy"
|
||||
>
|
||||
<span
|
||||
v-if="busy"
|
||||
class="spinner"
|
||||
/>
|
||||
<span v-else><Plus /> Dodaj</span>
|
||||
</button>
|
||||
</form>
|
||||
|
||||
@@ -18,7 +18,9 @@ const label = computed(() =>
|
||||
<template>
|
||||
<header class="main-header">
|
||||
<div class="logo-area">
|
||||
<div class="logo-icon"><Music /></div>
|
||||
<div class="logo-icon">
|
||||
<Music />
|
||||
</div>
|
||||
<div class="logo-text">
|
||||
<h1>ŻyrarBOT</h1>
|
||||
<span class="subtitle">Kontroler Web</span>
|
||||
@@ -26,11 +28,17 @@ const label = computed(() =>
|
||||
</div>
|
||||
|
||||
<div class="header-actions">
|
||||
<button class="btn btn-secondary" @click="$emit('openSettings')">
|
||||
<button
|
||||
class="btn btn-secondary"
|
||||
@click="$emit('openSettings')"
|
||||
>
|
||||
<Settings /> Ustawienia
|
||||
</button>
|
||||
<div class="bot-status-badge">
|
||||
<span class="status-indicator" :class="activeChannel ? 'online' : 'offline'"></span>
|
||||
<span
|
||||
class="status-indicator"
|
||||
:class="activeChannel ? 'online' : 'offline'"
|
||||
/>
|
||||
<span>{{ label }}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -37,19 +37,34 @@ async function replay(entry: HistoryTrack) {
|
||||
<template>
|
||||
<div class="glass-card history-panel">
|
||||
<div class="queue-header">
|
||||
<h2 class="card-title"><History /> Historia odtwarzania</h2>
|
||||
<h2 class="card-title">
|
||||
<History /> Historia odtwarzania
|
||||
</h2>
|
||||
<span class="queue-count">{{ tracksLabel(history.length) }}</span>
|
||||
</div>
|
||||
|
||||
<div class="queue-list-container list-short">
|
||||
<ul class="queue-list">
|
||||
<li v-for="entry in history" :key="entry.id" class="queue-item">
|
||||
<div class="queue-index"><RotateCcw /></div>
|
||||
<li
|
||||
v-for="entry in history"
|
||||
:key="entry.id"
|
||||
class="queue-item"
|
||||
>
|
||||
<div class="queue-index">
|
||||
<RotateCcw />
|
||||
</div>
|
||||
<div class="queue-track-info">
|
||||
<div class="queue-track-title" :title="entry.title">{{ entry.title }}</div>
|
||||
<div
|
||||
class="queue-track-title"
|
||||
:title="entry.title"
|
||||
>
|
||||
{{ entry.title }}
|
||||
</div>
|
||||
<div class="queue-track-meta">
|
||||
{{ entry.duration ? formatTime(entry.duration) : '--:--' }}
|
||||
<template v-if="entry.is_local"> • plik lokalny</template>
|
||||
<template v-if="entry.is_local">
|
||||
• plik lokalny
|
||||
</template>
|
||||
</div>
|
||||
</div>
|
||||
<div class="queue-item-actions">
|
||||
@@ -63,7 +78,10 @@ async function replay(entry: HistoryTrack) {
|
||||
</div>
|
||||
</li>
|
||||
|
||||
<div v-if="!history.length" class="empty-queue-message">
|
||||
<div
|
||||
v-if="!history.length"
|
||||
class="empty-queue-message"
|
||||
>
|
||||
<Clock />
|
||||
<p>Historia odtwarzania jest pusta.</p>
|
||||
</div>
|
||||
|
||||
@@ -14,11 +14,25 @@ onUnmounted(() => window.removeEventListener('keydown', onKeydown))
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="modal-overlay" @click.self="$emit('close')">
|
||||
<div class="modal-card glass-card" :class="{ wide }">
|
||||
<div
|
||||
class="modal-overlay"
|
||||
@click.self="$emit('close')"
|
||||
>
|
||||
<div
|
||||
class="modal-card glass-card"
|
||||
:class="{ wide }"
|
||||
>
|
||||
<div class="modal-header">
|
||||
<h2 class="card-title"><slot name="title" /></h2>
|
||||
<button class="btn-icon" title="Zamknij" @click="$emit('close')"><X /></button>
|
||||
<h2 class="card-title">
|
||||
<slot name="title" />
|
||||
</h2>
|
||||
<button
|
||||
class="btn-icon"
|
||||
title="Zamknij"
|
||||
@click="$emit('close')"
|
||||
>
|
||||
<X />
|
||||
</button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<slot />
|
||||
|
||||
@@ -106,43 +106,74 @@ async function cycleLoop() {
|
||||
</div>
|
||||
|
||||
<div class="visualizer-container">
|
||||
<div class="vinyl-record" :class="{ playing }">
|
||||
<div class="vinyl-center"></div>
|
||||
<div class="vinyl-grooves"></div>
|
||||
<div class="vinyl-glow"></div>
|
||||
<div class="vinyl-icon"><Music4 /></div>
|
||||
<div
|
||||
class="vinyl-record"
|
||||
:class="{ playing }"
|
||||
>
|
||||
<div class="vinyl-center" />
|
||||
<div class="vinyl-grooves" />
|
||||
<div class="vinyl-glow" />
|
||||
<div class="vinyl-icon">
|
||||
<Music4 />
|
||||
</div>
|
||||
</div>
|
||||
<div class="music-wave" :class="{ active: playing }">
|
||||
<span v-for="bar in 5" :key="bar"></span>
|
||||
<div
|
||||
class="music-wave"
|
||||
:class="{ active: playing }"
|
||||
>
|
||||
<span
|
||||
v-for="bar in 5"
|
||||
:key="bar"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="now-playing-info">
|
||||
<h3 class="track-title">{{ current?.title ?? 'Nic nie jest odtwarzane' }}</h3>
|
||||
<h3 class="track-title">
|
||||
{{ current?.title ?? 'Nic nie jest odtwarzane' }}
|
||||
</h3>
|
||||
<p class="track-artist">
|
||||
{{ current ? (current.url ? 'Źródło: YouTube' : 'Źródło: plik lokalny') : 'Połącz bota i dodaj utwór' }}
|
||||
</p>
|
||||
<a v-if="current?.url" :href="current.url" target="_blank" class="track-link-btn">
|
||||
<a
|
||||
v-if="current?.url"
|
||||
:href="current.url"
|
||||
target="_blank"
|
||||
class="track-link-btn"
|
||||
>
|
||||
<ExternalLink /> Otwórz w YouTube
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<div v-if="current" class="track-progress-container">
|
||||
<div
|
||||
v-if="current"
|
||||
class="track-progress-container"
|
||||
>
|
||||
<span class="time-text">{{ formatTime(elapsed) }}</span>
|
||||
<div class="progress-bar-bg">
|
||||
<div class="progress-bar-fill" :style="{ width: `${percent}%` }"></div>
|
||||
<div
|
||||
class="progress-bar-fill"
|
||||
:style="{ width: `${percent}%` }"
|
||||
/>
|
||||
</div>
|
||||
<span class="time-text">{{ duration > 0 ? formatTime(duration) : 'Live' }}</span>
|
||||
</div>
|
||||
|
||||
<div class="playback-state-bar">
|
||||
<span v-if="loopButton.badge" class="badge">
|
||||
<span
|
||||
v-if="loopButton.badge"
|
||||
class="badge"
|
||||
>
|
||||
<component :is="loopButton.icon" /> {{ loopButton.badge }}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div class="player-controls">
|
||||
<button class="btn-icon btn-secondary" title="Zatrzymaj i wyczyść" @click="stop">
|
||||
<button
|
||||
class="btn-icon btn-secondary"
|
||||
title="Zatrzymaj i wyczyść"
|
||||
@click="stop"
|
||||
>
|
||||
<Square />
|
||||
</button>
|
||||
<button
|
||||
@@ -152,7 +183,11 @@ async function cycleLoop() {
|
||||
>
|
||||
<component :is="playing ? Pause : Play" />
|
||||
</button>
|
||||
<button class="btn-icon btn-secondary" title="Pomiń utwór" @click="skip">
|
||||
<button
|
||||
class="btn-icon btn-secondary"
|
||||
title="Pomiń utwór"
|
||||
@click="skip"
|
||||
>
|
||||
<SkipForward />
|
||||
</button>
|
||||
<button
|
||||
@@ -166,7 +201,12 @@ async function cycleLoop() {
|
||||
</div>
|
||||
|
||||
<div class="volume-container">
|
||||
<button class="btn-icon-small" title="Głośność"><component :is="volumeIcon" /></button>
|
||||
<button
|
||||
class="btn-icon-small"
|
||||
title="Głośność"
|
||||
>
|
||||
<component :is="volumeIcon" />
|
||||
</button>
|
||||
<input
|
||||
type="range"
|
||||
class="premium-slider"
|
||||
@@ -175,7 +215,7 @@ async function cycleLoop() {
|
||||
:value="volume"
|
||||
@input="onVolumeInput"
|
||||
@change="commitVolume"
|
||||
/>
|
||||
>
|
||||
<span class="volume-value">{{ volume }}%</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -62,20 +62,48 @@ function commit() {
|
||||
}"
|
||||
draggable="true"
|
||||
>
|
||||
<div class="drag-handle" title="Przeciągnij, aby zmienić kolejność"><GripVertical /></div>
|
||||
<div
|
||||
class="drag-handle"
|
||||
title="Przeciągnij, aby zmienić kolejność"
|
||||
>
|
||||
<GripVertical />
|
||||
</div>
|
||||
|
||||
<div v-if="index === queueIndex" class="queue-index" title="Aktualnie odtwarzane">
|
||||
<div
|
||||
v-if="index === queueIndex"
|
||||
class="queue-index"
|
||||
title="Aktualnie odtwarzane"
|
||||
>
|
||||
<Volume2 class="playing-icon" />
|
||||
</div>
|
||||
<div v-else class="queue-index">{{ index + 1 }}</div>
|
||||
<div
|
||||
v-else
|
||||
class="queue-index"
|
||||
>
|
||||
{{ index + 1 }}
|
||||
</div>
|
||||
|
||||
<div class="queue-track-info">
|
||||
<div class="queue-track-title" :title="track.title">{{ track.title }}</div>
|
||||
<div
|
||||
class="queue-track-title"
|
||||
:title="track.title"
|
||||
>
|
||||
{{ track.title }}
|
||||
</div>
|
||||
|
||||
<div class="track-plays-control">
|
||||
<Repeat class="plays-icon" />
|
||||
<span class="plays-label" title="Pozostało odtworzeń z kolejki">Pozostało:</span>
|
||||
<button class="btn-tiny-action" title="Zmniejsz o 1" @click="step(-1)"><Minus /></button>
|
||||
<span
|
||||
class="plays-label"
|
||||
title="Pozostało odtworzeń z kolejki"
|
||||
>Pozostało:</span>
|
||||
<button
|
||||
class="btn-tiny-action"
|
||||
title="Zmniejsz o 1"
|
||||
@click="step(-1)"
|
||||
>
|
||||
<Minus />
|
||||
</button>
|
||||
<input
|
||||
v-model.number="plays"
|
||||
type="number"
|
||||
@@ -85,22 +113,44 @@ function commit() {
|
||||
@focus="editing = true"
|
||||
@blur="commit"
|
||||
@keyup.enter="($event.target as HTMLInputElement).blur()"
|
||||
/>
|
||||
<button class="btn-tiny-action" title="Zwiększ o 1" @click="step(1)"><Plus /></button>
|
||||
>
|
||||
<button
|
||||
class="btn-tiny-action"
|
||||
title="Zwiększ o 1"
|
||||
@click="step(1)"
|
||||
>
|
||||
<Plus />
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="queue-item-actions">
|
||||
<button class="btn-action-icon" title="Odtwarzaj od tej pozycji" @click="$emit('jump', index)">
|
||||
<button
|
||||
class="btn-action-icon"
|
||||
title="Odtwarzaj od tej pozycji"
|
||||
@click="$emit('jump', index)"
|
||||
>
|
||||
<Play />
|
||||
</button>
|
||||
<button class="btn-action-icon" title="Przesuń w górę" @click="$emit('moveUp', index)">
|
||||
<button
|
||||
class="btn-action-icon"
|
||||
title="Przesuń w górę"
|
||||
@click="$emit('moveUp', index)"
|
||||
>
|
||||
<ArrowUp />
|
||||
</button>
|
||||
<button class="btn-action-icon" title="Przesuń w dół" @click="$emit('moveDown', index)">
|
||||
<button
|
||||
class="btn-action-icon"
|
||||
title="Przesuń w dół"
|
||||
@click="$emit('moveDown', index)"
|
||||
>
|
||||
<ArrowDown />
|
||||
</button>
|
||||
<button class="btn-action-icon delete" title="Usuń z kolejki" @click="$emit('remove', track.id)">
|
||||
<button
|
||||
class="btn-action-icon delete"
|
||||
title="Usuń z kolejki"
|
||||
@click="$emit('remove', track.id)"
|
||||
>
|
||||
<Trash2 />
|
||||
</button>
|
||||
</div>
|
||||
|
||||
@@ -78,7 +78,9 @@ const warnInvalidPlays = () => notify('Wartość musi być z przedziału 1-999',
|
||||
<template>
|
||||
<div class="glass-card queue-panel">
|
||||
<div class="queue-header">
|
||||
<h2 class="card-title"><ListMusic /> Kolejka odtwarzania</h2>
|
||||
<h2 class="card-title">
|
||||
<ListMusic /> Kolejka odtwarzania
|
||||
</h2>
|
||||
<span class="queue-count">{{ tracksLabel(queue.length) }}</span>
|
||||
</div>
|
||||
|
||||
@@ -105,7 +107,10 @@ const warnInvalidPlays = () => notify('Wartość musi być z przedziału 1-999',
|
||||
@set-plays="setPlays"
|
||||
@invalid-plays="warnInvalidPlays"
|
||||
/>
|
||||
<div v-if="!queue.length" class="empty-queue-message">
|
||||
<div
|
||||
v-if="!queue.length"
|
||||
class="empty-queue-message"
|
||||
>
|
||||
<Disc />
|
||||
<p>Kolejka jest pusta. Dodaj coś!</p>
|
||||
</div>
|
||||
|
||||
@@ -50,7 +50,9 @@ const saveLogChannel = (guildId: string, channelId: string) =>
|
||||
|
||||
<template>
|
||||
<ModalShell @close="$emit('close')">
|
||||
<template #title><Settings /> Ustawienia ŻyrarBOT</template>
|
||||
<template #title>
|
||||
<Settings /> Ustawienia ŻyrarBOT
|
||||
</template>
|
||||
|
||||
<section class="settings-section divided">
|
||||
<h3><Repeat /> Domyślna liczba odtworzeń w kolejce</h3>
|
||||
@@ -68,8 +70,13 @@ const saveLogChannel = (guildId: string, channelId: string) =>
|
||||
:max="MAX_PLAYS"
|
||||
@focus="editing = true"
|
||||
@blur="editing = false"
|
||||
/>
|
||||
<button class="btn btn-primary" @click="saveDefaultPlays"><Save /> Zapisz</button>
|
||||
>
|
||||
<button
|
||||
class="btn btn-primary"
|
||||
@click="saveDefaultPlays"
|
||||
>
|
||||
<Save /> Zapisz
|
||||
</button>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
@@ -81,12 +88,22 @@ const saveLogChannel = (guildId: string, channelId: string) =>
|
||||
</p>
|
||||
|
||||
<div class="guilds-list">
|
||||
<div v-for="guild in guilds" :key="guild.guild_id" class="guild-setting-row glass-card-subtle">
|
||||
<div
|
||||
v-for="guild in guilds"
|
||||
:key="guild.guild_id"
|
||||
class="guild-setting-row glass-card-subtle"
|
||||
>
|
||||
<div class="guild-info">
|
||||
<div class="guild-icon"><Shield /></div>
|
||||
<div class="guild-icon">
|
||||
<Shield />
|
||||
</div>
|
||||
<div>
|
||||
<div class="guild-name">{{ guild.guild_name }}</div>
|
||||
<div class="guild-id">ID: {{ guild.guild_id }}</div>
|
||||
<div class="guild-name">
|
||||
{{ guild.guild_name }}
|
||||
</div>
|
||||
<div class="guild-id">
|
||||
ID: {{ guild.guild_id }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="guild-control">
|
||||
@@ -95,7 +112,9 @@ const saveLogChannel = (guildId: string, channelId: string) =>
|
||||
:value="guild.active_notification_channel_id ?? ''"
|
||||
@change="saveLogChannel(guild.guild_id, ($event.target as HTMLSelectElement).value)"
|
||||
>
|
||||
<option value="">-- Brak / Domyślny --</option>
|
||||
<option value="">
|
||||
-- Brak / Domyślny --
|
||||
</option>
|
||||
<option
|
||||
v-for="channel in guild.text_channels"
|
||||
:key="channel.channel_id"
|
||||
@@ -107,7 +126,10 @@ const saveLogChannel = (guildId: string, channelId: string) =>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div v-if="!guilds.length" class="empty-queue-message">
|
||||
<div
|
||||
v-if="!guilds.length"
|
||||
class="empty-queue-message"
|
||||
>
|
||||
<Server />
|
||||
<p>Brak serwerów Discord w pamięci bota.</p>
|
||||
</div>
|
||||
|
||||
@@ -14,7 +14,12 @@ const icons = {
|
||||
<template>
|
||||
<div class="toast-container">
|
||||
<TransitionGroup name="toast">
|
||||
<div v-for="toast in toasts" :key="toast.id" class="toast" :class="toast.type">
|
||||
<div
|
||||
v-for="toast in toasts"
|
||||
:key="toast.id"
|
||||
class="toast"
|
||||
:class="toast.type"
|
||||
>
|
||||
<component :is="icons[toast.type]" />
|
||||
<span>{{ toast.message }}</span>
|
||||
</div>
|
||||
|
||||
@@ -8,16 +8,33 @@ defineEmits<{ enqueue: [filename: string]; remove: [filename: string] }>()
|
||||
|
||||
<template>
|
||||
<li class="queue-item">
|
||||
<div class="queue-index"><FileAudio /></div>
|
||||
<div class="queue-index">
|
||||
<FileAudio />
|
||||
</div>
|
||||
<div class="queue-track-info">
|
||||
<div class="queue-track-title" :title="file.filename">{{ file.filename }}</div>
|
||||
<div class="queue-track-meta">{{ file.size_mb }} MB</div>
|
||||
<div
|
||||
class="queue-track-title"
|
||||
:title="file.filename"
|
||||
>
|
||||
{{ file.filename }}
|
||||
</div>
|
||||
<div class="queue-track-meta">
|
||||
{{ file.size_mb }} MB
|
||||
</div>
|
||||
</div>
|
||||
<div class="queue-item-actions">
|
||||
<button class="btn btn-primary btn-compact" title="Dodaj do kolejki" @click="$emit('enqueue', file.filename)">
|
||||
<button
|
||||
class="btn btn-primary btn-compact"
|
||||
title="Dodaj do kolejki"
|
||||
@click="$emit('enqueue', file.filename)"
|
||||
>
|
||||
<Plus /> Dodaj
|
||||
</button>
|
||||
<button class="btn-action-icon delete" title="Usuń z serwera" @click="$emit('remove', file.filename)">
|
||||
<button
|
||||
class="btn-action-icon delete"
|
||||
title="Usuń z serwera"
|
||||
@click="$emit('remove', file.filename)"
|
||||
>
|
||||
<Trash2 />
|
||||
</button>
|
||||
</div>
|
||||
|
||||
@@ -22,8 +22,13 @@ function play(filename: string) {
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<ModalShell wide @close="$emit('close')">
|
||||
<template #title><FolderUp /> Wszystkie pliki na serwerze</template>
|
||||
<ModalShell
|
||||
wide
|
||||
@close="$emit('close')"
|
||||
>
|
||||
<template #title>
|
||||
<FolderUp /> Wszystkie pliki na serwerze
|
||||
</template>
|
||||
|
||||
<p class="settings-desc">
|
||||
Pełna lista plików zapisanych w serwerowej bazie danych (posortowana od ostatnio używanych /
|
||||
@@ -38,7 +43,10 @@ function play(filename: string) {
|
||||
@enqueue="play"
|
||||
@remove="remove"
|
||||
/>
|
||||
<div v-if="!files.length" class="empty-queue-message">
|
||||
<div
|
||||
v-if="!files.length"
|
||||
class="empty-queue-message"
|
||||
>
|
||||
<FolderOpen />
|
||||
<p>Brak przesłanych plików na serwerze.</p>
|
||||
</div>
|
||||
|
||||
@@ -34,18 +34,33 @@ function play(filename: string) {
|
||||
<template>
|
||||
<div class="glass-card uploads-panel">
|
||||
<div class="queue-header">
|
||||
<h2 class="card-title"><FolderUp /> Serwerowa baza plików</h2>
|
||||
<h2 class="card-title">
|
||||
<FolderUp /> Serwerowa baza plików
|
||||
</h2>
|
||||
<span class="queue-count">{{ filesLabel(files.length) }}</span>
|
||||
</div>
|
||||
|
||||
<div class="upload-area">
|
||||
<input ref="fileInput" type="file" hidden multiple @change="onFilesPicked" />
|
||||
<button class="btn btn-secondary btn-block" :disabled="uploading" @click="fileInput?.click()">
|
||||
<input
|
||||
ref="fileInput"
|
||||
type="file"
|
||||
hidden
|
||||
multiple
|
||||
@change="onFilesPicked"
|
||||
>
|
||||
<button
|
||||
class="btn btn-secondary btn-block"
|
||||
:disabled="uploading"
|
||||
@click="fileInput?.click()"
|
||||
>
|
||||
<UploadCloud /> Prześlij plik wideo/audio na serwer
|
||||
</button>
|
||||
<div v-if="uploading" class="upload-progress">
|
||||
<div
|
||||
v-if="uploading"
|
||||
class="upload-progress"
|
||||
>
|
||||
<div class="progress-bar-bg">
|
||||
<div class="progress-bar-fill indeterminate"></div>
|
||||
<div class="progress-bar-fill indeterminate" />
|
||||
</div>
|
||||
<span class="time-text">{{ uploadLabel }}</span>
|
||||
</div>
|
||||
@@ -60,14 +75,20 @@ function play(filename: string) {
|
||||
@enqueue="play"
|
||||
@remove="remove"
|
||||
/>
|
||||
<div v-if="!files.length" class="empty-queue-message">
|
||||
<div
|
||||
v-if="!files.length"
|
||||
class="empty-queue-message"
|
||||
>
|
||||
<FolderOpen />
|
||||
<p>Brak przesłanych plików na serwerze.</p>
|
||||
</div>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<button class="btn btn-secondary btn-block" @click="$emit('openLibrary')">
|
||||
<button
|
||||
class="btn btn-secondary btn-block"
|
||||
@click="$emit('openLibrary')"
|
||||
>
|
||||
<FolderOpen /> Pokaż wszystkie pliki na serwerze ({{ files.length }})
|
||||
</button>
|
||||
</div>
|
||||
|
||||
@@ -41,15 +41,34 @@ async function toggle() {
|
||||
|
||||
<template>
|
||||
<div class="glass-card connection-panel">
|
||||
<h2 class="card-title"><Radio /> Kanał Głosowy</h2>
|
||||
<h2 class="card-title">
|
||||
<Radio /> Kanał Głosowy
|
||||
</h2>
|
||||
<div class="control-row">
|
||||
<select v-model="selected" class="premium-select" :disabled="!channels.length">
|
||||
<option v-if="!channels.length" value="">Brak dostępnych kanałów</option>
|
||||
<option v-for="channel in channels" :key="channel.channel_id" :value="channel.channel_id">
|
||||
<select
|
||||
v-model="selected"
|
||||
class="premium-select"
|
||||
:disabled="!channels.length"
|
||||
>
|
||||
<option
|
||||
v-if="!channels.length"
|
||||
value=""
|
||||
>
|
||||
Brak dostępnych kanałów
|
||||
</option>
|
||||
<option
|
||||
v-for="channel in channels"
|
||||
:key="channel.channel_id"
|
||||
:value="channel.channel_id"
|
||||
>
|
||||
{{ channel.guild_name }} - {{ channel.channel_name }}
|
||||
</option>
|
||||
</select>
|
||||
<button class="btn" :class="active ? 'btn-danger' : 'btn-primary btn-glow'" @click="toggle">
|
||||
<button
|
||||
class="btn"
|
||||
:class="active ? 'btn-danger' : 'btn-primary btn-glow'"
|
||||
@click="toggle"
|
||||
>
|
||||
<component :is="active ? LogOut : LogIn" />
|
||||
{{ active ? 'Odłącz' : 'Połącz' }}
|
||||
</button>
|
||||
|
||||
Reference in new issue
Block a user