🎨
This commit is contained in:
parent
43fafc8d57
commit
d147181a82
5 changed files with 83 additions and 22 deletions
|
@ -131,7 +131,7 @@ export default defineComponent({
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
.container-toggle-enter-active, .container-toggle-leave-active {
|
.container-toggle-enter-active, .container-toggle-leave-active {
|
||||||
overflow-y: hidden;
|
overflow-y: clip;
|
||||||
transition: opacity 0.5s, height 0.5s !important;
|
transition: opacity 0.5s, height 0.5s !important;
|
||||||
}
|
}
|
||||||
.container-toggle-enter-from {
|
.container-toggle-enter-from {
|
||||||
|
|
|
@ -98,7 +98,7 @@ export default defineComponent({
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
.folder-toggle-enter-active, .folder-toggle-leave-active {
|
.folder-toggle-enter-active, .folder-toggle-leave-active {
|
||||||
overflow-y: hidden;
|
overflow-y: clip;
|
||||||
transition: opacity 0.5s, height 0.5s !important;
|
transition: opacity 0.5s, height 0.5s !important;
|
||||||
}
|
}
|
||||||
.folder-toggle-enter-from {
|
.folder-toggle-enter-from {
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="dwzlatin" :class="{ opened }">
|
<div class="dwzlatin" :class="{ opened }" ref="root">
|
||||||
<div class="header _button" @click="toggle">
|
<div class="header _button" @click="toggle">
|
||||||
<span class="icon"><slot name="icon"></slot></span>
|
<span class="icon"><slot name="icon"></slot></span>
|
||||||
<span class="text"><slot name="label"></slot></span>
|
<span class="text"><slot name="label"></slot></span>
|
||||||
|
@ -9,17 +9,29 @@
|
||||||
<i v-else class="ti ti-chevron-down icon"></i>
|
<i v-else class="ti ti-chevron-down icon"></i>
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<KeepAlive>
|
<div v-if="openedAtLeastOnce" class="body">
|
||||||
<div v-if="openedAtLeastOnce" v-show="opened" class="body">
|
<Transition
|
||||||
<MkSpacer :margin-min="14" :margin-max="22">
|
:name="$store.state.animation ? 'folder-toggle' : ''"
|
||||||
<slot></slot>
|
@enter="enter"
|
||||||
</MkSpacer>
|
@after-enter="afterEnter"
|
||||||
</div>
|
@leave="leave"
|
||||||
</KeepAlive>
|
@after-leave="afterLeave"
|
||||||
|
>
|
||||||
|
<KeepAlive>
|
||||||
|
<div v-show="opened">
|
||||||
|
<MkSpacer :margin-min="14" :margin-max="22" :container="root">
|
||||||
|
<slot></slot>
|
||||||
|
</MkSpacer>
|
||||||
|
</div>
|
||||||
|
</KeepAlive>
|
||||||
|
</Transition>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
|
import { nextTick } from 'vue';
|
||||||
|
|
||||||
const props = withDefaults(defineProps<{
|
const props = withDefaults(defineProps<{
|
||||||
defaultOpen: boolean;
|
defaultOpen: boolean;
|
||||||
}>(), {
|
}>(), {
|
||||||
|
@ -28,16 +40,50 @@ const props = withDefaults(defineProps<{
|
||||||
|
|
||||||
let opened = $ref(props.defaultOpen);
|
let opened = $ref(props.defaultOpen);
|
||||||
let openedAtLeastOnce = $ref(props.defaultOpen);
|
let openedAtLeastOnce = $ref(props.defaultOpen);
|
||||||
|
let root = $ref<HTMLElement>();
|
||||||
|
|
||||||
const toggle = () => {
|
function enter(el) {
|
||||||
opened = !opened;
|
const elementHeight = el.getBoundingClientRect().height;
|
||||||
if (opened) {
|
el.style.height = 0;
|
||||||
|
el.offsetHeight; // reflow
|
||||||
|
el.style.height = elementHeight + 'px';
|
||||||
|
}
|
||||||
|
|
||||||
|
function afterEnter(el) {
|
||||||
|
el.style.height = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
function leave(el) {
|
||||||
|
const elementHeight = el.getBoundingClientRect().height;
|
||||||
|
el.style.height = elementHeight + 'px';
|
||||||
|
el.offsetHeight; // reflow
|
||||||
|
el.style.height = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
function afterLeave(el) {
|
||||||
|
el.style.height = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
function toggle() {
|
||||||
|
if (!opened) {
|
||||||
openedAtLeastOnce = true;
|
openedAtLeastOnce = true;
|
||||||
}
|
}
|
||||||
};
|
|
||||||
|
nextTick(() => {
|
||||||
|
opened = !opened;
|
||||||
|
});
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
|
.folder-toggle-enter-active, .folder-toggle-leave-active {
|
||||||
|
overflow-y: clip;
|
||||||
|
transition: opacity 0.3s, height 0.3s, transform 0.3s !important;
|
||||||
|
}
|
||||||
|
.folder-toggle-enter-from, .folder-toggle-leave-to {
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
|
||||||
.dwzlatin {
|
.dwzlatin {
|
||||||
display: block;
|
display: block;
|
||||||
|
|
||||||
|
|
|
@ -59,16 +59,17 @@ const finalValue = computed(() => {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
const thumbWidth = computed(() => {
|
const getThumbWidth = () => {
|
||||||
if (thumbEl.value == null) return 0;
|
if (thumbEl.value == null) return 0;
|
||||||
return thumbEl.value!.offsetWidth;
|
return thumbEl.value!.offsetWidth;
|
||||||
});
|
};
|
||||||
const thumbPosition = ref(0);
|
const thumbPosition = ref(0);
|
||||||
const calcThumbPosition = () => {
|
const calcThumbPosition = () => {
|
||||||
if (containerEl.value == null) {
|
if (containerEl.value == null) {
|
||||||
thumbPosition.value = 0;
|
thumbPosition.value = 0;
|
||||||
} else {
|
} else {
|
||||||
thumbPosition.value = (containerEl.value.offsetWidth - thumbWidth.value) * steppedRawValue.value;
|
thumbPosition.value = (containerEl.value.offsetWidth - getThumbWidth()) * steppedRawValue.value;
|
||||||
|
console.log(containerEl.value.offsetWidth, getThumbWidth());
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
watch([steppedRawValue, containerEl], calcThumbPosition);
|
watch([steppedRawValue, containerEl], calcThumbPosition);
|
||||||
|
@ -110,12 +111,14 @@ const onMousedown = (ev: MouseEvent | TouchEvent) => {
|
||||||
style.appendChild(document.createTextNode('* { cursor: grabbing !important; } body * { pointer-events: none !important; }'));
|
style.appendChild(document.createTextNode('* { cursor: grabbing !important; } body * { pointer-events: none !important; }'));
|
||||||
document.head.appendChild(style);
|
document.head.appendChild(style);
|
||||||
|
|
||||||
|
const thumbWidth = getThumbWidth();
|
||||||
|
|
||||||
const onDrag = (ev: MouseEvent | TouchEvent) => {
|
const onDrag = (ev: MouseEvent | TouchEvent) => {
|
||||||
ev.preventDefault();
|
ev.preventDefault();
|
||||||
const containerRect = containerEl.value!.getBoundingClientRect();
|
const containerRect = containerEl.value!.getBoundingClientRect();
|
||||||
const pointerX = ev.touches && ev.touches.length > 0 ? ev.touches[0].clientX : ev.clientX;
|
const pointerX = ev.touches && ev.touches.length > 0 ? ev.touches[0].clientX : ev.clientX;
|
||||||
const pointerPositionOnContainer = pointerX - (containerRect.left + (thumbWidth.value / 2));
|
const pointerPositionOnContainer = pointerX - (containerRect.left + (thumbWidth / 2));
|
||||||
rawValue.value = Math.min(1, Math.max(0, pointerPositionOnContainer / (containerEl.value!.offsetWidth - thumbWidth.value)));
|
rawValue.value = Math.min(1, Math.max(0, pointerPositionOnContainer / (containerEl.value!.offsetWidth - thumbWidth)));
|
||||||
};
|
};
|
||||||
|
|
||||||
let beforeValue = finalValue.value;
|
let beforeValue = finalValue.value;
|
||||||
|
|
|
@ -14,6 +14,9 @@ const props = withDefaults(defineProps<{
|
||||||
contentMax?: number | null;
|
contentMax?: number | null;
|
||||||
marginMin?: number;
|
marginMin?: number;
|
||||||
marginMax?: number;
|
marginMax?: number;
|
||||||
|
|
||||||
|
// MkFolderとかで開閉アニメーションの際にheightを正しく伝えるため
|
||||||
|
container?: HTMLElement,
|
||||||
}>(), {
|
}>(), {
|
||||||
contentMax: null,
|
contentMax: null,
|
||||||
marginMin: 12,
|
marginMin: 12,
|
||||||
|
@ -23,7 +26,7 @@ const props = withDefaults(defineProps<{
|
||||||
let ro: ResizeObserver;
|
let ro: ResizeObserver;
|
||||||
let root = $ref<HTMLElement>();
|
let root = $ref<HTMLElement>();
|
||||||
let content = $ref<HTMLElement>();
|
let content = $ref<HTMLElement>();
|
||||||
let margin = $ref(0);
|
let margin = $ref(props.marginMin);
|
||||||
const widthHistory = [null, null] as [number | null, number | null];
|
const widthHistory = [null, null] as [number | null, number | null];
|
||||||
const heightHistory = [null, null] as [number | null, number | null];
|
const heightHistory = [null, null] as [number | null, number | null];
|
||||||
const shouldSpacerMin = inject('shouldSpacerMin', false);
|
const shouldSpacerMin = inject('shouldSpacerMin', false);
|
||||||
|
@ -41,6 +44,15 @@ const adjust = (rect: { width: number; height: number; }) => {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if (props.container) {
|
||||||
|
const width = props.container.offsetWidth;
|
||||||
|
const height = props.container.offsetHeight;
|
||||||
|
adjust({
|
||||||
|
width,
|
||||||
|
height,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
ro = new ResizeObserver((entries) => {
|
ro = new ResizeObserver((entries) => {
|
||||||
/* iOSが対応していない
|
/* iOSが対応していない
|
||||||
|
@ -50,8 +62,8 @@ onMounted(() => {
|
||||||
});
|
});
|
||||||
*/
|
*/
|
||||||
|
|
||||||
const width = root!.offsetWidth;
|
const width = props.container ? props.container.offsetWidth : root!.offsetWidth;
|
||||||
const height = root!.offsetHeight;
|
const height = props.container ? props.container.offsetHeight : root!.offsetHeight;
|
||||||
|
|
||||||
//#region Prevent infinite resizing
|
//#region Prevent infinite resizing
|
||||||
// https://github.com/misskey-dev/misskey/issues/9076
|
// https://github.com/misskey-dev/misskey/issues/9076
|
||||||
|
|
Loading…
Reference in a new issue