Toolbar.vue
4.14 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
<script setup>
/**
* 筛选工具条。**列表页的筛选区只能用它** —— 页面自己搭栅格,就会各拍各的列数和宽度,一个后台里
* 三种筛选区长相。
*
* **一格 = label 在上、控件在下**,不是 label 贴在控件左边横排 —— 后者把一排筛选读成一句流水句
* (「时间窗 [x] 状态 [y] 厂商 [z]…」),字段边界只能靠数空格找,且控件左边被长短不一的中文标签顶得
* 参差不齐。
*
* **宽度由栅格给,不由控件自己拍。** 每格 `minmax(200px, 1fr)`,列数按容器宽度自适应;控件填满这一格。
* 各页面不要再给单个字段写死宽度 —— 那正是「用户框比模型框宽一倍」的来源。
*
* 用法:每个字段包一层 `.drama-toolbar-field`(内含 `<label>` + 控件);`actions` slot 放查询/重置,
* 它和最后一行控件**底边对齐**。字段值特别长(request id、时间区间)时加 `.drama-toolbar-field--wide`
* 占两格。
*
* `advanced` slot 放展开式高级筛选:同一套栅格续在第二行,上面一条分隔线。展开与否由页面控制
* (`v-if`),行怎么排由这里定 —— 页面不要为了第二行再搓一个栅格。
*
* `compact` 给只有一两个开关的行(区块标题栏里的启用筛选、图表的维度切换):控件保持自然宽度横排,
* 不进栅格 —— 三个选项的分段控件被拉到一整格宽,是另一种难看。
*/
defineProps({
/** 控件按自然宽度横排,不进栅格。 */
compact: { type: Boolean, default: false },
})
</script>
<template>
<div
class="drama-toolbar"
:class="{ 'is-compact': compact }"
>
<div class="drama-toolbar__main">
<div class="drama-toolbar__filters">
<slot />
</div>
<div
v-if="$slots.actions"
class="drama-toolbar__actions"
>
<slot name="actions" />
</div>
</div>
<div
v-if="$slots.advanced"
class="drama-toolbar__advanced"
>
<slot name="advanced" />
</div>
</div>
</template>
<style scoped>
.drama-toolbar {
display: grid;
gap: var(--drama-space-lg);
}
.drama-toolbar__main {
display: flex;
/* 控件底边成一条线:label 高度不一时也不会把控件顶得错位。 */
align-items: flex-end;
gap: var(--drama-space-lg);
flex-wrap: wrap;
}
.drama-toolbar__filters,
.drama-toolbar__advanced {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
gap: var(--drama-space-md) var(--drama-space-lg);
align-items: end;
}
.drama-toolbar__filters {
flex: 1 1 auto;
}
.drama-toolbar__advanced {
padding-top: var(--drama-space-lg);
border-top: 1px solid var(--drama-color-border);
}
.drama-toolbar__actions {
display: flex;
align-items: center;
gap: var(--drama-space-sm);
margin-left: auto;
}
.drama-toolbar :deep(.drama-toolbar-field) {
display: flex;
flex-direction: column;
gap: var(--drama-space-xs);
/* 不给 0,长值会把这一格撑出栅格。 */
min-width: 0;
}
.drama-toolbar :deep(.drama-toolbar-field > label) {
color: var(--drama-color-text-muted);
font-size: var(--drama-font-size-xs);
font-weight: var(--drama-font-weight-medium);
line-height: var(--drama-line-height-tight);
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
/* 控件撑满这一格 —— 宽度是栅格的事。 */
.drama-toolbar :deep(.drama-input),
.drama-toolbar :deep(.drama-select),
.drama-toolbar :deep(.drama-segmented) {
display: flex;
width: 100%;
}
.drama-toolbar :deep(.drama-segmented__item) {
flex: 1 1 0;
min-width: 0;
}
/* 分段控件横排 3–4 个选项,一格塞不下(英文 "Aborted" 就溢出);它天生占两格。 */
.drama-toolbar :deep(.drama-toolbar-field:has(.drama-segmented)),
.drama-toolbar :deep(.drama-toolbar-field--wide) {
grid-column: span 2;
}
.drama-toolbar.is-compact .drama-toolbar__filters {
display: flex;
flex-wrap: wrap;
align-items: flex-end;
}
.drama-toolbar.is-compact :deep(.drama-input),
.drama-toolbar.is-compact :deep(.drama-select),
.drama-toolbar.is-compact :deep(.drama-segmented) {
width: auto;
}
.drama-toolbar.is-compact :deep(.drama-segmented__item) {
flex: 0 0 auto;
}
</style>