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>
class="_button" <template #header>
:style="{ background: bg }" <div
@click="showBody = !showBody" :class="[$style.header, { [$style.opened]: opened }]"
> class="_button"
<div class="title"><slot name="header"></slot></div> role="button"
<div class="divider"></div> data-cy-folder-header
<button class="_button"> @click="toggle"
<template v-if="showBody" >
><i class="ph-caret-up ph-bold ph-lg"></i <div :class="$style.headerIcon">
></template> <slot name="icon"></slot>
<template v-else </div>
><i class="ph-caret-down ph-bold ph-lg"></i <div :class="$style.headerText">
></template> <div :class="$style.headerTextMain">
</button> <MkCondensedLine :minScale="2 / 3"
</header> ><slot name="label"></slot
<transition ></MkCondensedLine>
:name="$store.state.animation ? 'folder-toggle' : ''" </div>
@enter="enter" <div :class="$style.headerTextSub">
@after-enter="afterEnter" <slot name="caption"></slot>
@leave="leave" </div>
@after-leave="afterLeave" </div>
> <div :class="$style.headerRight">
<div v-show="showBody"> <span :class="$style.headerRightText"
<slot></slot> ><slot name="suffix"></slot
></span>
<i v-if="opened" class="ti ti-chevron-up icon"></i>
<i v-else class="ti ti-chevron-down icon"></i>
</div>
</div>
</template>
<div
v-if="openedAtLeastOnce"
: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> </div>
</transition> </MkStickyContainer>
</div> </div>
</template> </template>
<script lang="ts"> <script lang="ts" setup>
import { defineComponent } from "vue"; import { nextTick, onMounted } from "vue";
import tinycolor from "tinycolor2"; import { defaultStore } from "@/store";
const localStoragePrefix = "ui:folder:"; const props = withDefaults(
defineProps<{
defaultOpen?: boolean;
maxHeight?: number | null;
}>(),
{
defaultOpen: false,
maxHeight: null,
}
);
export default defineComponent({ const getBgColor = (el: HTMLElement) => {
props: { const style = window.getComputedStyle(el);
expanded: { if (
type: Boolean, style.backgroundColor &&
required: false, !["rgba(0, 0, 0, 0)", "rgba(0,0,0,0)", "transparent"].includes(
default: true, style.backgroundColor
}, )
persistKey: { ) {
type: String, return style.backgroundColor;
required: false, } else {
default: null, return el.parentElement ? getBgColor(el.parentElement) : "transparent";
}, }
}, };
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"
);
}
},
},
mounted() {
function getParentBg(el: Element | null): string {
if (el == null || el.tagName === "BODY") return "var(--bg)";
const bg = el.style.background || el.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
);
bg.setAlpha(0.85);
this.bg = bg.toRgbString();
},
methods: {
toggleContent(show: boolean) {
this.showBody = show;
},
enter(el) { let rootEl = $shallowRef<HTMLElement>();
const elementHeight = el.getBoundingClientRect().height; let bgSame = $ref(false);
el.style.height = 0; let opened = $ref(props.defaultOpen);
el.offsetHeight; // reflow let openedAtLeastOnce = $ref(props.defaultOpen);
el.style.height = elementHeight + "px";
}, function enter(el) {
afterEnter(el) { const elementHeight = el.getBoundingClientRect().height;
el.style.height = null; el.style.height = 0;
}, el.offsetHeight; // reflow
leave(el) { el.style.height =
const elementHeight = el.getBoundingClientRect().height; Math.min(elementHeight, props.maxHeight ?? Infinity) + "px";
el.style.height = elementHeight + "px"; }
el.offsetHeight; // reflow
el.style.height = 0; function afterEnter(el) {
}, el.style.height = null;
afterLeave(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;
}
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;
}
&:empty {
display: none;
}
}
> .divider {
flex: 1;
margin: auto;
height: 1px;
background: var(--divider);
}
> button {
padding: 12px 0 12px 16px;
}
} }
&.max-width_500px { &.active {
> header { color: var(--accent);
> .title { background: var(--buttonHoverBg);
padding: 8px 10px 8px 0; }
}
&.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 {
display: none;
& + .headerText {
padding-left: 4px;
} }
} }
} }
.headerText {
white-space: nowrap;
text-overflow: ellipsis;
overflow: hidden;
padding-right: 12px;
}
.headerTextMain {
}
.headerTextSub {
color: var(--fgTransparentWeak);
font-size: 0.85em;
}
.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>