Skip to content
1 change: 1 addition & 0 deletions docs/.vitepress/themeConfig.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ const sharedSidebarItems = [
base: '/components/',
items: [
{ text: 'Container 容器', link: 'container' },
{ text: 'Layout 布局', link: 'layout' },
{ text: 'Bubble 气泡', link: 'bubble' },
{ text: 'Sender 消息输入框', link: 'sender' },
{ text: 'Prompts 提示集', link: 'prompts' },
Expand Down
189 changes: 189 additions & 0 deletions docs/demos/layout/aside-collapse-effect.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,189 @@
<script setup lang="ts">
import { computed, ref } from 'vue'
import { TrLayout } from '@opentiny/tiny-robot'
import { TinyRadio, TinyRadioGroup, TinySlider, TinySwitch } from '@opentiny/vue'
import type { LayoutAsideCollapseEffect, LayoutAsideOptions } from '@opentiny/tiny-robot'

const collapseEffect = ref<LayoutAsideCollapseEffect>('overlay')
const collapsedWidth = ref(72)
const open = ref(true)

const leftAside = computed<LayoutAsideOptions>(() => ({
open: open.value,
expandedWidth: 176,
collapsedWidth: collapsedWidth.value,
collapseEffect: collapseEffect.value,
}))

const hint = computed(() =>
collapseEffect.value === 'overlay' ? '收起时内容层不跟随宽度滑动' : '收起时内容层随宽度一起滑动',
)

const collapsedHint = computed(() =>
collapsedWidth.value === 0 ? '当前收起到 0,主要看收起过程。' : '当前会留一条窄栏,更容易看出两种结果的差别。',
)
</script>

<template>
<div class="layout-collapse-effect-demo">
<div class="layout-collapse-effect-demo__controls">
<div class="layout-collapse-effect-demo__group">
<label class="layout-collapse-effect-demo__field">
<span>收起方式</span>
<tiny-radio-group v-model="collapseEffect">
<tiny-radio label="overlay">overlay</tiny-radio>
<tiny-radio label="slide">slide</tiny-radio>
</tiny-radio-group>
</label>

<label class="layout-collapse-effect-demo__field">
<span>展开</span>
<tiny-switch v-model="open"></tiny-switch>
</label>
</div>

<label class="layout-collapse-effect-demo__field layout-collapse-effect-demo__field--range">
<span class="layout-collapse-effect-demo__range-label">收起宽度</span>
<TinySlider
v-model.number="collapsedWidth"
class="layout-collapse-effect-demo__range"
:min="0"
:max="120"
:step="4"
/>
<strong>{{ collapsedWidth }}px</strong>
</label>
</div>

<TrLayout class="layout-collapse-effect-demo__layout" :left-aside="leftAside">
<template #left-aside>
<div class="layout-collapse-effect-demo__aside">
<div class="layout-collapse-effect-demo__aside-rail" />
<div class="layout-collapse-effect-demo__aside-panel" />
</div>
</template>

<template #main>
<div class="layout-collapse-effect-demo__main">
<strong>{{ collapseEffect }}</strong>
<span>{{ hint }}</span>
<em>{{ collapsedHint }}</em>
</div>
</template>
</TrLayout>
</div>
</template>

<style>
.layout-collapse-effect-demo__layout {
--layout-collapse-effect-demo-aside-bg: color-mix(
in srgb,
var(--vp-c-brand-1, var(--tr-color-primary, #5e7ce0)) 6%,
var(--vp-c-bg, #ffffff)
);
--layout-collapse-effect-demo-rail-bg: color-mix(in srgb, var(--vp-c-text-1, #1f2329) 4%, var(--vp-c-bg, #ffffff));
--layout-collapse-effect-demo-panel-bg: color-mix(
in srgb,
var(--vp-c-brand-1, var(--tr-color-primary, #5e7ce0)) 10%,
var(--vp-c-bg, #ffffff)
);
--tr-layout-height: 216px;
--tr-layout-main-min-width: 0;
--tr-layout-left-aside-bg: var(--layout-collapse-effect-demo-aside-bg);
--tr-layout-main-bg: var(--vp-c-bg, #ffffff);
overflow: hidden;
border: 1px solid var(--vp-c-divider, var(--tr-border-color, #dcdfe6));
border-radius: 12px;
color: var(--vp-c-text-1, var(--tr-text-primary, #1f2329));
}
</style>

<style scoped>
.layout-collapse-effect-demo {
display: grid;
gap: 12px;
}

.layout-collapse-effect-demo__controls {
display: flex;
flex-wrap: wrap;
gap: 12px;
align-items: center;
justify-content: space-between;
}

.layout-collapse-effect-demo__group {
display: inline-flex;
align-items: center;
gap: 16px;
flex-wrap: wrap;
}

.layout-collapse-effect-demo__field {
display: inline-flex;
align-items: center;
gap: 8px;
color: var(--vp-c-text-2, var(--tr-text-secondary, #4e5969));
}

.layout-collapse-effect-demo__field--range {
flex: 1 1 280px;
}

.layout-collapse-effect-demo__range-label {
min-width: 60px;
}

.layout-collapse-effect-demo__range {
min-width: 160px;
flex: 1;
}

.layout-collapse-effect-demo__aside {
display: grid;
grid-template-columns: 48px minmax(0, 1fr);
gap: 10px;
box-sizing: border-box;
width: 176px;
height: 100%;
padding: 12px;
background: var(--layout-collapse-effect-demo-aside-bg);
}

.layout-collapse-effect-demo__aside-rail,
.layout-collapse-effect-demo__aside-panel {
height: 100%;
border-radius: 12px;
}

.layout-collapse-effect-demo__aside-rail {
background: var(--layout-collapse-effect-demo-rail-bg);
}

.layout-collapse-effect-demo__aside-panel {
background: var(--layout-collapse-effect-demo-panel-bg);
}

.layout-collapse-effect-demo__main {
display: grid;
align-content: center;
justify-items: center;
gap: 8px;
height: 100%;
padding: 20px;
box-sizing: border-box;
color: var(--vp-c-text-2, var(--tr-text-secondary, #4e5969));
text-align: center;
background: var(--vp-c-bg, #ffffff);
}

.layout-collapse-effect-demo__main strong {
color: var(--vp-c-text-1, var(--tr-text-primary, #1f2329));
font-size: 14px;
}

.layout-collapse-effect-demo__main em {
font-style: normal;
font-size: 12px;
}
</style>
171 changes: 171 additions & 0 deletions docs/demos/layout/aside-controlled.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,171 @@
<script setup lang="ts">
import { computed, ref } from 'vue'
import { TrLayout } from '@opentiny/tiny-robot'
import { TinyButton, TinySlider } from '@opentiny/vue'
import type { LayoutAsideOptions, LayoutAsideOpenValue, LayoutAsideResizeValue } from '@opentiny/tiny-robot'

const leftOpen = ref(true)
const leftExpandedWidth = ref(220)
const leftWidthMin = 160
const leftWidthMax = 320
const rightOpen = ref(false)

const leftAside = computed<LayoutAsideOptions>(() => ({
open: leftOpen.value,
expandedWidth: leftExpandedWidth.value,
collapsedWidth: 0,
minExpandedWidth: leftWidthMin,
maxExpandedWidth: leftWidthMax,
resizable: true,
}))

const rightAside = computed<LayoutAsideOptions>(() => ({
mode: 'drawer',
open: rightOpen.value,
}))

function updateLeftAsideOpen(detail: LayoutAsideOpenValue) {
leftOpen.value = detail.open
}

function updateLeftAsideWidth(detail: LayoutAsideResizeValue) {
leftExpandedWidth.value = detail.expandedWidth
}

function updateRightAsideOpen(detail: LayoutAsideOpenValue) {
rightOpen.value = detail.open
}
</script>

<template>
<div class="layout-slot-props-demo">
<div class="layout-slot-props-demo__controls">
<div class="layout-slot-props-demo__group">
<span class="layout-slot-props-demo__group-label">左侧栏</span>
<TinyButton :reset-time="0" @click="leftOpen = !leftOpen">
{{ leftOpen ? '收起侧栏' : '展开侧栏' }}
</TinyButton>
<label class="layout-slot-props-demo__range-wrap">
<span class="layout-slot-props-demo__range-label">宽度</span>
<TinySlider
v-model.number="leftExpandedWidth"
class="layout-slot-props-demo__range"
:min="leftWidthMin"
:max="leftWidthMax"
:step="4"
@change="leftOpen = true"
/>
<strong>{{ leftExpandedWidth }}px</strong>
</label>
</div>

<div class="layout-slot-props-demo__group">
<span class="layout-slot-props-demo__group-label">右侧栏</span>
<TinyButton :reset-time="0" @click="rightOpen = !rightOpen">
{{ rightOpen ? '关闭 Drawer' : '打开 Drawer' }}
</TinyButton>
</div>
</div>

<TrLayout
class="layout-slot-props-demo__layout"
:left-aside="leftAside"
:right-aside="rightAside"
@left-aside-open-change="updateLeftAsideOpen"
@left-aside-resize="updateLeftAsideWidth"
@right-aside-open-change="updateRightAsideOpen"
>
<template #left-aside>
<div class="layout-slot-props-demo__aside">
<p v-if="leftOpen">左侧栏宽度:{{ leftExpandedWidth }}px</p>
<p v-else>左侧栏已关闭,请通过外部按钮重新展开。</p>
</div>
</template>

<template #header>
<div class="layout-slot-props-demo__header">Header 区域</div>
</template>

<template #main>
<div class="layout-slot-props-demo__main">Main 区域</div>
</template>

<template #right-aside>
<div class="layout-slot-props-demo__drawer">
<p>Drawer</p>
<p>由外部按钮控制开关。</p>
</div>
</template>
</TrLayout>
</div>
</template>

<style>
.layout-slot-props-demo__layout {
--tr-layout-height: 360px;
overflow: hidden;
border: 1px solid var(--vp-c-divider, var(--tr-border-color, #dcdfe6));
border-radius: 16px;
}
</style>

<style scoped>
.layout-slot-props-demo {
display: grid;
gap: 12px;
}

.layout-slot-props-demo__controls {
display: grid;
gap: 8px;
}

.layout-slot-props-demo__group {
display: flex;
flex-wrap: wrap;
gap: 8px;
align-items: center;
}

.layout-slot-props-demo__group-label {
font-weight: 600;
}

.layout-slot-props-demo__range-wrap {
display: inline-flex;
align-items: center;
gap: 8px;
flex-wrap: wrap;
}

.layout-slot-props-demo__range-label {
font-weight: 600;
}

.layout-slot-props-demo__range {
min-width: 160px;
flex: 1;
}

.layout-slot-props-demo__header {
padding: 12px 16px;
border-bottom: 1px solid var(--vp-c-divider, var(--tr-border-color, #dcdfe6));
}

.layout-slot-props-demo__aside,
.layout-slot-props-demo__drawer,
.layout-slot-props-demo__main {
display: grid;
align-content: start;
gap: 10px;
box-sizing: border-box;
height: 100%;
padding: 16px;
background: var(--vp-c-bg, #ffffff);
}

.layout-slot-props-demo__aside p,
.layout-slot-props-demo__drawer p {
margin: 0;
}
</style>
Loading