Switch between List and Grid view fix #1

This commit is contained in:
Artem Anufrij
2026-10-08 14:21:43 +02:00
parent 3beb10799d
commit 98bac30c02
3 changed files with 90 additions and 14 deletions
+3
View File
@@ -9,6 +9,9 @@
version="1.1" version="1.1"
inkscape:version="1.4.4 (dcaf3e7d9e, 2026-05-05)" inkscape:version="1.4.4 (dcaf3e7d9e, 2026-05-05)"
sodipodi:docname="icon_64.svg" sodipodi:docname="icon_64.svg"
inkscape:export-filename="icon_192.png"
inkscape:export-xdpi="288"
inkscape:export-ydpi="288"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:xlink="http://www.w3.org/1999/xlink"

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 12 KiB

+47 -6
View File
@@ -1,11 +1,15 @@
<script setup> <script setup>
import { ref, computed, onBeforeUnmount } from "vue"; import { ref, computed, onBeforeUnmount } from "vue";
import { FontAwesomeIcon } from "@fortawesome/vue-fontawesome"; import { FontAwesomeIcon } from "@fortawesome/vue-fontawesome";
import { faMinus, faPlus, faPlay, faStop, faTrash, faArrowDown } from "@fortawesome/free-solid-svg-icons"; import { faMinus, faPlus, faPlay, faStop, faTrash, faArrowDown, faList, faGrip, faDownload, faUpload } from "@fortawesome/free-solid-svg-icons";
// App Einstellungen
const view = ref(loadView());
const MIN_BPM = 20; const MIN_BPM = 20;
const MAX_BPM = 300; const MAX_BPM = 300;
const STORAGE_KEY = "ClickPresets" const STORAGE_KEY_PRESETS = "ClickPresets"
const STORAGE_KEY_VIEW = "ClickView"
// Reaktiver Zustand (für die UI) // Reaktiver Zustand (für die UI)
const bpm = ref(120); const bpm = ref(120);
@@ -116,7 +120,7 @@ onBeforeUnmount(() => {
//PRESETS //PRESETS
function loadPresets() { function loadPresets() {
try { try {
const raw = localStorage.getItem(STORAGE_KEY); const raw = localStorage.getItem(STORAGE_KEY_PRESETS);
return raw ? JSON.parse(raw) : []; return raw ? JSON.parse(raw) : [];
} catch (error) { } catch (error) {
console.error("Presets could not be loaded:", error); console.error("Presets could not be loaded:", error);
@@ -129,13 +133,13 @@ function addPreset() {
const preset = { tempo: bpm.value, id: nextId }; const preset = { tempo: bpm.value, id: nextId };
presets.value.push(preset); presets.value.push(preset);
localStorage.setItem(STORAGE_KEY, JSON.stringify(presets.value)); localStorage.setItem(STORAGE_KEY_PRESETS, JSON.stringify(presets.value));
} }
function deletePreset() { function deletePreset() {
presets.value = presets.value.filter(f => f.id != selectedPreset.value.id); presets.value = presets.value.filter(f => f.id != selectedPreset.value.id);
localStorage.setItem(STORAGE_KEY, JSON.stringify(presets.value)); localStorage.setItem(STORAGE_KEY_PRESETS, JSON.stringify(presets.value));
stop(); stop();
selectedPreset = ref(null); selectedPreset = ref(null);
} }
@@ -153,6 +157,24 @@ const sortedPresets = computed(() =>
[...presets.value].sort((a, b) => a.tempo - b.tempo) [...presets.value].sort((a, b) => a.tempo - b.tempo)
); );
// App View
function loadView() {
try {
const raw = localStorage.getItem(STORAGE_KEY_VIEW);
return raw || "grid";
} catch (error) {
console.error("View settings could not be loaded:", error);
return "grid";
}
}
function switchView(val) {
view.value = val;
localStorage.setItem(STORAGE_KEY_VIEW, val);
}
</script> </script>
<template> <template>
@@ -193,7 +215,7 @@ const sortedPresets = computed(() =>
<div id="presets"> <div id="presets">
<h1>Presets</h1> <h1>Presets</h1>
<h2 id="presetsMessage" v-if="presets.length == 0">No Presets defined</h2> <h2 id="presetsMessage" v-if="presets.length == 0">No Presets defined</h2>
<div id="presetsItems"> <div id="presetsItems" :class="{ list: view == 'list', grid: view == 'grid' }">
<button v-for="preset in sortedPresets" :key="preset.id" class="presetItem" :class="{ selected: selectedPreset === preset }" @click="startPreset(preset)"> <button v-for="preset in sortedPresets" :key="preset.id" class="presetItem" :class="{ selected: selectedPreset === preset }" @click="startPreset(preset)">
<h2>{{ preset.tempo }}</h2> <h2>{{ preset.tempo }}</h2>
BPM BPM
@@ -201,4 +223,23 @@ const sortedPresets = computed(() =>
</div> </div>
</div> </div>
</main> </main>
<footer>
<div class="left">
<button>
<font-awesome-icon :icon="faUpload" size="xl" />
</button>
<button>
<font-awesome-icon :icon="faDownload" size="xl" />
</button>
</div>
<div class="grow"></div>
<div class="right">
<button v-if="view == 'grid'" @click="switchView('list')">
<font-awesome-icon :icon="faList" size="xl" />
</button>
<button v-if="view == 'list'" @click="switchView('grid')">
<font-awesome-icon :icon="faGrip" size="xl" />
</button>
</div>
</footer>
</template> </template>
+40 -8
View File
@@ -20,6 +20,19 @@ main {
overflow: auto; overflow: auto;
} }
footer {
display: flex;
border-top-style: solid;
border-top-color: var(--light-gray);
border-top-width: 1px;
}
footer button {
height: 48px;
width: 48px;
background: transparent;
}
body, body,
textarea, textarea,
input, input,
@@ -29,9 +42,7 @@ pre {
} }
body, body,
button, button {
a,
label {
color: var(--dark); color: var(--dark);
} }
@@ -119,21 +130,38 @@ button#stop {
#presetsItems { #presetsItems {
display: flex; display: flex;
justify-content: center; }
#presetsItems.list {
flex-direction: column;
width: stretch;
}
#presetsItems.grid {
align-self: center; align-self: center;
flex-wrap: wrap; flex-wrap: wrap;
justify-content: center;
} }
.presetItem { .presetItem {
min-width: 86px; display: flex;
border-width: 1px; border-width: 1px;
border-color: var(--light-gray); border-color: var(--light-gray);
border-style: solid; border-style: solid;
border-radius: 4px; border-radius: 4px;
margin: 4px;
padding: 4px;
text-align: center;
background-color: var(--white); background-color: var(--white);
margin: 4px;
}
#presetsItems.list .presetItem {
align-items: center;
}
#presetsItems.grid .presetItem {
min-width: 86px;
text-align: center;
flex-direction: column;
} }
.presetItem.selected { .presetItem.selected {
@@ -151,3 +179,7 @@ input[type="number"] {
-moz-appearance: textfield; -moz-appearance: textfield;
appearance: textfield; appearance: textfield;
} }
.grow {
flex-grow: 1;
}