refactor api
This commit is contained in:
@@ -0,0 +1,13 @@
|
||||
import view from "./index.vue";
|
||||
import Toolkit from "../../utils/Toolkit";
|
||||
|
||||
export type {
|
||||
DescriptionGridAlign,
|
||||
DescriptionGridItem,
|
||||
DescriptionGridProps
|
||||
} from "./type";
|
||||
|
||||
export const DescriptionGrid = Toolkit.withInstall(view);
|
||||
export default DescriptionGrid;
|
||||
|
||||
|
||||
@@ -0,0 +1,133 @@
|
||||
<template>
|
||||
<div
|
||||
class="cw-description-grid"
|
||||
:class="{
|
||||
bordered,
|
||||
'mobile-single': singleColumnOnMobile
|
||||
}"
|
||||
:style="gridStyle"
|
||||
>
|
||||
<template v-for="item in items" :key="item.key">
|
||||
<div class="cell label" :class="item.labelClass">
|
||||
<slot :name="`label-${item.key}`" :item="item">
|
||||
<span v-text="item.label" />
|
||||
</slot>
|
||||
</div>
|
||||
<div class="cell value" :class="item.valueClass">
|
||||
<slot :name="`value-${item.key}`" :item="item">
|
||||
<span v-text="formatValue(item.value)" />
|
||||
</slot>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { computed } from "vue";
|
||||
import type { CSSProperties, PropType } from "vue";
|
||||
import type { DescriptionGridAlign, DescriptionGridItem } from "./type";
|
||||
|
||||
defineOptions({
|
||||
name: "DescriptionGrid"
|
||||
});
|
||||
|
||||
const props = defineProps({
|
||||
items: {
|
||||
type: Array as PropType<DescriptionGridItem[]>,
|
||||
default: () => []
|
||||
},
|
||||
columns: {
|
||||
type: Number,
|
||||
default: 2
|
||||
},
|
||||
emptyText: {
|
||||
type: String,
|
||||
default: "-"
|
||||
},
|
||||
bordered: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
singleColumnOnMobile: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
labelAlign: {
|
||||
type: String as PropType<DescriptionGridAlign>,
|
||||
default: "left"
|
||||
},
|
||||
valueAlign: {
|
||||
type: String as PropType<DescriptionGridAlign>,
|
||||
default: "left"
|
||||
}
|
||||
});
|
||||
|
||||
const normalizedColumns = computed(() => {
|
||||
if (!props.columns || props.columns < 1) {
|
||||
return 1;
|
||||
}
|
||||
return Math.floor(props.columns);
|
||||
});
|
||||
|
||||
const gridStyle = computed<CSSProperties>(() => {
|
||||
return {
|
||||
"--cw-description-columns": String(normalizedColumns.value),
|
||||
"--cw-description-grid-template": Array
|
||||
.from({ length: normalizedColumns.value }, () => "max-content minmax(0, 1fr)")
|
||||
.join(" "),
|
||||
"--cw-description-label-align": props.labelAlign,
|
||||
"--cw-description-value-align": props.valueAlign
|
||||
} as CSSProperties;
|
||||
});
|
||||
|
||||
function formatValue(value: DescriptionGridItem["value"]): string {
|
||||
if (value === null || value === undefined || value === "") {
|
||||
return props.emptyText;
|
||||
}
|
||||
return String(value);
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.cw-description-grid {
|
||||
display: grid;
|
||||
max-width: 100%;
|
||||
grid-template-columns: var(--cw-description-grid-template);
|
||||
|
||||
.cell {
|
||||
min-width: 0;
|
||||
padding: 12px 16px;
|
||||
}
|
||||
|
||||
.label {
|
||||
color: var(--t-color-text-placeholder, var(--td-text-color-placeholder));
|
||||
text-align: var(--cw-description-label-align);
|
||||
white-space: nowrap;
|
||||
background: var(--t-color-bg-container-secondary, var(--td-bg-color-secondarycontainer));
|
||||
}
|
||||
|
||||
.value {
|
||||
text-align: var(--cw-description-value-align);
|
||||
word-break: break-all;
|
||||
background: var(--t-color-bg-container, var(--td-bg-color-container));
|
||||
}
|
||||
|
||||
&.bordered {
|
||||
border-top: 1px solid var(--t-color-border-1, var(--td-component-border));
|
||||
border-left: 1px solid var(--t-color-border-1, var(--td-component-border));
|
||||
|
||||
.cell {
|
||||
border-right: 1px solid var(--t-color-border-1, var(--td-component-border));
|
||||
border-bottom: 1px solid var(--t-color-border-1, var(--td-component-border));
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 48rem) {
|
||||
&.mobile-single {
|
||||
grid-template-columns: max-content minmax(0, max-content);
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
export type DescriptionGridAlign = "left" | "center" | "right";
|
||||
|
||||
export interface DescriptionGridItem {
|
||||
/** 唯一标识,同时用于生成具名插槽名称 */
|
||||
key: string;
|
||||
/** 标签文本 */
|
||||
label: string;
|
||||
/** 默认展示值 */
|
||||
value?: string | number | boolean | null;
|
||||
/** 标签单元格自定义类名 */
|
||||
labelClass?: string;
|
||||
/** 内容单元格自定义类名 */
|
||||
valueClass?: string;
|
||||
}
|
||||
|
||||
export interface DescriptionGridProps {
|
||||
/** 描述项列表 */
|
||||
items: DescriptionGridItem[];
|
||||
/** 一行显示几组 key/value */
|
||||
columns?: number;
|
||||
/** 空值占位文本 */
|
||||
emptyText?: string;
|
||||
/** 是否显示边框 */
|
||||
bordered?: boolean;
|
||||
/** 是否在窄屏下自动降为单列 */
|
||||
singleColumnOnMobile?: boolean;
|
||||
/** 标签内容对齐方式 */
|
||||
labelAlign?: DescriptionGridAlign;
|
||||
/** 值内容对齐方式 */
|
||||
valueAlign?: DescriptionGridAlign;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user