chore: rebase to v13 MkFolder

Co-authored-by: Syuilo <syuilotan@yahoo.co.jp>
This commit is contained in:
ThatOneCalculator 2023-05-25 21:46:45 -07:00
parent e1462133f6
commit 8783cf0adf
No known key found for this signature in database
GPG Key ID: 8703CACD01000000
1 changed files with 237 additions and 172 deletions

View File

@ -1,195 +1,260 @@
<template> <template>
<div v-size="{ max: [500] }" class="ssazuxis"> <div ref="rootEl" :class="$style.root" role="group" :aria-expanded="opened">
<header <MkStickyContainer>
<template #header>
<div
:class="[$style.header, { [$style.opened]: opened }]"
class="_button" class="_button"
:style="{ background: bg }" role="button"
@click="showBody = !showBody" data-cy-folder-header
@click="toggle"
> >
<div class="title"><slot name="header"></slot></div> <div :class="$style.headerIcon">
<div class="divider"></div> <slot name="icon"></slot>
<button class="_button"> </div>
<template v-if="showBody" <div :class="$style.headerText">
><i class="ph-caret-up ph-bold ph-lg"></i <div :class="$style.headerTextMain">
></template> <MkCondensedLine :minScale="2 / 3"
<template v-else ><slot name="label"></slot
><i class="ph-caret-down ph-bold ph-lg"></i ></MkCondensedLine>
></template> </div>
</button> <div :class="$style.headerTextSub">
</header> <slot name="caption"></slot>
<transition </div>
:name="$store.state.animation ? 'folder-toggle' : ''" </div>
@enter="enter" <div :class="$style.headerRight">
@after-enter="afterEnter" <span :class="$style.headerRightText"
@leave="leave" ><slot name="suffix"></slot
@after-leave="afterLeave" ></span>
> <i v-if="opened" class="ti ti-chevron-up icon"></i>
<div v-show="showBody"> <i v-else class="ti ti-chevron-down icon"></i>
<slot></slot>
</div> </div>
</transition>
</div> </div>
</template> </template>
<script lang="ts"> <div
import { defineComponent } from "vue"; v-if="openedAtLeastOnce"
import tinycolor from "tinycolor2"; :class="[$style.body, { [$style.bgSame]: bgSame }]"
:style="{
maxHeight: maxHeight ? `${maxHeight}px` : null,
overflow: maxHeight ? `auto` : null,
}"
:aria-hidden="!opened"
>
<Transition
:enterActiveClass="
defaultStore.state.animation
? $style.transition_toggle_enterActive
: ''
"
:leaveActiveClass="
defaultStore.state.animation
? $style.transition_toggle_leaveActive
: ''
"
:enterFromClass="
defaultStore.state.animation
? $style.transition_toggle_enterFrom
: ''
"
:leaveToClass="
defaultStore.state.animation
? $style.transition_toggle_leaveTo
: ''
"
@enter="enter"
@afterEnter="afterEnter"
@leave="leave"
@afterLeave="afterLeave"
>
<KeepAlive>
<div v-show="opened">
<MkSpacer :marginMin="14" :marginMax="22">
<slot></slot>
</MkSpacer>
</div>
</KeepAlive>
</Transition>
</div>
</MkStickyContainer>
</div>
</template>
const localStoragePrefix = "ui:folder:"; <script lang="ts" setup>
import { nextTick, onMounted } from "vue";
import { defaultStore } from "@/store";
export default defineComponent({ const props = withDefaults(
props: { defineProps<{
expanded: { defaultOpen?: boolean;
type: Boolean, maxHeight?: number | null;
required: false, }>(),
default: true, {
}, defaultOpen: false,
persistKey: { maxHeight: null,
type: String, }
required: false,
default: null,
},
},
data() {
return {
bg: null,
showBody:
this.persistKey &&
localStorage.getItem(localStoragePrefix + this.persistKey)
? localStorage.getItem(
localStoragePrefix + this.persistKey
) === "t"
: this.expanded,
};
},
watch: {
showBody() {
if (this.persistKey) {
localStorage.setItem(
localStoragePrefix + this.persistKey,
this.showBody ? "t" : "f"
); );
}
}, const getBgColor = (el: HTMLElement) => {
}, const style = window.getComputedStyle(el);
mounted() { if (
function getParentBg(el: Element | null): string { style.backgroundColor &&
if (el == null || el.tagName === "BODY") return "var(--bg)"; !["rgba(0, 0, 0, 0)", "rgba(0,0,0,0)", "transparent"].includes(
const bg = el.style.background || el.style.backgroundColor; style.backgroundColor
if (bg) {
return bg;
} else {
return getParentBg(el.parentElement);
}
}
const rawBg = getParentBg(this.$el);
const bg = tinycolor(
rawBg.startsWith("var(")
? getComputedStyle(document.documentElement).getPropertyValue(
rawBg.slice(4, -1)
) )
: rawBg ) {
); return style.backgroundColor;
bg.setAlpha(0.85); } else {
this.bg = bg.toRgbString(); return el.parentElement ? getBgColor(el.parentElement) : "transparent";
}, }
methods: { };
toggleContent(show: boolean) {
this.showBody = show;
},
enter(el) { let rootEl = $shallowRef<HTMLElement>();
let bgSame = $ref(false);
let opened = $ref(props.defaultOpen);
let openedAtLeastOnce = $ref(props.defaultOpen);
function enter(el) {
const elementHeight = el.getBoundingClientRect().height; const elementHeight = el.getBoundingClientRect().height;
el.style.height = 0; el.style.height = 0;
el.offsetHeight; // reflow el.offsetHeight; // reflow
el.style.height = elementHeight + "px"; el.style.height =
}, Math.min(elementHeight, props.maxHeight ?? Infinity) + "px";
afterEnter(el) { }
function afterEnter(el) {
el.style.height = null; el.style.height = null;
}, }
leave(el) {
function leave(el) {
const elementHeight = el.getBoundingClientRect().height; const elementHeight = el.getBoundingClientRect().height;
el.style.height = elementHeight + "px"; el.style.height = elementHeight + "px";
el.offsetHeight; // reflow el.offsetHeight; // reflow
el.style.height = 0; el.style.height = 0;
}, }
afterLeave(el) {
function afterLeave(el) {
el.style.height = null; el.style.height = null;
}, }
},
function toggle() {
if (!opened) {
openedAtLeastOnce = true;
}
nextTick(() => {
opened = !opened;
});
}
onMounted(() => {
const computedStyle = getComputedStyle(document.documentElement);
const parentBg = getBgColor(rootEl.parentElement);
const myBg = computedStyle.getPropertyValue("--panel");
bgSame = parentBg === myBg;
}); });
</script> </script>
<style lang="scss" scoped> <style lang="scss" module>
.folder-toggle-enter-active, .transition_toggle_enterActive,
.folder-toggle-leave-active { .transition_toggle_leaveActive {
overflow-y: hidden; overflow-y: clip;
transition: opacity 0.5s, height 0.5s !important; transition: opacity 0.3s, height 0.3s, transform 0.3s !important;
} }
.folder-toggle-enter-from { .transition_toggle_enterFrom,
opacity: 0; .transition_toggle_leaveTo {
}
.folder-toggle-leave-to {
opacity: 0; opacity: 0;
} }
.ssazuxis { .root {
position: relative; display: block;
}
> header { .header {
display: flex; display: flex;
position: relative; align-items: center;
z-index: 10; width: 100%;
position: sticky; box-sizing: border-box;
top: var(--stickyTop, 0px); padding: 9px 12px 9px 12px;
padding: var(--x-padding); background: var(--buttonBg);
-webkit-backdrop-filter: var(--blur, blur(8px)); -webkit-backdrop-filter: var(--blur, blur(15px));
backdrop-filter: var(--blur, blur(20px)); backdrop-filter: var(--blur, blur(15px));
margin-inline: -12px; border-radius: 6px;
padding-inline: 12px; transition: border-radius 0.3s;
mask: linear-gradient(
to right,
transparent,
black 12px calc(100% - 12px),
transparent
);
-webkit-mask: linear-gradient(
to right,
transparent,
black 12px calc(100% - 12px),
transparent
);
> .title { &:hover {
margin: 0; text-decoration: none;
padding: 12px 16px 12px 0; background: var(--buttonHoverBg);
> i {
margin-right: 6px;
} }
&.active {
color: var(--accent);
background: var(--buttonHoverBg);
}
&.opened {
border-radius: 6px 6px 0 0;
}
}
.headerUpper {
display: flex;
align-items: center;
}
.headerLower {
color: var(--fgTransparentWeak);
font-size: 0.85em;
padding-left: 4px;
}
.headerIcon {
margin-right: 0.75em;
flex-shrink: 0;
text-align: center;
opacity: 0.8;
&:empty { &:empty {
display: none; display: none;
& + .headerText {
padding-left: 4px;
}
} }
} }
> .divider { .headerText {
flex: 1; white-space: nowrap;
margin: auto; text-overflow: ellipsis;
height: 1px; overflow: hidden;
background: var(--divider); padding-right: 12px;
} }
> button { .headerTextMain {
padding: 12px 0 12px 16px;
}
} }
&.max-width_500px { .headerTextSub {
> header { color: var(--fgTransparentWeak);
> .title { font-size: 0.85em;
padding: 8px 10px 8px 0;
} }
.headerRight {
margin-left: auto;
color: var(--fgTransparentWeak);
white-space: nowrap;
} }
.headerRightText:not(:empty) {
margin-right: 0.75em;
}
.body {
background: var(--panel);
border-radius: 0 0 6px 6px;
container-type: inline-size;
&.bgSame {
background: var(--bg);
} }
} }
</style> </style>