mirror of
https://github.com/Dvorinka/swingmusic-extended.git
synced 2026-06-05 13:03:02 +00:00
normalize context menu using @popperjs
+ normalize context children too + add setting to toggle context children via click or hover + add a select setting component + remove dead teleport code from sidebar tabs wrapper + general clean up
This commit is contained in:
committed by
Mungai Njoroge
parent
4e0837a627
commit
bbe7984e4e
@@ -1,22 +1,8 @@
|
|||||||
<template>
|
<template>
|
||||||
<div
|
<div
|
||||||
class="context-menu rounded shadow-lg"
|
class="context-menu rounded shadow-lg no-select"
|
||||||
ref="contextMenu"
|
ref="contextMenu"
|
||||||
:class="[
|
|
||||||
{ 'context-menu-visible': context.visible },
|
|
||||||
{ 'context-normalizedX': context.normalizedX },
|
|
||||||
{
|
|
||||||
'context-normalizedY': context.normalizedY,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
'context-many-kids': context.hasManyChildren(),
|
|
||||||
},
|
|
||||||
]"
|
|
||||||
id="context-menu"
|
id="context-menu"
|
||||||
:style="{
|
|
||||||
left: context.x + 'px',
|
|
||||||
top: context.y + 'px',
|
|
||||||
}"
|
|
||||||
>
|
>
|
||||||
<ContextItem
|
<ContextItem
|
||||||
class="context-item"
|
class="context-item"
|
||||||
@@ -24,7 +10,8 @@
|
|||||||
:key="option.label"
|
:key="option.label"
|
||||||
:class="[{ critical: option.critical }, option.type]"
|
:class="[{ critical: option.critical }, option.type]"
|
||||||
:option="option"
|
:option="option"
|
||||||
@click="option.action && option.action()"
|
:childrenShowMode="settings.contextChildrenShowMode"
|
||||||
|
@hideContextMenu="context.hideContextMenu()"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
@@ -34,9 +21,12 @@ import { ref } from "vue";
|
|||||||
import { onClickOutside } from "@vueuse/core";
|
import { onClickOutside } from "@vueuse/core";
|
||||||
|
|
||||||
import useContextStore from "../stores/context";
|
import useContextStore from "../stores/context";
|
||||||
import ContextItem from "./Contextmenu/ContextItem.vue";
|
import useSettingsStore from "../stores/settings";
|
||||||
const context = useContextStore();
|
|
||||||
|
|
||||||
|
import ContextItem from "./Contextmenu/ContextItem.vue";
|
||||||
|
|
||||||
|
const context = useContextStore();
|
||||||
|
const settings = useSettingsStore();
|
||||||
const contextMenu = ref<HTMLElement>();
|
const contextMenu = ref<HTMLElement>();
|
||||||
|
|
||||||
let clickCount = 0;
|
let clickCount = 0;
|
||||||
@@ -64,6 +54,7 @@ onClickOutside(contextMenu, (e) => {
|
|||||||
width: 12rem;
|
width: 12rem;
|
||||||
z-index: 10000 !important;
|
z-index: 10000 !important;
|
||||||
transform: scale(0);
|
transform: scale(0);
|
||||||
|
height: min-content;
|
||||||
|
|
||||||
padding: $small 0;
|
padding: $small 0;
|
||||||
background: $context;
|
background: $context;
|
||||||
@@ -81,32 +72,4 @@ onClickOutside(contextMenu, (e) => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.context-menu-visible {
|
|
||||||
transform: scale(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
.context-normalizedX {
|
|
||||||
.more {
|
|
||||||
transform: rotate(180deg);
|
|
||||||
}
|
|
||||||
|
|
||||||
.context-item > .children {
|
|
||||||
left: -13rem;
|
|
||||||
transform-origin: center right;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.context-normalizedY {
|
|
||||||
.context-item > .children {
|
|
||||||
transform-origin: bottom right;
|
|
||||||
top: -0.5rem;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.context-many-kids {
|
|
||||||
.context-item > .children {
|
|
||||||
overflow-y: auto;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -1,15 +1,33 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="context-item">
|
<div
|
||||||
|
class="context-item"
|
||||||
|
@mouseenter="
|
||||||
|
option.children &&
|
||||||
|
childrenShowMode === contextChildrenShowMode.hover &&
|
||||||
|
showChildren()
|
||||||
|
"
|
||||||
|
@mouseleave="
|
||||||
|
option.children &&
|
||||||
|
childrenShowMode === contextChildrenShowMode.hover &&
|
||||||
|
hideChildren()
|
||||||
|
"
|
||||||
|
@click="runAction"
|
||||||
|
ref="parentRef"
|
||||||
|
>
|
||||||
<div class="icon image" :class="option.icon"></div>
|
<div class="icon image" :class="option.icon"></div>
|
||||||
<div class="label ellip">{{ option.label }}</div>
|
<div class="label ellip">{{ option.label }}</div>
|
||||||
<div class="more image" v-if="option.children"></div>
|
<div class="more image" v-if="option.children"></div>
|
||||||
<div class="children rounded shadow-sm" v-if="option.children">
|
<div
|
||||||
|
class="children rounded shadow-sm"
|
||||||
|
v-if="option.children"
|
||||||
|
ref="childRef"
|
||||||
|
>
|
||||||
<div
|
<div
|
||||||
class="context-item"
|
class="context-item"
|
||||||
v-for="child in option.children"
|
v-for="child in option.children"
|
||||||
:key="child.label"
|
:key="child.label"
|
||||||
:class="[{ critical: child.critical }, child.type]"
|
:class="[{ critical: child.critical }, child.type]"
|
||||||
@click="child.action && child.action()"
|
@click="child.action && runChildAction(child.action)"
|
||||||
>
|
>
|
||||||
<div class="label ellip">
|
<div class="label ellip">
|
||||||
{{ child.label }}
|
{{ child.label }}
|
||||||
@@ -20,11 +38,83 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { Option } from "@/interfaces";
|
import { ref } from "vue";
|
||||||
|
import { createPopper, Instance } from "@popperjs/core";
|
||||||
|
|
||||||
defineProps<{
|
import { Option } from "@/interfaces";
|
||||||
|
import { contextChildrenShowMode } from "@/composables/enums";
|
||||||
|
|
||||||
|
const props = defineProps<{
|
||||||
option: Option;
|
option: Option;
|
||||||
|
childrenShowMode: contextChildrenShowMode;
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
|
const emit = defineEmits<{
|
||||||
|
(event: "hideContextMenu"): void;
|
||||||
|
}>();
|
||||||
|
|
||||||
|
const parentRef = ref<HTMLElement>();
|
||||||
|
const childRef = ref<HTMLElement>();
|
||||||
|
const childrenShown = ref(false);
|
||||||
|
|
||||||
|
let popperInstance: Instance | null = null;
|
||||||
|
|
||||||
|
function showChildren() {
|
||||||
|
if (childrenShown.value) {
|
||||||
|
childrenShown.value = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
popperInstance = createPopper(
|
||||||
|
parentRef.value as HTMLElement,
|
||||||
|
childRef.value as HTMLElement,
|
||||||
|
{
|
||||||
|
placement: "right-start",
|
||||||
|
modifiers: [
|
||||||
|
{
|
||||||
|
name: "offset",
|
||||||
|
options: {
|
||||||
|
offset: [-5, -2],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}
|
||||||
|
);
|
||||||
|
childRef.value ? (childRef.value.style.visibility = "visible") : null;
|
||||||
|
childrenShown.value = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
function hideChildren() {
|
||||||
|
childRef.value ? (childRef.value.style.visibility = "hidden") : null;
|
||||||
|
popperInstance?.destroy();
|
||||||
|
childrenShown.value = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
function hideContextMenu() {
|
||||||
|
if (props.option.children) return;
|
||||||
|
emit("hideContextMenu");
|
||||||
|
}
|
||||||
|
|
||||||
|
function runAction() {
|
||||||
|
if (props.option.children) {
|
||||||
|
if (childrenShown.value) {
|
||||||
|
console.log("what");
|
||||||
|
hideChildren();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
showChildren();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
props.option.action && props.option.action();
|
||||||
|
hideContextMenu();
|
||||||
|
}
|
||||||
|
|
||||||
|
function runChildAction(action: () => void) {
|
||||||
|
action();
|
||||||
|
emit("hideContextMenu");
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss">
|
<style lang="scss">
|
||||||
@@ -40,19 +130,15 @@ defineProps<{
|
|||||||
width: 1.5rem;
|
width: 1.5rem;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
right: $small;
|
right: $small;
|
||||||
background-image: url("../assets/icons/expand.svg");
|
background-image: url("../../assets/icons/expand.svg");
|
||||||
}
|
}
|
||||||
|
|
||||||
.children {
|
.children {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
right: -13rem;
|
|
||||||
width: 13rem;
|
width: 13rem;
|
||||||
top: -0.5rem;
|
|
||||||
max-height: 23.5rem;
|
|
||||||
|
|
||||||
background-color: $context;
|
background-color: $context;
|
||||||
transform: scale(0);
|
transform: scale(0);
|
||||||
transform-origin: top left;
|
|
||||||
padding: $small 0;
|
padding: $small 0;
|
||||||
|
|
||||||
.context-item {
|
.context-item {
|
||||||
@@ -66,12 +152,12 @@ defineProps<{
|
|||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
background: $darkestblue;
|
background: $darkestblue;
|
||||||
|
}
|
||||||
|
|
||||||
.children {
|
.children {
|
||||||
transform: scale(1);
|
transform: scale(0);
|
||||||
transition: transform 0.1s ease-in-out;
|
overflow: auto;
|
||||||
transition-delay: 0.3s;
|
max-height: calc(100vh - 10rem);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.icon {
|
.icon {
|
||||||
|
|||||||
@@ -13,7 +13,6 @@
|
|||||||
key-field="id"
|
key-field="id"
|
||||||
v-slot="{ item, index }"
|
v-slot="{ item, index }"
|
||||||
>
|
>
|
||||||
|
|
||||||
<TrackItem
|
<TrackItem
|
||||||
:index="index"
|
:index="index"
|
||||||
:track="item.track"
|
:track="item.track"
|
||||||
@@ -52,7 +51,7 @@ function playFromQueue(index: number) {
|
|||||||
function scrollToCurrent() {
|
function scrollToCurrent() {
|
||||||
const elem = document.getElementById("queue-scrollable") as HTMLElement;
|
const elem = document.getElementById("queue-scrollable") as HTMLElement;
|
||||||
|
|
||||||
const top = queue.currentindex * itemHeight - itemHeight;
|
const top = (queue.currentindex - 1) * itemHeight;
|
||||||
elem.scroll({
|
elem.scroll({
|
||||||
top,
|
top,
|
||||||
behavior: "smooth",
|
behavior: "smooth",
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
<template>
|
<template>
|
||||||
<div id="right-tabs" class="rounded">
|
<div id="right-tabs" class="rounded">
|
||||||
<div class="tab-buttons-wrapper">
|
<div class="tab-buttons-wrapper">
|
||||||
<Teleport :disabled="!isOnSearchPage" to="#nav-tab-headers">
|
|
||||||
<div class="tabheaders rounded-sm no-scroll">
|
<div class="tabheaders rounded-sm no-scroll">
|
||||||
<div
|
<div
|
||||||
class="tab"
|
class="tab"
|
||||||
@@ -13,7 +12,6 @@
|
|||||||
{{ tab }}
|
{{ tab }}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</Teleport>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div id="tab-content" v-auto-animate>
|
<div id="tab-content" v-auto-animate>
|
||||||
@@ -24,7 +22,6 @@
|
|||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
defineProps<{
|
defineProps<{
|
||||||
isOnSearchPage?: boolean;
|
|
||||||
tabs: string[];
|
tabs: string[];
|
||||||
currentTab: string;
|
currentTab: string;
|
||||||
}>();
|
}>();
|
||||||
|
|||||||
@@ -26,11 +26,13 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { onMounted, ref } from "vue";
|
import { ref } from "vue";
|
||||||
|
|
||||||
|
import useTabStore from "@/stores/tabs";
|
||||||
|
import useSearchStore from "@/stores/search";
|
||||||
|
|
||||||
import BackSvg from "@/assets/icons/arrow.svg";
|
import BackSvg from "@/assets/icons/arrow.svg";
|
||||||
import SearchSvg from "@/assets/icons/search.svg";
|
import SearchSvg from "@/assets/icons/search.svg";
|
||||||
import useSearchStore from "@/stores/search";
|
|
||||||
import useTabStore from "@/stores/tabs";
|
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
on_nav?: boolean;
|
on_nav?: boolean;
|
||||||
|
|||||||
@@ -0,0 +1,52 @@
|
|||||||
|
<template>
|
||||||
|
<div class="setting-select rounded-sm no-scroll">
|
||||||
|
<div
|
||||||
|
class="option"
|
||||||
|
v-for="option in optionsWithActive"
|
||||||
|
:key="option.title"
|
||||||
|
:class="{ active: option.active }"
|
||||||
|
@click="setterFn(option.value)"
|
||||||
|
>
|
||||||
|
{{ option.title }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { SettingOption } from "@/interfaces/settings";
|
||||||
|
import { computed } from "vue";
|
||||||
|
|
||||||
|
const props = defineProps<{
|
||||||
|
options: SettingOption[] | undefined;
|
||||||
|
source: () => string;
|
||||||
|
setterFn: (value: any) => void;
|
||||||
|
}>();
|
||||||
|
|
||||||
|
const optionsWithActive = computed(() => {
|
||||||
|
return props.options?.map((option) => {
|
||||||
|
return {
|
||||||
|
...option,
|
||||||
|
active: option.value === props.source(),
|
||||||
|
};
|
||||||
|
});
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
.setting-select {
|
||||||
|
display: flex;
|
||||||
|
background-color: $gray3;
|
||||||
|
|
||||||
|
.option {
|
||||||
|
padding: 0.5rem;
|
||||||
|
cursor: pointer;
|
||||||
|
user-select: none;
|
||||||
|
min-width: 4rem;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.option.active {
|
||||||
|
background-color: $darkestblue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -19,6 +19,12 @@
|
|||||||
@click="setting.action()"
|
@click="setting.action()"
|
||||||
:state="setting.source()"
|
:state="setting.source()"
|
||||||
/>
|
/>
|
||||||
|
<Select
|
||||||
|
v-if="setting.type === SettingType.select"
|
||||||
|
:options="setting.options"
|
||||||
|
:source="setting.source"
|
||||||
|
:setterFn="setting.action"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -26,8 +32,11 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { SettingGroup, SettingType } from "@/interfaces/settings";
|
import { SettingType } from "@/settings/enums";
|
||||||
|
import { SettingGroup } from "@/interfaces/settings";
|
||||||
|
|
||||||
import Switch from "./Components/Switch.vue";
|
import Switch from "./Components/Switch.vue";
|
||||||
|
import Select from "./Components/Select.vue";
|
||||||
|
|
||||||
defineProps<{
|
defineProps<{
|
||||||
group: SettingGroup;
|
group: SettingGroup;
|
||||||
|
|||||||
@@ -94,7 +94,7 @@ function emitUpdate() {
|
|||||||
emit("playThis");
|
emit("playThis");
|
||||||
}
|
}
|
||||||
|
|
||||||
function showMenu(e: Event) {
|
function showMenu(e: MouseEvent) {
|
||||||
showContext(e, props.track, options_button_clicked);
|
showContext(e, props.track, options_button_clicked);
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -9,13 +9,13 @@ import { Track } from "@/interfaces";
|
|||||||
import trackContext from "@/contexts/track_context";
|
import trackContext from "@/contexts/track_context";
|
||||||
|
|
||||||
export const showTrackContextMenu = (
|
export const showTrackContextMenu = (
|
||||||
e: Event,
|
e: MouseEvent,
|
||||||
track: Track,
|
track: Track,
|
||||||
flag: Ref<boolean>
|
flag: Ref<boolean>
|
||||||
) => {
|
) => {
|
||||||
const menu = useContextStore();
|
const menu = useContextStore();
|
||||||
|
|
||||||
const options = trackContext(track, useModalStore, useQueueStore);
|
const options = () => trackContext(track, useModalStore, useQueueStore);
|
||||||
|
|
||||||
menu.showContextMenu(e, options, ContextSrc.Track);
|
menu.showContextMenu(e, options, ContextSrc.Track);
|
||||||
flag.value = true;
|
flag.value = true;
|
||||||
|
|||||||
@@ -46,3 +46,8 @@ export const FuseTrackOptions = {
|
|||||||
{ name: "albumartist", weight: 0.25 },
|
{ name: "albumartist", weight: 0.25 },
|
||||||
],
|
],
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export enum contextChildrenShowMode {
|
||||||
|
click = "click",
|
||||||
|
hover = "hover",
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,9 +1,4 @@
|
|||||||
export enum SettingType {
|
import { SettingType } from "@/settings/enums";
|
||||||
text,
|
|
||||||
select,
|
|
||||||
multiselect,
|
|
||||||
binary,
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface SettingOption {
|
export interface SettingOption {
|
||||||
title: string;
|
title: string;
|
||||||
|
|||||||
@@ -0,0 +1,6 @@
|
|||||||
|
export enum SettingType {
|
||||||
|
text,
|
||||||
|
select,
|
||||||
|
multiselect,
|
||||||
|
binary,
|
||||||
|
}
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
import { Setting } from "@/interfaces/settings";
|
||||||
|
import { SettingType } from "@/settings/enums";
|
||||||
|
import { contextChildrenShowModeStrings as showModeStr } from "./../strings";
|
||||||
|
|
||||||
|
import useSettingsStore from "@/stores/settings";
|
||||||
|
import { contextChildrenShowMode as mode } from "@/composables/enums";
|
||||||
|
|
||||||
|
const settings = useSettingsStore;
|
||||||
|
|
||||||
|
const context_children_show_mode: Setting = {
|
||||||
|
title: showModeStr.settings.show_mode,
|
||||||
|
type: SettingType.select,
|
||||||
|
options: [
|
||||||
|
{
|
||||||
|
title: mode.click,
|
||||||
|
value: mode.click,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: mode.hover,
|
||||||
|
value: mode.hover,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
source: () => settings().contextChildrenShowMode,
|
||||||
|
action: (value: mode) => settings().setContextChildrenShowMode(value),
|
||||||
|
};
|
||||||
|
|
||||||
|
export default [context_children_show_mode];
|
||||||
@@ -1,7 +1,9 @@
|
|||||||
import { Setting, SettingType } from "@/interfaces/settings";
|
import { SettingType } from "../enums";
|
||||||
import useSettingsStore from "@/stores/settings";
|
import { Setting } from "@/interfaces/settings";
|
||||||
import { appWidthStrings } from "./../strings";
|
import { appWidthStrings } from "./../strings";
|
||||||
|
|
||||||
|
import useSettingsStore from "@/stores/settings";
|
||||||
|
|
||||||
const settings = useSettingsStore;
|
const settings = useSettingsStore;
|
||||||
|
|
||||||
const extend_to_full_width: Setting = {
|
const extend_to_full_width: Setting = {
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import { SettingCategory } from "@/interfaces/settings";
|
import { SettingCategory } from "@/interfaces/settings";
|
||||||
import * as strings from "../strings";
|
import * as strings from "../strings";
|
||||||
|
import contextChildrenShowMode from "./context-children-show-mode";
|
||||||
import extendWidth from "./extend-width";
|
import extendWidth from "./extend-width";
|
||||||
import nowPlaying from "./now-playing";
|
import nowPlaying from "./now-playing";
|
||||||
import sidebarSettings from "./sidebar";
|
import sidebarSettings from "./sidebar";
|
||||||
@@ -10,7 +11,11 @@ export default {
|
|||||||
title: "General",
|
title: "General",
|
||||||
groups: [
|
groups: [
|
||||||
{
|
{
|
||||||
settings: [...sidebarSettings, ...extendWidth],
|
settings: [
|
||||||
|
...sidebarSettings,
|
||||||
|
...extendWidth,
|
||||||
|
...contextChildrenShowMode,
|
||||||
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: npStrings.title,
|
title: npStrings.title,
|
||||||
|
|||||||
@@ -1,7 +1,9 @@
|
|||||||
import { Setting, SettingType } from "@/interfaces/settings";
|
import { SettingType } from "../enums";
|
||||||
import useSettingsStore from "@/stores/settings";
|
import { Setting } from "@/interfaces/settings";
|
||||||
import { nowPlayingStrings as data } from "../strings";
|
import { nowPlayingStrings as data } from "../strings";
|
||||||
|
|
||||||
|
import useSettingsStore from "@/stores/settings";
|
||||||
|
|
||||||
const settings = useSettingsStore;
|
const settings = useSettingsStore;
|
||||||
|
|
||||||
const disable_np_img: Setting = {
|
const disable_np_img: Setting = {
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
|
import { SettingType } from "../enums";
|
||||||
import { sidebarStrings } from "./../strings";
|
import { sidebarStrings } from "./../strings";
|
||||||
import { Setting, SettingType } from "@/interfaces/settings";
|
import { Setting } from "@/interfaces/settings";
|
||||||
|
|
||||||
import useSettingsStore from "@/stores/settings";
|
import useSettingsStore from "@/stores/settings";
|
||||||
|
|
||||||
const settings = useSettingsStore;
|
const settings = useSettingsStore;
|
||||||
|
|||||||
@@ -28,3 +28,9 @@ export const sidebarStrings = <S>{
|
|||||||
use_sidebar: "Show right sidebar",
|
use_sidebar: "Show right sidebar",
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const contextChildrenShowModeStrings = <S>{
|
||||||
|
settings: {
|
||||||
|
show_mode: "Show context children on",
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|||||||
+48
-39
@@ -1,70 +1,79 @@
|
|||||||
import { defineStore } from "pinia";
|
import { defineStore } from "pinia";
|
||||||
import normalize from "../composables/normalizeContextMenu";
|
|
||||||
import { Option } from "../interfaces";
|
import { Option } from "../interfaces";
|
||||||
import { ContextSrc } from "../composables/enums";
|
import { ContextSrc } from "../composables/enums";
|
||||||
|
import { createPopper, VirtualElement } from "@popperjs/core";
|
||||||
|
|
||||||
function getPlaceholders(length: number) {
|
function generateGetBoundingClientRect(x = 0, y = 0) {
|
||||||
let list: Option[] = [];
|
return () => ({
|
||||||
|
width: 0,
|
||||||
for (let index = 0; index < length; index++) {
|
height: 0,
|
||||||
list.push("" as Option);
|
top: y,
|
||||||
|
right: x,
|
||||||
|
bottom: y,
|
||||||
|
left: x,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
return list;
|
|
||||||
}
|
|
||||||
|
|
||||||
getPlaceholders(5);
|
|
||||||
|
|
||||||
export default defineStore("context-menu", {
|
export default defineStore("context-menu", {
|
||||||
state: () => ({
|
state: () => ({
|
||||||
visible: false,
|
visible: false,
|
||||||
options: getPlaceholders(5),
|
options: {} as Option[],
|
||||||
x: 500,
|
|
||||||
y: 500,
|
|
||||||
normalizedX: false,
|
|
||||||
normalizedY: false,
|
|
||||||
src: <null | string>"",
|
src: <null | string>"",
|
||||||
|
elem: <HTMLElement | null>null,
|
||||||
}),
|
}),
|
||||||
actions: {
|
actions: {
|
||||||
showContextMenu(
|
showContextMenu(
|
||||||
e: any,
|
e: MouseEvent,
|
||||||
context_options: Promise<Option[]>,
|
getContextOptions: () => Promise<Option[]>,
|
||||||
src: ContextSrc
|
src: ContextSrc
|
||||||
) {
|
) {
|
||||||
if (this.visible) {
|
if (this.visible) {
|
||||||
this.visible = false;
|
this.hideContextMenu();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.visible = true;
|
if (this.elem === null) {
|
||||||
context_options.then((options) => {
|
this.elem = document.getElementById("context-menu");
|
||||||
|
}
|
||||||
|
|
||||||
|
const virtualElement = {
|
||||||
|
getBoundingClientRect: generateGetBoundingClientRect(e.x, e.y),
|
||||||
|
} as VirtualElement;
|
||||||
|
|
||||||
|
getContextOptions()
|
||||||
|
.then((options) => {
|
||||||
this.options = options;
|
this.options = options;
|
||||||
|
})
|
||||||
|
.then(() => {
|
||||||
|
createPopper(virtualElement, this.elem as HTMLElement, {
|
||||||
|
placement: "right-start",
|
||||||
|
modifiers: [
|
||||||
|
{
|
||||||
|
name: "flip",
|
||||||
|
options: {
|
||||||
|
fallbackPlacements: ["left-start"],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
const xy = normalize(e.clientX, e.clientY);
|
this.visible = true;
|
||||||
|
|
||||||
this.x = xy.normalX;
|
|
||||||
this.y = xy.normalY;
|
|
||||||
|
|
||||||
this.normalizedX = xy.normalizedX;
|
|
||||||
this.normalizedY = xy.normalizedY;
|
|
||||||
this.src = src;
|
this.src = src;
|
||||||
|
|
||||||
|
// const xy = normalize(e.clientX, e.clientY);
|
||||||
|
|
||||||
|
// this.x = xy.normalX;
|
||||||
|
// this.y = xy.normalY;
|
||||||
|
|
||||||
|
// this.normalizedX = xy.normalizedX;
|
||||||
|
// this.normalizedY = xy.normalizedY;
|
||||||
},
|
},
|
||||||
hideContextMenu() {
|
hideContextMenu() {
|
||||||
this.visible = false;
|
this.visible = false;
|
||||||
this.src = null;
|
this.src = null;
|
||||||
this.options = [];
|
this.options = [];
|
||||||
},
|
this.elem ? (this.elem.style.transform = "scale(0)") : null;
|
||||||
hasManyChildren() {
|
|
||||||
let result = false;
|
|
||||||
|
|
||||||
this.options.forEach((option: Option) => {
|
|
||||||
if (option.children && option.children.length > 9) {
|
|
||||||
result = true;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
return result;
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1 +0,0 @@
|
|||||||
|
|
||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import { contextChildrenShowMode } from "@/composables/enums";
|
||||||
import { xxl } from "@/composables/useBreakpoints";
|
import { xxl } from "@/composables/useBreakpoints";
|
||||||
import { defineStore } from "pinia";
|
import { defineStore } from "pinia";
|
||||||
|
|
||||||
@@ -6,6 +7,7 @@ export default defineStore("settings", {
|
|||||||
use_np_img: false,
|
use_np_img: false,
|
||||||
use_sidebar: true,
|
use_sidebar: true,
|
||||||
extend_width: false,
|
extend_width: false,
|
||||||
|
contextChildrenShowMode: contextChildrenShowMode.click,
|
||||||
}),
|
}),
|
||||||
actions: {
|
actions: {
|
||||||
toggleUseNPImg() {
|
toggleUseNPImg() {
|
||||||
@@ -17,10 +19,13 @@ export default defineStore("settings", {
|
|||||||
toggleExtendWidth() {
|
toggleExtendWidth() {
|
||||||
this.extend_width = !this.extend_width;
|
this.extend_width = !this.extend_width;
|
||||||
},
|
},
|
||||||
|
setContextChildrenShowMode(mode: contextChildrenShowMode) {
|
||||||
|
this.contextChildrenShowMode = mode;
|
||||||
|
},
|
||||||
},
|
},
|
||||||
getters: {
|
getters: {
|
||||||
can_extend_width(): boolean {
|
can_extend_width(): boolean {
|
||||||
return xxl.value
|
return xxl.value;
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
persist: true,
|
persist: true,
|
||||||
|
|||||||
Vendored
+1
-1
@@ -1,4 +1,4 @@
|
|||||||
declare module "*.svg" {
|
declare module "*.svg" {
|
||||||
const content: string;
|
const content: any;
|
||||||
export default content;
|
export default content;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -54,7 +54,7 @@ function playFromQueue(index: number) {
|
|||||||
function scrollToCurrent() {
|
function scrollToCurrent() {
|
||||||
const scrollable = document.getElementById("queue-page-scrollable");
|
const scrollable = document.getElementById("queue-page-scrollable");
|
||||||
const itemHeight = 64;
|
const itemHeight = 64;
|
||||||
const top = queue.currentindex * itemHeight - itemHeight;
|
const top = (queue.currentindex - 1) * itemHeight;
|
||||||
|
|
||||||
scrollable?.scrollTo({
|
scrollable?.scrollTo({
|
||||||
top,
|
top,
|
||||||
|
|||||||
+1
-1
@@ -10,7 +10,7 @@
|
|||||||
"sourceMap": true,
|
"sourceMap": true,
|
||||||
"resolveJsonModule": true,
|
"resolveJsonModule": true,
|
||||||
"isolatedModules": true,
|
"isolatedModules": true,
|
||||||
"esModuleInterop": true,
|
"esModuleInterop": false,
|
||||||
"lib": ["ESNext", "DOM"],
|
"lib": ["ESNext", "DOM"],
|
||||||
"skipLibCheck": true,
|
"skipLibCheck": true,
|
||||||
"paths": {
|
"paths": {
|
||||||
|
|||||||
Reference in New Issue
Block a user