refactor
This commit is contained in:
		
							parent
							
								
									8524e9d735
								
							
						
					
					
						commit
						e633c3b84b
					
				
					 22 changed files with 453 additions and 450 deletions
				
			
		|  | @ -33,12 +33,12 @@ | |||
| 		<option v-for="item in c.items" :key="item.value" :value="item.value">{{ item.text }}</option> | ||||
| 	</MkSelect> | ||||
| 	<MkButton v-else-if="c.type === 'postFormButton'" :primary="c.primary" :rounded="c.rounded" :small="size === 'small'" @click="openPostForm">{{ c.text }}</MkButton> | ||||
| 	<FormFolder v-else-if="c.type === 'folder'" :default-open="c.opened"> | ||||
| 	<MkFolder v-else-if="c.type === 'folder'" :default-open="c.opened"> | ||||
| 		<template #label>{{ c.title }}</template> | ||||
| 		<template v-for="child in c.children" :key="child"> | ||||
| 			<MkAsUi v-if="!g(child).hidden" :component="g(child)" :components="props.components" :size="size"/> | ||||
| 		</template> | ||||
| 	</FormFolder> | ||||
| 	</MkFolder> | ||||
| 	<div v-else-if="c.type === 'container'" :class="[$style.container, { [$style.fontSerif]: c.font === 'serif', [$style.fontMonospace]: c.font === 'monospace', [$style.containerCenter]: c.align === 'center' }]" :style="{ backgroundColor: c.bgColor ?? null, color: c.fgColor ?? null, borderWidth: c.borderWidth ? `${c.borderWidth}px` : 0, borderColor: c.borderColor ?? 'var(--divider)', padding: c.padding ? `${c.padding}px` : 0, borderRadius: c.rounded ? '8px' : 0 }"> | ||||
| 		<template v-for="child in c.children" :key="child"> | ||||
| 			<MkAsUi v-if="!g(child).hidden" :component="g(child)" :components="props.components" :size="size"/> | ||||
|  | @ -56,7 +56,7 @@ import MkSwitch from '@/components/MkSwitch.vue'; | |||
| import MkTextarea from '@/components/MkTextarea.vue'; | ||||
| import MkSelect from '@/components/MkSelect.vue'; | ||||
| import { AsUiComponent } from '@/scripts/aiscript/ui'; | ||||
| import FormFolder from '@/components/form/folder.vue'; | ||||
| import MkFolder from '@/components/MkFolder.vue'; | ||||
| 
 | ||||
| const props = withDefaults(defineProps<{ | ||||
| 	component: AsUiComponent; | ||||
|  |  | |||
							
								
								
									
										154
									
								
								packages/frontend/src/components/MkFoldableSection.vue
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										154
									
								
								packages/frontend/src/components/MkFoldableSection.vue
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,154 @@ | |||
| <template> | ||||
| <div class="ssazuxis"> | ||||
| 	<header class="_button" :style="{ background: bg }" @click="showBody = !showBody"> | ||||
| 		<div class="title"><div><slot name="header"></slot></div></div> | ||||
| 		<div class="divider"></div> | ||||
| 		<button class="_button"> | ||||
| 			<template v-if="showBody"><i class="ti ti-chevron-up"></i></template> | ||||
| 			<template v-else><i class="ti ti-chevron-down"></i></template> | ||||
| 		</button> | ||||
| 	</header> | ||||
| 	<Transition | ||||
| 		:name="$store.state.animation ? 'folder-toggle' : ''" | ||||
| 		@enter="enter" | ||||
| 		@after-enter="afterEnter" | ||||
| 		@leave="leave" | ||||
| 		@after-leave="afterLeave" | ||||
| 	> | ||||
| 		<div v-show="showBody"> | ||||
| 			<slot></slot> | ||||
| 		</div> | ||||
| 	</Transition> | ||||
| </div> | ||||
| </template> | ||||
| 
 | ||||
| <script lang="ts"> | ||||
| import { defineComponent } from 'vue'; | ||||
| import tinycolor from 'tinycolor2'; | ||||
| import { miLocalStorage } from '@/local-storage'; | ||||
| 
 | ||||
| const miLocalStoragePrefix = 'ui:folder:' as const; | ||||
| 
 | ||||
| export default defineComponent({ | ||||
| 	props: { | ||||
| 		expanded: { | ||||
| 			type: Boolean, | ||||
| 			required: false, | ||||
| 			default: true, | ||||
| 		}, | ||||
| 		persistKey: { | ||||
| 			type: String, | ||||
| 			required: false, | ||||
| 			default: null, | ||||
| 		}, | ||||
| 	}, | ||||
| 	data() { | ||||
| 		return { | ||||
| 			bg: null, | ||||
| 			showBody: (this.persistKey && miLocalStorage.getItem(`${miLocalStoragePrefix}${this.persistKey}`)) ? (miLocalStorage.getItem(`${miLocalStoragePrefix}${this.persistKey}`) === 't') : this.expanded, | ||||
| 		}; | ||||
| 	}, | ||||
| 	watch: { | ||||
| 		showBody() { | ||||
| 			if (this.persistKey) { | ||||
| 				miLocalStorage.setItem(`${miLocalStoragePrefix}${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) { | ||||
| 			const elementHeight = el.getBoundingClientRect().height; | ||||
| 			el.style.height = 0; | ||||
| 			el.offsetHeight; // reflow | ||||
| 			el.style.height = elementHeight + 'px'; | ||||
| 		}, | ||||
| 		afterEnter(el) { | ||||
| 			el.style.height = null; | ||||
| 		}, | ||||
| 		leave(el) { | ||||
| 			const elementHeight = el.getBoundingClientRect().height; | ||||
| 			el.style.height = elementHeight + 'px'; | ||||
| 			el.offsetHeight; // reflow | ||||
| 			el.style.height = 0; | ||||
| 		}, | ||||
| 		afterLeave(el) { | ||||
| 			el.style.height = null; | ||||
| 		}, | ||||
| 	}, | ||||
| }); | ||||
| </script> | ||||
| 
 | ||||
| <style lang="scss" scoped> | ||||
| .folder-toggle-enter-active, .folder-toggle-leave-active { | ||||
| 	overflow-y: clip; | ||||
| 	transition: opacity 0.5s, height 0.5s !important; | ||||
| } | ||||
| .folder-toggle-enter-from { | ||||
| 	opacity: 0; | ||||
| } | ||||
| .folder-toggle-leave-to { | ||||
| 	opacity: 0; | ||||
| } | ||||
| 
 | ||||
| .ssazuxis { | ||||
| 	position: relative; | ||||
| 
 | ||||
| 	> header { | ||||
| 		display: flex; | ||||
| 		position: relative; | ||||
| 		z-index: 10; | ||||
| 		position: sticky; | ||||
| 		top: var(--stickyTop, 0px); | ||||
| 		padding: var(--x-padding); | ||||
| 		-webkit-backdrop-filter: var(--blur, blur(8px)); | ||||
| 		backdrop-filter: var(--blur, blur(20px)); | ||||
| 
 | ||||
| 		> .title { | ||||
| 			display: grid; | ||||
| 			place-content: center; | ||||
| 			margin: 0; | ||||
| 			padding: 12px 16px 12px 0; | ||||
| 		} | ||||
| 
 | ||||
| 		> .divider { | ||||
| 			flex: 1; | ||||
| 			margin: auto; | ||||
| 			height: 1px; | ||||
| 			background: var(--divider); | ||||
| 		} | ||||
| 
 | ||||
| 		> button { | ||||
| 			padding: 12px 0 12px 16px; | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| @container (max-width: 500px) { | ||||
| 	.ssazuxis { | ||||
| 		> header { | ||||
| 			> .title { | ||||
| 				padding: 8px 10px 8px 0; | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| </style> | ||||
|  | @ -1,153 +1,177 @@ | |||
| <template> | ||||
| <div class="ssazuxis"> | ||||
| 	<header class="_button" :style="{ background: bg }" @click="showBody = !showBody"> | ||||
| 		<div class="title"><div><slot name="header"></slot></div></div> | ||||
| 		<div class="divider"></div> | ||||
| 		<button class="_button"> | ||||
| 			<template v-if="showBody"><i class="ti ti-chevron-up"></i></template> | ||||
| 			<template v-else><i class="ti ti-chevron-down"></i></template> | ||||
| 		</button> | ||||
| 	</header> | ||||
| 	<Transition | ||||
| 		:name="$store.state.animation ? 'folder-toggle' : ''" | ||||
| 		@enter="enter" | ||||
| 		@after-enter="afterEnter" | ||||
| 		@leave="leave" | ||||
| 		@after-leave="afterLeave" | ||||
| 	> | ||||
| 		<div v-show="showBody"> | ||||
| 			<slot></slot> | ||||
| 		</div> | ||||
| 	</Transition> | ||||
| <div ref="rootEl" class="dwzlatin" :class="{ opened }"> | ||||
| 	<div class="header _button" @click="toggle"> | ||||
| 		<span class="icon"><slot name="icon"></slot></span> | ||||
| 		<span class="text"><slot name="label"></slot></span> | ||||
| 		<span class="right"> | ||||
| 			<span class="text"><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> | ||||
| 		</span> | ||||
| 	</div> | ||||
| 	<div v-if="openedAtLeastOnce" class="body" :class="{ bgSame }" :style="{ maxHeight: maxHeight ? `${maxHeight}px` : null }"> | ||||
| 		<Transition | ||||
| 			:name="$store.state.animation ? 'folder-toggle' : ''" | ||||
| 			@enter="enter" | ||||
| 			@after-enter="afterEnter" | ||||
| 			@leave="leave" | ||||
| 			@after-leave="afterLeave" | ||||
| 		> | ||||
| 			<KeepAlive> | ||||
| 				<div v-show="opened"> | ||||
| 					<MkSpacer :margin-min="14" :margin-max="22"> | ||||
| 						<slot></slot> | ||||
| 					</MkSpacer> | ||||
| 				</div> | ||||
| 			</KeepAlive> | ||||
| 		</Transition> | ||||
| 	</div> | ||||
| </div> | ||||
| </template> | ||||
| 
 | ||||
| <script lang="ts"> | ||||
| import { defineComponent } from 'vue'; | ||||
| import tinycolor from 'tinycolor2'; | ||||
| import { miLocalStorage } from '@/local-storage'; | ||||
| <script lang="ts" setup> | ||||
| import { nextTick, onMounted } from 'vue'; | ||||
| 
 | ||||
| const miLocalStoragePrefix = 'ui:folder:' as const; | ||||
| const props = withDefaults(defineProps<{ | ||||
| 	defaultOpen: boolean; | ||||
| 	maxHeight: number | null; | ||||
| }>(), { | ||||
| 	defaultOpen: false, | ||||
| 	maxHeight: null, | ||||
| }); | ||||
| 
 | ||||
| export default defineComponent({ | ||||
| 	props: { | ||||
| 		expanded: { | ||||
| 			type: Boolean, | ||||
| 			required: false, | ||||
| 			default: true, | ||||
| 		}, | ||||
| 		persistKey: { | ||||
| 			type: String, | ||||
| 			required: false, | ||||
| 			default: null, | ||||
| 		}, | ||||
| 	}, | ||||
| 	data() { | ||||
| 		return { | ||||
| 			bg: null, | ||||
| 			showBody: (this.persistKey && miLocalStorage.getItem(`${miLocalStoragePrefix}${this.persistKey}`)) ? (miLocalStorage.getItem(`${miLocalStoragePrefix}${this.persistKey}`) === 't') : this.expanded, | ||||
| 		}; | ||||
| 	}, | ||||
| 	watch: { | ||||
| 		showBody() { | ||||
| 			if (this.persistKey) { | ||||
| 				miLocalStorage.setItem(`${miLocalStoragePrefix}${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; | ||||
| 		}, | ||||
| const getBgColor = (el: HTMLElement) => { | ||||
| 	const style = window.getComputedStyle(el); | ||||
| 	if (style.backgroundColor && !['rgba(0, 0, 0, 0)', 'rgba(0,0,0,0)', 'transparent'].includes(style.backgroundColor)) { | ||||
| 		return style.backgroundColor; | ||||
| 	} else { | ||||
| 		return el.parentElement ? getBgColor(el.parentElement) : 'transparent'; | ||||
| 	} | ||||
| }; | ||||
| 
 | ||||
| 		enter(el) { | ||||
| 			const elementHeight = el.getBoundingClientRect().height; | ||||
| 			el.style.height = 0; | ||||
| 			el.offsetHeight; // reflow | ||||
| 			el.style.height = elementHeight + 'px'; | ||||
| 		}, | ||||
| 		afterEnter(el) { | ||||
| 			el.style.height = null; | ||||
| 		}, | ||||
| 		leave(el) { | ||||
| 			const elementHeight = el.getBoundingClientRect().height; | ||||
| 			el.style.height = elementHeight + 'px'; | ||||
| 			el.offsetHeight; // reflow | ||||
| 			el.style.height = 0; | ||||
| 		}, | ||||
| 		afterLeave(el) { | ||||
| 			el.style.height = null; | ||||
| 		}, | ||||
| 	}, | ||||
| let rootEl = $ref<HTMLElement>(); | ||||
| let bgSame = $ref(false); | ||||
| let opened = $ref(props.defaultOpen); | ||||
| let openedAtLeastOnce = $ref(props.defaultOpen); | ||||
| 
 | ||||
| function enter(el) { | ||||
| 	const elementHeight = el.getBoundingClientRect().height; | ||||
| 	el.style.height = 0; | ||||
| 	el.offsetHeight; // reflow | ||||
| 	el.style.height = Math.min(elementHeight, props.maxHeight ?? Infinity) + '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; | ||||
| 	} | ||||
| 
 | ||||
| 	nextTick(() => { | ||||
| 		opened = !opened; | ||||
| 	}); | ||||
| } | ||||
| 
 | ||||
| onMounted(() => { | ||||
| 	const computedStyle = getComputedStyle(document.documentElement); | ||||
| 	const parentBg = getBgColor(rootEl.parentElement); | ||||
| 	const myBg = computedStyle.getPropertyValue('--panel'); | ||||
| 	bgSame = parentBg === myBg; | ||||
| }); | ||||
| </script> | ||||
| 
 | ||||
| <style lang="scss" scoped> | ||||
| .folder-toggle-enter-active, .folder-toggle-leave-active { | ||||
| 	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 { | ||||
| 	opacity: 0; | ||||
| } | ||||
| .folder-toggle-leave-to { | ||||
| .folder-toggle-enter-from, .folder-toggle-leave-to { | ||||
| 	opacity: 0; | ||||
| } | ||||
| 
 | ||||
| .ssazuxis { | ||||
| 	position: relative; | ||||
| .dwzlatin { | ||||
| 	display: block; | ||||
| 
 | ||||
| 	> header { | ||||
| 	> .header { | ||||
| 		display: flex; | ||||
| 		position: relative; | ||||
| 		z-index: 10; | ||||
| 		position: sticky; | ||||
| 		top: var(--stickyTop, 0px); | ||||
| 		padding: var(--x-padding); | ||||
| 		-webkit-backdrop-filter: var(--blur, blur(8px)); | ||||
| 		backdrop-filter: var(--blur, blur(20px)); | ||||
| 		align-items: center; | ||||
| 		width: 100%; | ||||
| 		box-sizing: border-box; | ||||
| 		padding: 10px 14px 10px 14px; | ||||
| 		background: var(--buttonBg); | ||||
| 		border-radius: 6px; | ||||
| 
 | ||||
| 		> .title { | ||||
| 			display: grid; | ||||
| 			place-content: center; | ||||
| 			margin: 0; | ||||
| 			padding: 12px 16px 12px 0; | ||||
| 		&:hover { | ||||
| 			text-decoration: none; | ||||
| 			background: var(--buttonHoverBg); | ||||
| 		} | ||||
| 
 | ||||
| 		> .divider { | ||||
| 			flex: 1; | ||||
| 			margin: auto; | ||||
| 			height: 1px; | ||||
| 			background: var(--divider); | ||||
| 		&.active { | ||||
| 			color: var(--accent); | ||||
| 			background: var(--buttonHoverBg); | ||||
| 		} | ||||
| 
 | ||||
| 		> button { | ||||
| 			padding: 12px 0 12px 16px; | ||||
| 		> .icon { | ||||
| 			margin-right: 0.75em; | ||||
| 			flex-shrink: 0; | ||||
| 			text-align: center; | ||||
| 			opacity: 0.8; | ||||
| 
 | ||||
| 			&:empty { | ||||
| 				display: none; | ||||
| 
 | ||||
| 				& + .text { | ||||
| 					padding-left: 4px; | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
| 
 | ||||
| 		> .text { | ||||
| 			white-space: nowrap; | ||||
| 			text-overflow: ellipsis; | ||||
| 			overflow: hidden; | ||||
| 			padding-right: 12px; | ||||
| 		} | ||||
| 
 | ||||
| 		> .right { | ||||
| 			margin-left: auto; | ||||
| 			opacity: 0.7; | ||||
| 			white-space: nowrap; | ||||
| 
 | ||||
| 			> .text:not(:empty) { | ||||
| 				margin-right: 0.75em; | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| @container (max-width: 500px) { | ||||
| 	.ssazuxis { | ||||
| 		> header { | ||||
| 			> .title { | ||||
| 				padding: 8px 10px 8px 0; | ||||
| 			} | ||||
| 	> .body { | ||||
| 		background: var(--panel); | ||||
| 		border-radius: 0 0 6px 6px; | ||||
| 		container-type: inline-size; | ||||
| 		overflow: auto; | ||||
| 
 | ||||
| 		&.bgSame { | ||||
| 			background: var(--bg); | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	&.opened { | ||||
| 		> .header { | ||||
| 			border-radius: 6px 6px 0 0; | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  |  | |||
|  | @ -1,6 +1,6 @@ | |||
| <template> | ||||
| <div :class="$style.root"> | ||||
| 	<MkFolder class="item"> | ||||
| 	<MkFoldableSection class="item"> | ||||
| 		<template #header>Chart</template> | ||||
| 		<div :class="$style.chart"> | ||||
| 			<div class="selects"> | ||||
|  | @ -34,9 +34,9 @@ | |||
| 				<MkChart :src="chartSrc" :span="chartSpan" :limit="chartLimit" :detailed="true"></MkChart> | ||||
| 			</div> | ||||
| 		</div> | ||||
| 	</MkFolder> | ||||
| 	</MkFoldableSection> | ||||
| 
 | ||||
| 	<MkFolder class="item"> | ||||
| 	<MkFoldableSection class="item"> | ||||
| 		<template #header>Active users heatmap</template> | ||||
| 		<MkSelect v-model="heatmapSrc" style="margin: 0 0 12px 0;"> | ||||
| 			<option value="active-users">Active users</option> | ||||
|  | @ -48,16 +48,16 @@ | |||
| 		<div class="_panel" :class="$style.heatmap"> | ||||
| 			<MkHeatmap :src="heatmapSrc"/> | ||||
| 		</div> | ||||
| 	</MkFolder> | ||||
| 	</MkFoldableSection> | ||||
| 
 | ||||
| 	<MkFolder class="item"> | ||||
| 	<MkFoldableSection class="item"> | ||||
| 		<template #header>Retention rate</template> | ||||
| 		<div class="_panel" :class="$style.retention"> | ||||
| 			<MkRetentionHeatmap/> | ||||
| 		</div> | ||||
| 	</MkFolder> | ||||
| 	</MkFoldableSection> | ||||
| 
 | ||||
| 	<MkFolder class="item"> | ||||
| 	<MkFoldableSection class="item"> | ||||
| 		<template #header>Federation</template> | ||||
| 		<div :class="$style.federation"> | ||||
| 			<div class="pies"> | ||||
|  | @ -71,7 +71,7 @@ | |||
| 				</div> | ||||
| 			</div> | ||||
| 		</div> | ||||
| 	</MkFolder> | ||||
| 	</MkFoldableSection> | ||||
| </div> | ||||
| </template> | ||||
| 
 | ||||
|  | @ -84,7 +84,7 @@ import { useChartTooltip } from '@/scripts/use-chart-tooltip'; | |||
| import * as os from '@/os'; | ||||
| import { i18n } from '@/i18n'; | ||||
| import MkHeatmap from '@/components/MkHeatmap.vue'; | ||||
| import MkFolder from '@/components/MkFolder.vue'; | ||||
| import MkFoldableSection from '@/components/MkFoldableSection.vue'; | ||||
| import MkRetentionHeatmap from '@/components/MkRetentionHeatmap.vue'; | ||||
| import { initChart } from '@/scripts/init-chart'; | ||||
| 
 | ||||
|  |  | |||
|  | @ -1,175 +0,0 @@ | |||
| <template> | ||||
| <div ref="rootEl" class="dwzlatin" :class="{ opened }"> | ||||
| 	<div class="header _button" @click="toggle"> | ||||
| 		<span class="icon"><slot name="icon"></slot></span> | ||||
| 		<span class="text"><slot name="label"></slot></span> | ||||
| 		<span class="right"> | ||||
| 			<span class="text"><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> | ||||
| 		</span> | ||||
| 	</div> | ||||
| 	<div v-if="openedAtLeastOnce" class="body" :class="{ bgSame }"> | ||||
| 		<Transition | ||||
| 			:name="$store.state.animation ? 'folder-toggle' : ''" | ||||
| 			@enter="enter" | ||||
| 			@after-enter="afterEnter" | ||||
| 			@leave="leave" | ||||
| 			@after-leave="afterLeave" | ||||
| 		> | ||||
| 			<KeepAlive> | ||||
| 				<div v-show="opened"> | ||||
| 					<MkSpacer :margin-min="14" :margin-max="22"> | ||||
| 						<slot></slot> | ||||
| 					</MkSpacer> | ||||
| 				</div> | ||||
| 			</KeepAlive> | ||||
| 		</Transition> | ||||
| 	</div> | ||||
| </div> | ||||
| </template> | ||||
| 
 | ||||
| <script lang="ts" setup> | ||||
| import { nextTick, onMounted } from 'vue'; | ||||
| 
 | ||||
| const props = withDefaults(defineProps<{ | ||||
| 	defaultOpen: boolean; | ||||
| }>(), { | ||||
| 	defaultOpen: false, | ||||
| }); | ||||
| 
 | ||||
| const getBgColor = (el: HTMLElement) => { | ||||
| 	const style = window.getComputedStyle(el); | ||||
| 	if (style.backgroundColor && !['rgba(0, 0, 0, 0)', 'rgba(0,0,0,0)', 'transparent'].includes(style.backgroundColor)) { | ||||
| 		return style.backgroundColor; | ||||
| 	} else { | ||||
| 		return el.parentElement ? getBgColor(el.parentElement) : 'transparent'; | ||||
| 	} | ||||
| }; | ||||
| 
 | ||||
| let rootEl = $ref<HTMLElement>(); | ||||
| let bgSame = $ref(false); | ||||
| let opened = $ref(props.defaultOpen); | ||||
| let openedAtLeastOnce = $ref(props.defaultOpen); | ||||
| 
 | ||||
| function enter(el) { | ||||
| 	const elementHeight = el.getBoundingClientRect().height; | ||||
| 	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; | ||||
| 	} | ||||
| 
 | ||||
| 	nextTick(() => { | ||||
| 		opened = !opened; | ||||
| 	}); | ||||
| } | ||||
| 
 | ||||
| onMounted(() => { | ||||
| 	const computedStyle = getComputedStyle(document.documentElement); | ||||
| 	const parentBg = getBgColor(rootEl.parentElement); | ||||
| 	const myBg = computedStyle.getPropertyValue('--panel'); | ||||
| 	bgSame = parentBg === myBg; | ||||
| }); | ||||
| </script> | ||||
| 
 | ||||
| <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 { | ||||
| 	display: block; | ||||
| 
 | ||||
| 	> .header { | ||||
| 		display: flex; | ||||
| 		align-items: center; | ||||
| 		width: 100%; | ||||
| 		box-sizing: border-box; | ||||
| 		padding: 10px 14px 10px 14px; | ||||
| 		background: var(--buttonBg); | ||||
| 		border-radius: 6px; | ||||
| 
 | ||||
| 		&:hover { | ||||
| 			text-decoration: none; | ||||
| 			background: var(--buttonHoverBg); | ||||
| 		} | ||||
| 
 | ||||
| 		&.active { | ||||
| 			color: var(--accent); | ||||
| 			background: var(--buttonHoverBg); | ||||
| 		} | ||||
| 
 | ||||
| 		> .icon { | ||||
| 			margin-right: 0.75em; | ||||
| 			flex-shrink: 0; | ||||
| 			text-align: center; | ||||
| 			opacity: 0.8; | ||||
| 
 | ||||
| 			&:empty { | ||||
| 				display: none; | ||||
| 
 | ||||
| 				& + .text { | ||||
| 					padding-left: 4px; | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
| 
 | ||||
| 		> .text { | ||||
| 			white-space: nowrap; | ||||
| 			text-overflow: ellipsis; | ||||
| 			overflow: hidden; | ||||
| 			padding-right: 12px; | ||||
| 		} | ||||
| 
 | ||||
| 		> .right { | ||||
| 			margin-left: auto; | ||||
| 			opacity: 0.7; | ||||
| 			white-space: nowrap; | ||||
| 
 | ||||
| 			> .text:not(:empty) { | ||||
| 				margin-right: 0.75em; | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	> .body { | ||||
| 		background: var(--panel); | ||||
| 		border-radius: 0 0 6px 6px; | ||||
| 		container-type: inline-size; | ||||
| 
 | ||||
| 		&.bgSame { | ||||
| 			background: var(--bg); | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	&.opened { | ||||
| 		> .header { | ||||
| 			border-radius: 6px 6px 0 0; | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| </style> | ||||
|  | @ -12,19 +12,19 @@ | |||
| 		--> | ||||
| 	</div> | ||||
| 
 | ||||
| 	<MkFolder v-if="searchEmojis" class="emojis"> | ||||
| 	<MkFoldableSection v-if="searchEmojis" class="emojis"> | ||||
| 		<template #header>{{ $ts.searchResult }}</template> | ||||
| 		<div class="zuvgdzyt"> | ||||
| 			<XEmoji v-for="emoji in searchEmojis" :key="emoji.name" class="emoji" :emoji="emoji"/> | ||||
| 		</div> | ||||
| 	</MkFolder> | ||||
| 	</MkFoldableSection> | ||||
| 	 | ||||
| 	<MkFolder v-for="category in customEmojiCategories" v-once :key="category" class="emojis"> | ||||
| 	<MkFoldableSection v-for="category in customEmojiCategories" v-once :key="category" class="emojis"> | ||||
| 		<template #header>{{ category || $ts.other }}</template> | ||||
| 		<div class="zuvgdzyt"> | ||||
| 			<XEmoji v-for="emoji in customEmojis.filter(e => e.category === category)" :key="emoji.name" class="emoji" :emoji="emoji"/> | ||||
| 		</div> | ||||
| 	</MkFolder> | ||||
| 	</MkFoldableSection> | ||||
| </div> | ||||
| </template> | ||||
| 
 | ||||
|  | @ -34,7 +34,7 @@ import XEmoji from './emojis.emoji.vue'; | |||
| import MkButton from '@/components/MkButton.vue'; | ||||
| import MkInput from '@/components/MkInput.vue'; | ||||
| import MkSelect from '@/components/MkSelect.vue'; | ||||
| import MkFolder from '@/components/MkFolder.vue'; | ||||
| import MkFoldableSection from '@/components/MkFoldableSection.vue'; | ||||
| import MkTab from '@/components/MkTab.vue'; | ||||
| import * as os from '@/os'; | ||||
| import { emojiCategories, emojiTags } from '@/instance'; | ||||
|  | @ -44,7 +44,7 @@ export default defineComponent({ | |||
| 		MkButton, | ||||
| 		MkInput, | ||||
| 		MkSelect, | ||||
| 		MkFolder, | ||||
| 		MkFoldableSection, | ||||
| 		MkTab, | ||||
| 		XEmoji, | ||||
| 	}, | ||||
|  |  | |||
|  | @ -4,24 +4,24 @@ | |||
| 	<MkSpacer :content-max="700" :margin-min="16" :margin-max="32"> | ||||
| 		<FormSuspense :p="init"> | ||||
| 			<div class="_gaps_m"> | ||||
| 				<FormFolder> | ||||
| 				<MkFolder> | ||||
| 					<template #icon><i class="ti ti-brand-twitter"></i></template> | ||||
| 					<template #label>Twitter</template> | ||||
| 					<template #suffix>{{ enableTwitterIntegration ? i18n.ts.enabled : i18n.ts.disabled }}</template> | ||||
| 					<XTwitter/> | ||||
| 				</FormFolder> | ||||
| 				<FormFolder> | ||||
| 				</MkFolder> | ||||
| 				<MkFolder> | ||||
| 					<template #icon><i class="ti ti-brand-github"></i></template> | ||||
| 					<template #label>GitHub</template> | ||||
| 					<template #suffix>{{ enableGithubIntegration ? i18n.ts.enabled : i18n.ts.disabled }}</template> | ||||
| 					<XGithub/> | ||||
| 				</FormFolder> | ||||
| 				<FormFolder> | ||||
| 				</MkFolder> | ||||
| 				<MkFolder> | ||||
| 					<template #icon><i class="ti ti-brand-discord"></i></template> | ||||
| 					<template #label>Discord</template> | ||||
| 					<template #suffix>{{ enableDiscordIntegration ? i18n.ts.enabled : i18n.ts.disabled }}</template> | ||||
| 					<XDiscord/> | ||||
| 				</FormFolder> | ||||
| 				</MkFolder> | ||||
| 			</div> | ||||
| 		</FormSuspense> | ||||
| 	</MkSpacer> | ||||
|  | @ -34,7 +34,7 @@ import XTwitter from './integrations.twitter.vue'; | |||
| import XGithub from './integrations.github.vue'; | ||||
| import XDiscord from './integrations.discord.vue'; | ||||
| import FormSuspense from '@/components/form/suspense.vue'; | ||||
| import FormFolder from '@/components/form/folder.vue'; | ||||
| import MkFolder from '@/components/MkFolder.vue'; | ||||
| import * as os from '@/os'; | ||||
| import { i18n } from '@/i18n'; | ||||
| import { definePageMetadata } from '@/scripts/page-metadata'; | ||||
|  |  | |||
|  | @ -1,60 +1,60 @@ | |||
| <template> | ||||
| <MkSpacer :content-max="1000"> | ||||
| 	<div ref="rootEl" class="edbbcaef"> | ||||
| 		<MkFolder class="item"> | ||||
| 		<MkFoldableSection class="item"> | ||||
| 			<template #header>Stats</template> | ||||
| 			<XStats/> | ||||
| 		</MkFolder> | ||||
| 		</MkFoldableSection> | ||||
| 
 | ||||
| 		<MkFolder class="item"> | ||||
| 		<MkFoldableSection class="item"> | ||||
| 			<template #header>Active users</template> | ||||
| 			<XActiveUsers/> | ||||
| 		</MkFolder> | ||||
| 		</MkFoldableSection> | ||||
| 
 | ||||
| 		<MkFolder class="item"> | ||||
| 		<MkFoldableSection class="item"> | ||||
| 			<template #header>Heatmap</template> | ||||
| 			<XHeatmap/> | ||||
| 		</MkFolder> | ||||
| 		</MkFoldableSection> | ||||
| 
 | ||||
| 		<MkFolder class="item"> | ||||
| 		<MkFoldableSection class="item"> | ||||
| 			<template #header>Retention rate</template> | ||||
| 			<XRetention/> | ||||
| 		</MkFolder> | ||||
| 		</MkFoldableSection> | ||||
| 
 | ||||
| 		<MkFolder class="item"> | ||||
| 		<MkFoldableSection class="item"> | ||||
| 			<template #header>Moderators</template> | ||||
| 			<XModerators/> | ||||
| 		</MkFolder> | ||||
| 		</MkFoldableSection> | ||||
| 
 | ||||
| 		<MkFolder class="item"> | ||||
| 		<MkFoldableSection class="item"> | ||||
| 			<template #header>Federation</template> | ||||
| 			<XFederation/> | ||||
| 		</MkFolder> | ||||
| 		</MkFoldableSection> | ||||
| 		 | ||||
| 		<MkFolder class="item"> | ||||
| 		<MkFoldableSection class="item"> | ||||
| 			<template #header>Instances</template> | ||||
| 			<XInstances/> | ||||
| 		</MkFolder> | ||||
| 		</MkFoldableSection> | ||||
| 
 | ||||
| 		<MkFolder class="item"> | ||||
| 		<MkFoldableSection class="item"> | ||||
| 			<template #header>Ap requests</template> | ||||
| 			<XApRequests/> | ||||
| 		</MkFolder> | ||||
| 		</MkFoldableSection> | ||||
| 
 | ||||
| 		<MkFolder class="item"> | ||||
| 		<MkFoldableSection class="item"> | ||||
| 			<template #header>New users</template> | ||||
| 			<XUsers/> | ||||
| 		</MkFolder> | ||||
| 		</MkFoldableSection> | ||||
| 
 | ||||
| 		<MkFolder class="item"> | ||||
| 		<MkFoldableSection class="item"> | ||||
| 			<template #header>Deliver queue</template> | ||||
| 			<XQueue domain="deliver"/> | ||||
| 		</MkFolder> | ||||
| 		</MkFoldableSection> | ||||
| 
 | ||||
| 		<MkFolder class="item"> | ||||
| 		<MkFoldableSection class="item"> | ||||
| 			<template #header>Inbox queue</template> | ||||
| 			<XQueue domain="inbox"/> | ||||
| 		</MkFolder> | ||||
| 		</MkFoldableSection> | ||||
| 	</div> | ||||
| </MkSpacer> | ||||
| </template> | ||||
|  | @ -79,7 +79,7 @@ import { i18n } from '@/i18n'; | |||
| import { definePageMetadata } from '@/scripts/page-metadata'; | ||||
| import { defaultStore } from '@/store'; | ||||
| import MkFileListForAdmin from '@/components/MkFileListForAdmin.vue'; | ||||
| import MkFolder from '@/components/MkFolder.vue'; | ||||
| import MkFoldableSection from '@/components/MkFoldableSection.vue'; | ||||
| 
 | ||||
| const rootEl = $shallowRef<HTMLElement>(); | ||||
| let serverInfo: any = $ref(null); | ||||
|  |  | |||
|  | @ -4,7 +4,7 @@ | |||
| 	<MkSpacer :content-max="700" :margin-min="16" :margin-max="32"> | ||||
| 		<FormSuspense :p="init"> | ||||
| 			<div class="_gaps_m"> | ||||
| 				<FormFolder> | ||||
| 				<MkFolder> | ||||
| 					<template #icon><i class="ti ti-shield"></i></template> | ||||
| 					<template #label>{{ i18n.ts.botProtection }}</template> | ||||
| 					<template v-if="enableHcaptcha" #suffix>hCaptcha</template> | ||||
|  | @ -13,9 +13,9 @@ | |||
| 					<template v-else #suffix>{{ i18n.ts.none }} ({{ i18n.ts.notRecommended }})</template> | ||||
| 
 | ||||
| 					<XBotProtection/> | ||||
| 				</FormFolder> | ||||
| 				</MkFolder> | ||||
| 
 | ||||
| 				<FormFolder> | ||||
| 				<MkFolder> | ||||
| 					<template #icon><i class="ti ti-eye-off"></i></template> | ||||
| 					<template #label>{{ i18n.ts.sensitiveMediaDetection }}</template> | ||||
| 					<template v-if="sensitiveMediaDetection === 'all'" #suffix>{{ i18n.ts.all }}</template> | ||||
|  | @ -56,9 +56,9 @@ | |||
| 
 | ||||
| 						<MkButton primary @click="save"><i class="ti ti-device-floppy"></i> {{ i18n.ts.save }}</MkButton> | ||||
| 					</div> | ||||
| 				</FormFolder> | ||||
| 				</MkFolder> | ||||
| 
 | ||||
| 				<FormFolder> | ||||
| 				<MkFolder> | ||||
| 					<template #label>Active Email Validation</template> | ||||
| 					<template v-if="enableActiveEmailValidation" #suffix>Enabled</template> | ||||
| 					<template v-else #suffix>Disabled</template> | ||||
|  | @ -69,9 +69,9 @@ | |||
| 							<template #label>Enable</template> | ||||
| 						</MkSwitch> | ||||
| 					</div> | ||||
| 				</FormFolder> | ||||
| 				</MkFolder> | ||||
| 
 | ||||
| 				<FormFolder> | ||||
| 				<MkFolder> | ||||
| 					<template #label>Log IP address</template> | ||||
| 					<template v-if="enableIpLogging" #suffix>Enabled</template> | ||||
| 					<template v-else #suffix>Disabled</template> | ||||
|  | @ -81,9 +81,9 @@ | |||
| 							<template #label>Enable</template> | ||||
| 						</MkSwitch> | ||||
| 					</div> | ||||
| 				</FormFolder> | ||||
| 				</MkFolder> | ||||
| 
 | ||||
| 				<FormFolder> | ||||
| 				<MkFolder> | ||||
| 					<template #label>Summaly Proxy</template> | ||||
| 
 | ||||
| 					<div class="_gaps_m"> | ||||
|  | @ -94,7 +94,7 @@ | |||
| 
 | ||||
| 						<MkButton primary @click="save"><i class="ti ti-device-floppy"></i> {{ i18n.ts.save }}</MkButton> | ||||
| 					</div> | ||||
| 				</FormFolder> | ||||
| 				</MkFolder> | ||||
| 			</div> | ||||
| 		</FormSuspense> | ||||
| 	</MkSpacer> | ||||
|  | @ -105,7 +105,7 @@ | |||
| import { } from 'vue'; | ||||
| import XBotProtection from './bot-protection.vue'; | ||||
| import XHeader from './_header_.vue'; | ||||
| import FormFolder from '@/components/form/folder.vue'; | ||||
| import MkFolder from '@/components/MkFolder.vue'; | ||||
| import MkRadios from '@/components/MkRadios.vue'; | ||||
| import MkSwitch from '@/components/MkSwitch.vue'; | ||||
| import FormInfo from '@/components/MkInfo.vue'; | ||||
|  |  | |||
|  | @ -6,52 +6,52 @@ | |||
| 	</MkTab> | ||||
| 	<div v-if="origin === 'local'"> | ||||
| 		<template v-if="tag == null"> | ||||
| 			<MkFolder class="_margin" persist-key="explore-pinned-users"> | ||||
| 			<MkFoldableSection class="_margin" persist-key="explore-pinned-users"> | ||||
| 				<template #header><i class="fas fa-bookmark ti-fw" style="margin-right: 0.5em;"></i>{{ i18n.ts.pinnedUsers }}</template> | ||||
| 				<XUserList :pagination="pinnedUsers"/> | ||||
| 			</MkFolder> | ||||
| 			<MkFolder class="_margin" persist-key="explore-popular-users"> | ||||
| 			</MkFoldableSection> | ||||
| 			<MkFoldableSection class="_margin" persist-key="explore-popular-users"> | ||||
| 				<template #header><i class="fas fa-chart-line ti-fw" style="margin-right: 0.5em;"></i>{{ i18n.ts.popularUsers }}</template> | ||||
| 				<XUserList :pagination="popularUsers"/> | ||||
| 			</MkFolder> | ||||
| 			<MkFolder class="_margin" persist-key="explore-recently-updated-users"> | ||||
| 			</MkFoldableSection> | ||||
| 			<MkFoldableSection class="_margin" persist-key="explore-recently-updated-users"> | ||||
| 				<template #header><i class="fas fa-comment-alt ti-fw" style="margin-right: 0.5em;"></i>{{ i18n.ts.recentlyUpdatedUsers }}</template> | ||||
| 				<XUserList :pagination="recentlyUpdatedUsers"/> | ||||
| 			</MkFolder> | ||||
| 			<MkFolder class="_margin" persist-key="explore-recently-registered-users"> | ||||
| 			</MkFoldableSection> | ||||
| 			<MkFoldableSection class="_margin" persist-key="explore-recently-registered-users"> | ||||
| 				<template #header><i class="ti ti-plus ti-fw" style="margin-right: 0.5em;"></i>{{ i18n.ts.recentlyRegisteredUsers }}</template> | ||||
| 				<XUserList :pagination="recentlyRegisteredUsers"/> | ||||
| 			</MkFolder> | ||||
| 			</MkFoldableSection> | ||||
| 		</template> | ||||
| 	</div> | ||||
| 	<div v-else> | ||||
| 		<MkFolder ref="tagsEl" :foldable="true" :expanded="false" class="_margin"> | ||||
| 		<MkFoldableSection ref="tagsEl" :foldable="true" :expanded="false" class="_margin"> | ||||
| 			<template #header><i class="ti ti-hash ti-fw" style="margin-right: 0.5em;"></i>{{ i18n.ts.popularTags }}</template> | ||||
| 
 | ||||
| 			<div class="vxjfqztj"> | ||||
| 				<MkA v-for="tag in tagsLocal" :key="'local:' + tag.tag" :to="`/explore/tags/${tag.tag}`" class="local">{{ tag.tag }}</MkA> | ||||
| 				<MkA v-for="tag in tagsRemote" :key="'remote:' + tag.tag" :to="`/explore/tags/${tag.tag}`">{{ tag.tag }}</MkA> | ||||
| 			</div> | ||||
| 		</MkFolder> | ||||
| 		</MkFoldableSection> | ||||
| 
 | ||||
| 		<MkFolder v-if="tag != null" :key="`${tag}`" class="_margin"> | ||||
| 		<MkFoldableSection v-if="tag != null" :key="`${tag}`" class="_margin"> | ||||
| 			<template #header><i class="ti ti-hash ti-fw" style="margin-right: 0.5em;"></i>{{ tag }}</template> | ||||
| 			<XUserList :pagination="tagUsers"/> | ||||
| 		</MkFolder> | ||||
| 		</MkFoldableSection> | ||||
| 
 | ||||
| 		<template v-if="tag == null"> | ||||
| 			<MkFolder class="_margin"> | ||||
| 			<MkFoldableSection class="_margin"> | ||||
| 				<template #header><i class="fas fa-chart-line ti-fw" style="margin-right: 0.5em;"></i>{{ i18n.ts.popularUsers }}</template> | ||||
| 				<XUserList :pagination="popularUsersF"/> | ||||
| 			</MkFolder> | ||||
| 			<MkFolder class="_margin"> | ||||
| 			</MkFoldableSection> | ||||
| 			<MkFoldableSection class="_margin"> | ||||
| 				<template #header><i class="fas fa-comment-alt ti-fw" style="margin-right: 0.5em;"></i>{{ i18n.ts.recentlyUpdatedUsers }}</template> | ||||
| 				<XUserList :pagination="recentlyUpdatedUsersF"/> | ||||
| 			</MkFolder> | ||||
| 			<MkFolder class="_margin"> | ||||
| 			</MkFoldableSection> | ||||
| 			<MkFoldableSection class="_margin"> | ||||
| 				<template #header><i class="fas fa-rocket ti-fw" style="margin-right: 0.5em;"></i>{{ i18n.ts.recentlyDiscoveredUsers }}</template> | ||||
| 				<XUserList :pagination="recentlyRegisteredUsersF"/> | ||||
| 			</MkFolder> | ||||
| 			</MkFoldableSection> | ||||
| 		</template> | ||||
| 	</div> | ||||
| </MkSpacer> | ||||
|  | @ -60,7 +60,7 @@ | |||
| <script lang="ts" setup> | ||||
| import { computed, watch } from 'vue'; | ||||
| import XUserList from '@/components/MkUserList.vue'; | ||||
| import MkFolder from '@/components/MkFolder.vue'; | ||||
| import MkFoldableSection from '@/components/MkFoldableSection.vue'; | ||||
| import MkTab from '@/components/MkTab.vue'; | ||||
| import number from '@/filters/number'; | ||||
| import * as os from '@/os'; | ||||
|  | @ -72,7 +72,7 @@ const props = defineProps<{ | |||
| }>(); | ||||
| 
 | ||||
| let origin = $ref('local'); | ||||
| let tagsEl = $shallowRef<InstanceType<typeof MkFolder>>(); | ||||
| let tagsEl = $shallowRef<InstanceType<typeof MkFoldableSection>>(); | ||||
| let tagsLocal = $ref([]); | ||||
| let tagsRemote = $ref([]); | ||||
| 
 | ||||
|  |  | |||
|  | @ -33,7 +33,7 @@ | |||
| import { computed, watch } from 'vue'; | ||||
| import XFeatured from './explore.featured.vue'; | ||||
| import XUsers from './explore.users.vue'; | ||||
| import MkFolder from '@/components/MkFolder.vue'; | ||||
| import MkFoldableSection from '@/components/MkFoldableSection.vue'; | ||||
| import MkInput from '@/components/MkInput.vue'; | ||||
| import MkRadios from '@/components/MkRadios.vue'; | ||||
| import number from '@/filters/number'; | ||||
|  | @ -51,7 +51,7 @@ const props = withDefaults(defineProps<{ | |||
| }); | ||||
| 
 | ||||
| let tab = $ref(props.initialTab); | ||||
| let tagsEl = $shallowRef<InstanceType<typeof MkFolder>>(); | ||||
| let tagsEl = $shallowRef<InstanceType<typeof MkFoldableSection>>(); | ||||
| let searchQuery = $ref(null); | ||||
| let searchOrigin = $ref('combined'); | ||||
| 
 | ||||
|  |  | |||
|  | @ -27,12 +27,12 @@ | |||
| 						</div> | ||||
| 					</div> | ||||
| 				</Transition> | ||||
| 				<FormFolder class="_margin"> | ||||
| 				<MkFolder class="_margin"> | ||||
| 					<template #icon><i class="ti ti-code"></i></template> | ||||
| 					<template #label>{{ i18n.ts._play.viewSource }}</template> | ||||
| 
 | ||||
| 					<MkTextarea :model-value="flash.script" readonly tall class="_monospace" spellcheck="false"></MkTextarea> | ||||
| 				</FormFolder> | ||||
| 				</MkFolder> | ||||
| 				<div :class="$style.footer"> | ||||
| 					<Mfm :text="`By @${flash.user.username}`"/> | ||||
| 					<div class="date"> | ||||
|  | @ -65,7 +65,7 @@ import { definePageMetadata } from '@/scripts/page-metadata'; | |||
| import MkAsUi from '@/components/MkAsUi.vue'; | ||||
| import { AsUiComponent, AsUiRoot, patch, registerAsUiLib, render } from '@/scripts/aiscript/ui'; | ||||
| import { createAiScriptEnv } from '@/scripts/aiscript/api'; | ||||
| import FormFolder from '@/components/form/folder.vue'; | ||||
| import MkFolder from '@/components/MkFolder.vue'; | ||||
| import MkTextarea from '@/components/MkTextarea.vue'; | ||||
| 
 | ||||
| const props = defineProps<{ | ||||
|  |  | |||
|  | @ -4,22 +4,22 @@ | |||
| 	<MkSpacer :content-max="1400"> | ||||
| 		<div class="_root"> | ||||
| 			<div v-if="tab === 'explore'"> | ||||
| 				<MkFolder class="_margin"> | ||||
| 				<MkFoldableSection class="_margin"> | ||||
| 					<template #header><i class="ti ti-clock"></i>{{ i18n.ts.recentPosts }}</template> | ||||
| 					<MkPagination v-slot="{items}" :pagination="recentPostsPagination" :disable-auto-load="true"> | ||||
| 						<div class="vfpdbgtk"> | ||||
| 							<MkGalleryPostPreview v-for="post in items" :key="post.id" :post="post" class="post"/> | ||||
| 						</div> | ||||
| 					</MkPagination> | ||||
| 				</MkFolder> | ||||
| 				<MkFolder class="_margin"> | ||||
| 				</MkFoldableSection> | ||||
| 				<MkFoldableSection class="_margin"> | ||||
| 					<template #header><i class="ti ti-comet"></i>{{ i18n.ts.popularPosts }}</template> | ||||
| 					<MkPagination v-slot="{items}" :pagination="popularPostsPagination" :disable-auto-load="true"> | ||||
| 						<div class="vfpdbgtk"> | ||||
| 							<MkGalleryPostPreview v-for="post in items" :key="post.id" :post="post" class="post"/> | ||||
| 						</div> | ||||
| 					</MkPagination> | ||||
| 				</MkFolder> | ||||
| 				</MkFoldableSection> | ||||
| 			</div> | ||||
| 			<div v-else-if="tab === 'liked'"> | ||||
| 				<MkPagination v-slot="{items}" :pagination="likedPostsPagination"> | ||||
|  | @ -44,7 +44,7 @@ | |||
| <script lang="ts" setup> | ||||
| import { computed, defineComponent, watch } from 'vue'; | ||||
| import XUserList from '@/components/MkUserList.vue'; | ||||
| import MkFolder from '@/components/MkFolder.vue'; | ||||
| import MkFoldableSection from '@/components/MkFoldableSection.vue'; | ||||
| import MkInput from '@/components/MkInput.vue'; | ||||
| import MkButton from '@/components/MkButton.vue'; | ||||
| import MkTab from '@/components/MkTab.vue'; | ||||
|  |  | |||
|  | @ -2,24 +2,24 @@ | |||
| <div class="_gaps_m"> | ||||
| 	<FormSection first> | ||||
| 		<template #label><i class="ti ti-pencil"></i> {{ i18n.ts._exportOrImport.allNotes }}</template> | ||||
| 		<FormFolder> | ||||
| 		<MkFolder> | ||||
| 			<template #label>{{ i18n.ts.export }}</template> | ||||
| 			<template #icon><i class="ti ti-download"></i></template> | ||||
| 			<MkButton primary :class="$style.button" inline @click="exportNotes()"><i class="ti ti-download"></i> {{ i18n.ts.export }}</MkButton> | ||||
| 		</FormFolder> | ||||
| 		</MkFolder> | ||||
| 	</FormSection> | ||||
| 	<FormSection> | ||||
| 		<template #label><i class="ti ti-star"></i> {{ i18n.ts._exportOrImport.favoritedNotes }}</template> | ||||
| 		<FormFolder> | ||||
| 		<MkFolder> | ||||
| 			<template #label>{{ i18n.ts.export }}</template> | ||||
| 			<template #icon><i class="ti ti-download"></i></template> | ||||
| 			<MkButton primary :class="$style.button" inline @click="exportFavorites()"><i class="ti ti-download"></i> {{ i18n.ts.export }}</MkButton> | ||||
| 		</FormFolder> | ||||
| 		</MkFolder> | ||||
| 	</FormSection> | ||||
| 	<FormSection> | ||||
| 		<template #label><i class="ti ti-users"></i> {{ i18n.ts._exportOrImport.followingList }}</template> | ||||
| 		<div class="_gaps_s"> | ||||
| 			<FormFolder> | ||||
| 			<MkFolder> | ||||
| 				<template #label>{{ i18n.ts.export }}</template> | ||||
| 				<template #icon><i class="ti ti-download"></i></template> | ||||
| 				<div class="_gaps_s"> | ||||
|  | @ -31,57 +31,57 @@ | |||
| 					</MkSwitch> | ||||
| 					<MkButton primary :class="$style.button" inline @click="exportFollowing()"><i class="ti ti-download"></i> {{ i18n.ts.export }}</MkButton> | ||||
| 				</div> | ||||
| 			</FormFolder> | ||||
| 			<FormFolder> | ||||
| 			</MkFolder> | ||||
| 			<MkFolder> | ||||
| 				<template #label>{{ i18n.ts.import }}</template> | ||||
| 				<template #icon><i class="ti ti-upload"></i></template> | ||||
| 				<MkButton primary :class="$style.button" inline @click="importFollowing($event)"><i class="ti ti-upload"></i> {{ i18n.ts.import }}</MkButton> | ||||
| 			</FormFolder> | ||||
| 			</MkFolder> | ||||
| 		</div> | ||||
| 	</FormSection> | ||||
| 	<FormSection> | ||||
| 		<template #label><i class="ti ti-users"></i> {{ i18n.ts._exportOrImport.userLists }}</template> | ||||
| 		<div class="_gaps_s"> | ||||
| 			<FormFolder> | ||||
| 			<MkFolder> | ||||
| 				<template #label>{{ i18n.ts.export }}</template> | ||||
| 				<template #icon><i class="ti ti-download"></i></template> | ||||
| 				<MkButton primary :class="$style.button" inline @click="exportUserLists()"><i class="ti ti-download"></i> {{ i18n.ts.export }}</MkButton> | ||||
| 			</FormFolder> | ||||
| 			<FormFolder> | ||||
| 			</MkFolder> | ||||
| 			<MkFolder> | ||||
| 				<template #label>{{ i18n.ts.import }}</template> | ||||
| 				<template #icon><i class="ti ti-upload"></i></template> | ||||
| 				<MkButton primary :class="$style.button" inline @click="importUserLists($event)"><i class="ti ti-upload"></i> {{ i18n.ts.import }}</MkButton> | ||||
| 			</FormFolder> | ||||
| 			</MkFolder> | ||||
| 		</div> | ||||
| 	</FormSection> | ||||
| 	<FormSection> | ||||
| 		<template #label><i class="ti ti-user-off"></i> {{ i18n.ts._exportOrImport.muteList }}</template> | ||||
| 		<div class="_gaps_s"> | ||||
| 			<FormFolder> | ||||
| 			<MkFolder> | ||||
| 				<template #label>{{ i18n.ts.export }}</template> | ||||
| 				<template #icon><i class="ti ti-download"></i></template> | ||||
| 				<MkButton primary :class="$style.button" inline @click="exportMuting()"><i class="ti ti-download"></i> {{ i18n.ts.export }}</MkButton> | ||||
| 			</FormFolder> | ||||
| 			<FormFolder> | ||||
| 			</MkFolder> | ||||
| 			<MkFolder> | ||||
| 				<template #label>{{ i18n.ts.import }}</template> | ||||
| 				<template #icon><i class="ti ti-upload"></i></template> | ||||
| 				<MkButton primary :class="$style.button" inline @click="importMuting($event)"><i class="ti ti-upload"></i> {{ i18n.ts.import }}</MkButton> | ||||
| 			</FormFolder> | ||||
| 			</MkFolder> | ||||
| 		</div> | ||||
| 	</FormSection> | ||||
| 	<FormSection> | ||||
| 		<template #label><i class="ti ti-user-off"></i> {{ i18n.ts._exportOrImport.blockingList }}</template> | ||||
| 		<div class="_gaps_s"> | ||||
| 			<FormFolder> | ||||
| 			<MkFolder> | ||||
| 				<template #label>{{ i18n.ts.export }}</template> | ||||
| 				<template #icon><i class="ti ti-download"></i></template> | ||||
| 				<MkButton primary :class="$style.button" inline @click="exportBlocking()"><i class="ti ti-download"></i> {{ i18n.ts.export }}</MkButton> | ||||
| 			</FormFolder> | ||||
| 			<FormFolder> | ||||
| 			</MkFolder> | ||||
| 			<MkFolder> | ||||
| 				<template #label>{{ i18n.ts.import }}</template> | ||||
| 				<template #icon><i class="ti ti-upload"></i></template> | ||||
| 				<MkButton primary :class="$style.button" inline @click="importBlocking($event)"><i class="ti ti-upload"></i> {{ i18n.ts.import }}</MkButton> | ||||
| 			</FormFolder> | ||||
| 			</MkFolder> | ||||
| 		</div> | ||||
| 	</FormSection> | ||||
| </div> | ||||
|  | @ -91,7 +91,7 @@ | |||
| import { ref } from 'vue'; | ||||
| import MkButton from '@/components/MkButton.vue'; | ||||
| import FormSection from '@/components/form/section.vue'; | ||||
| import FormFolder from '@/components/form/folder.vue'; | ||||
| import MkFolder from '@/components/MkFolder.vue'; | ||||
| import MkSwitch from '@/components/MkSwitch.vue'; | ||||
| import * as os from '@/os'; | ||||
| import { selectFile } from '@/scripts/select-file'; | ||||
|  |  | |||
|  | @ -32,7 +32,7 @@ | |||
| 	<FormSection> | ||||
| 		<div class="_gaps_m"> | ||||
| 			<MkSwitch v-model="rememberNoteVisibility" @update:model-value="save()">{{ i18n.ts.rememberNoteVisibility }}</MkSwitch> | ||||
| 			<FormFolder v-if="!rememberNoteVisibility"> | ||||
| 			<MkFolder v-if="!rememberNoteVisibility"> | ||||
| 				<template #label>{{ i18n.ts.defaultNoteVisibility }}</template> | ||||
| 				<template v-if="defaultNoteVisibility === 'public'" #suffix>{{ i18n.ts._visibility.public }}</template> | ||||
| 				<template v-else-if="defaultNoteVisibility === 'home'" #suffix>{{ i18n.ts._visibility.home }}</template> | ||||
|  | @ -48,7 +48,7 @@ | |||
| 					</MkSelect> | ||||
| 					<MkSwitch v-model="defaultNoteLocalOnly">{{ i18n.ts._visibility.localOnly }}</MkSwitch> | ||||
| 				</div> | ||||
| 			</FormFolder> | ||||
| 			</MkFolder> | ||||
| 		</div> | ||||
| 	</FormSection> | ||||
| 
 | ||||
|  | @ -61,7 +61,7 @@ import { } from 'vue'; | |||
| import MkSwitch from '@/components/MkSwitch.vue'; | ||||
| import MkSelect from '@/components/MkSelect.vue'; | ||||
| import FormSection from '@/components/form/section.vue'; | ||||
| import FormFolder from '@/components/form/folder.vue'; | ||||
| import MkFolder from '@/components/MkFolder.vue'; | ||||
| import * as os from '@/os'; | ||||
| import { defaultStore } from '@/store'; | ||||
| import { i18n } from '@/i18n'; | ||||
|  |  | |||
|  | @ -33,7 +33,7 @@ | |||
| 	</MkSelect> | ||||
| 
 | ||||
| 	<FormSlot> | ||||
| 		<FormFolder> | ||||
| 		<MkFolder> | ||||
| 			<template #icon><i class="ti ti-list"></i></template> | ||||
| 			<template #label>{{ i18n.ts._profile.metadataEdit }}</template> | ||||
| 
 | ||||
|  | @ -51,18 +51,18 @@ | |||
| 					<MkButton inline primary @click="saveFields"><i class="ti ti-check"></i> {{ i18n.ts.save }}</MkButton> | ||||
| 				</div> | ||||
| 			</div> | ||||
| 		</FormFolder> | ||||
| 		</MkFolder> | ||||
| 		<template #caption>{{ i18n.ts._profile.metadataDescription }}</template> | ||||
| 	</FormSlot> | ||||
| 
 | ||||
| 	<FormFolder> | ||||
| 	<MkFolder> | ||||
| 		<template #label>{{ i18n.ts.advancedSettings }}</template> | ||||
| 
 | ||||
| 		<div class="_gaps_m"> | ||||
| 			<MkSwitch v-model="profile.isCat">{{ i18n.ts.flagAsCat }}<template #caption>{{ i18n.ts.flagAsCatDescription }}</template></MkSwitch> | ||||
| 			<MkSwitch v-model="profile.isBot">{{ i18n.ts.flagAsBot }}<template #caption>{{ i18n.ts.flagAsBotDescription }}</template></MkSwitch> | ||||
| 		</div> | ||||
| 	</FormFolder> | ||||
| 	</MkFolder> | ||||
| 
 | ||||
| 	<MkSwitch v-model="profile.showTimelineReplies">{{ i18n.ts.flagShowTimelineReplies }}<template #caption>{{ i18n.ts.flagShowTimelineRepliesDescription }} {{ i18n.ts.reflectMayTakeTime }}</template></MkSwitch> | ||||
| </div> | ||||
|  | @ -76,7 +76,7 @@ import MkTextarea from '@/components/MkTextarea.vue'; | |||
| import MkSwitch from '@/components/MkSwitch.vue'; | ||||
| import MkSelect from '@/components/MkSelect.vue'; | ||||
| import FormSplit from '@/components/form/split.vue'; | ||||
| import FormFolder from '@/components/form/folder.vue'; | ||||
| import MkFolder from '@/components/MkFolder.vue'; | ||||
| import FormSlot from '@/components/form/slot.vue'; | ||||
| import { host } from '@/config'; | ||||
| import { selectFile } from '@/scripts/select-file'; | ||||
|  |  | |||
|  | @ -7,12 +7,12 @@ | |||
| 	<FormSection> | ||||
| 		<template #label>{{ i18n.ts.sounds }}</template> | ||||
| 		<div class="_gaps_s"> | ||||
| 			<FormFolder v-for="type in Object.keys(sounds)" :key="type"> | ||||
| 			<MkFolder v-for="type in Object.keys(sounds)" :key="type"> | ||||
| 				<template #label>{{ $t('_sfx.' + type) }}</template> | ||||
| 				<template #suffix>{{ sounds[type].type ?? i18n.ts.none }}</template> | ||||
| 
 | ||||
| 				<XSound :type="sounds[type].type" :volume="sounds[type].volume" @update="(res) => updated(type, res)"/> | ||||
| 			</FormFolder> | ||||
| 			</MkFolder> | ||||
| 		</div> | ||||
| 	</FormSection> | ||||
| 
 | ||||
|  | @ -27,7 +27,7 @@ import MkRange from '@/components/MkRange.vue'; | |||
| import MkButton from '@/components/MkButton.vue'; | ||||
| import FormLink from '@/components/form/link.vue'; | ||||
| import FormSection from '@/components/form/section.vue'; | ||||
| import FormFolder from '@/components/form/folder.vue'; | ||||
| import MkFolder from '@/components/MkFolder.vue'; | ||||
| import * as os from '@/os'; | ||||
| import { ColdDeviceStorage } from '@/store'; | ||||
| import { playFile } from '@/scripts/sound'; | ||||
|  |  | |||
|  | @ -1,10 +1,10 @@ | |||
| <template> | ||||
| <div class="_gaps_m"> | ||||
| 	<FormFolder v-for="x in statusbars" :key="x.id"> | ||||
| 	<MkFolder v-for="x in statusbars" :key="x.id"> | ||||
| 		<template #label>{{ x.type ?? i18n.ts.notSet }}</template> | ||||
| 		<template #suffix>{{ x.name }}</template> | ||||
| 		<XStatusbar :_id="x.id" :user-lists="userLists"/> | ||||
| 	</FormFolder> | ||||
| 	</MkFolder> | ||||
| 	<MkButton primary @click="add">{{ i18n.ts.add }}</MkButton> | ||||
| </div> | ||||
| </template> | ||||
|  | @ -14,7 +14,7 @@ import { computed, onMounted, ref, watch } from 'vue'; | |||
| import { v4 as uuid } from 'uuid'; | ||||
| import XStatusbar from './statusbar.statusbar.vue'; | ||||
| import MkRadios from '@/components/MkRadios.vue'; | ||||
| import FormFolder from '@/components/form/folder.vue'; | ||||
| import MkFolder from '@/components/MkFolder.vue'; | ||||
| import MkButton from '@/components/MkButton.vue'; | ||||
| import * as os from '@/os'; | ||||
| import { defaultStore } from '@/store'; | ||||
|  |  | |||
|  | @ -3,7 +3,7 @@ | |||
| 	<template #header><MkPageHeader :actions="headerActions" :tabs="headerTabs"/></template> | ||||
| 	<MkSpacer :content-max="800" :margin-min="16" :margin-max="32"> | ||||
| 		<div class="cwepdizn _gaps_m"> | ||||
| 			<FormFolder :default-open="true"> | ||||
| 			<MkFolder :default-open="true"> | ||||
| 				<template #label>{{ i18n.ts.backgroundColor }}</template> | ||||
| 				<div class="cwepdizn-colors"> | ||||
| 					<div class="row"> | ||||
|  | @ -17,9 +17,9 @@ | |||
| 						</button> | ||||
| 					</div> | ||||
| 				</div> | ||||
| 			</FormFolder> | ||||
| 			</MkFolder> | ||||
| 
 | ||||
| 			<FormFolder :default-open="true"> | ||||
| 			<MkFolder :default-open="true"> | ||||
| 				<template #label>{{ i18n.ts.accentColor }}</template> | ||||
| 				<div class="cwepdizn-colors"> | ||||
| 					<div class="row"> | ||||
|  | @ -28,9 +28,9 @@ | |||
| 						</button> | ||||
| 					</div> | ||||
| 				</div> | ||||
| 			</FormFolder> | ||||
| 			</MkFolder> | ||||
| 
 | ||||
| 			<FormFolder :default-open="true"> | ||||
| 			<MkFolder :default-open="true"> | ||||
| 				<template #label>{{ i18n.ts.textColor }}</template> | ||||
| 				<div class="cwepdizn-colors"> | ||||
| 					<div class="row"> | ||||
|  | @ -39,9 +39,9 @@ | |||
| 						</button> | ||||
| 					</div> | ||||
| 				</div> | ||||
| 			</FormFolder> | ||||
| 			</MkFolder> | ||||
| 
 | ||||
| 			<FormFolder :default-open="false"> | ||||
| 			<MkFolder :default-open="false"> | ||||
| 				<template #icon><i class="ti ti-code"></i></template> | ||||
| 				<template #label>{{ i18n.ts.editCode }}</template> | ||||
| 
 | ||||
|  | @ -51,9 +51,9 @@ | |||
| 					</MkTextarea> | ||||
| 					<MkButton primary @click="applyThemeCode">{{ i18n.ts.apply }}</MkButton> | ||||
| 				</div> | ||||
| 			</FormFolder> | ||||
| 			</MkFolder> | ||||
| 
 | ||||
| 			<FormFolder :default-open="false"> | ||||
| 			<MkFolder :default-open="false"> | ||||
| 				<template #label>{{ i18n.ts.addDescription }}</template> | ||||
| 
 | ||||
| 				<div class="_gaps_m"> | ||||
|  | @ -61,7 +61,7 @@ | |||
| 						<template #label>{{ i18n.ts._theme.description }}</template> | ||||
| 					</MkTextarea> | ||||
| 				</div> | ||||
| 			</FormFolder> | ||||
| 			</MkFolder> | ||||
| 		</div> | ||||
| 	</MkSpacer> | ||||
| </MkStickyContainer> | ||||
|  | @ -76,7 +76,7 @@ import JSON5 from 'json5'; | |||
| 
 | ||||
| import MkButton from '@/components/MkButton.vue'; | ||||
| import MkTextarea from '@/components/MkTextarea.vue'; | ||||
| import FormFolder from '@/components/form/folder.vue'; | ||||
| import MkFolder from '@/components/MkFolder.vue'; | ||||
| 
 | ||||
| import { $i } from '@/account'; | ||||
| import { Theme, applyTheme } from '@/scripts/theme'; | ||||
|  |  | |||
|  | @ -77,12 +77,12 @@ | |||
| 
 | ||||
| 						<MkButton v-if="user.host != null" @click="updateRemoteUser"><i class="ti ti-refresh"></i> {{ i18n.ts.updateRemoteUser }}</MkButton> | ||||
| 
 | ||||
| 						<FormFolder> | ||||
| 						<MkFolder> | ||||
| 							<template #label>Raw</template> | ||||
| 
 | ||||
| 							<MkObjectView v-if="ap" tall :value="ap"> | ||||
| 							</MkObjectView> | ||||
| 						</FormFolder> | ||||
| 						</MkFolder> | ||||
| 					</div> | ||||
| 				</FormSection> | ||||
| 			</div> | ||||
|  | @ -98,7 +98,7 @@ | |||
| 				<MkTextarea v-model="moderationNote" manual-save> | ||||
| 					<template #label>Moderation note</template> | ||||
| 				</MkTextarea> | ||||
| 				<FormFolder> | ||||
| 				<MkFolder> | ||||
| 					<template #label>IP</template> | ||||
| 					<MkInfo v-if="!iAmAdmin" warn>{{ i18n.ts.requireAdminForView }}</MkInfo> | ||||
| 					<MkInfo v-else>The date is the IP address was first acknowledged.</MkInfo> | ||||
|  | @ -108,12 +108,12 @@ | |||
| 							<span class="ip">{{ record.ip }}</span> | ||||
| 						</div> | ||||
| 					</template> | ||||
| 				</FormFolder> | ||||
| 				<FormFolder> | ||||
| 				</MkFolder> | ||||
| 				<MkFolder> | ||||
| 					<template #label>{{ i18n.ts.files }}</template> | ||||
| 
 | ||||
| 					<MkFileListForAdmin :pagination="filesPagination" view-mode="grid"/> | ||||
| 				</FormFolder> | ||||
| 				</MkFolder> | ||||
| 				<FormSection> | ||||
| 					<template #label>Drive Capacity Override</template> | ||||
| 
 | ||||
|  | @ -165,7 +165,7 @@ import FormSection from '@/components/form/section.vue'; | |||
| import MkButton from '@/components/MkButton.vue'; | ||||
| import MkInput from '@/components/MkInput.vue'; | ||||
| import FormSplit from '@/components/form/split.vue'; | ||||
| import FormFolder from '@/components/form/folder.vue'; | ||||
| import MkFolder from '@/components/MkFolder.vue'; | ||||
| import MkKeyValue from '@/components/MkKeyValue.vue'; | ||||
| import MkSelect from '@/components/MkSelect.vue'; | ||||
| import FormSuspense from '@/components/form/suspense.vue'; | ||||
|  |  | |||
|  | @ -1,22 +1,22 @@ | |||
| <template> | ||||
| <MkSpacer :content-max="700"> | ||||
| 	<div class="_gaps"> | ||||
| 		<MkFolder class="item"> | ||||
| 		<MkFoldableSection class="item"> | ||||
| 			<template #header><i class="ti ti-activity"></i> Heatmap</template> | ||||
| 			<XHeatmap :user="user" :src="'notes'"/> | ||||
| 		</MkFolder> | ||||
| 		<MkFolder class="item"> | ||||
| 		</MkFoldableSection> | ||||
| 		<MkFoldableSection class="item"> | ||||
| 			<template #header><i class="ti ti-pencil"></i> Notes</template> | ||||
| 			<XNotes :user="user"/> | ||||
| 		</MkFolder> | ||||
| 		<MkFolder class="item"> | ||||
| 		</MkFoldableSection> | ||||
| 		<MkFoldableSection class="item"> | ||||
| 			<template #header><i class="ti ti-users"></i> Following</template> | ||||
| 			<XFollowing :user="user"/> | ||||
| 		</MkFolder> | ||||
| 		<MkFolder class="item"> | ||||
| 		</MkFoldableSection> | ||||
| 		<MkFoldableSection class="item"> | ||||
| 			<template #header><i class="ti ti-eye"></i> PV</template> | ||||
| 			<XPv :user="user"/> | ||||
| 		</MkFolder> | ||||
| 		</MkFoldableSection> | ||||
| 	</div> | ||||
| </MkSpacer> | ||||
| </template> | ||||
|  | @ -28,7 +28,7 @@ import XHeatmap from './activity.heatmap.vue'; | |||
| import XPv from './activity.pv.vue'; | ||||
| import XNotes from './activity.notes.vue'; | ||||
| import XFollowing from './activity.following.vue'; | ||||
| import MkFolder from '@/components/MkFolder.vue'; | ||||
| import MkFoldableSection from '@/components/MkFoldableSection.vue'; | ||||
| 
 | ||||
| const props = defineProps<{ | ||||
| 	user: misskey.entities.User; | ||||
|  |  | |||
|  | @ -115,7 +115,7 @@ import XUserTimeline from './index.timeline.vue'; | |||
| import XNote from '@/components/MkNote.vue'; | ||||
| import MkFollowButton from '@/components/MkFollowButton.vue'; | ||||
| import MkContainer from '@/components/MkContainer.vue'; | ||||
| import MkFolder from '@/components/MkFolder.vue'; | ||||
| import MkFoldableSection from '@/components/MkFoldableSection.vue'; | ||||
| import MkRemoteCaution from '@/components/MkRemoteCaution.vue'; | ||||
| import MkTab from '@/components/MkTab.vue'; | ||||
| import MkInfo from '@/components/MkInfo.vue'; | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue