Switch between List and Grid view fix #1
This commit is contained in:
@@ -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
@@ -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
@@ -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;
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user