This commit is contained in:
2026-01-05 12:47:14 +08:00
commit 1fc846fae3
1614 changed files with 162035 additions and 0 deletions

View File

@@ -0,0 +1,63 @@
import type { ExtractPropTypes } from 'vue'
import { CLICK_EVENT } from '../_constants'
import { commonProps, makeNumericProp, makeStringProp } from '../_utils'
export const cellProps = {
...commonProps,
/**
* @description 标题名称
*/
title: String,
/**
* @description 左侧副标题
*/
subTitle: String,
/**
* @description 右侧描述
*/
desc: String,
/**
* @description 右侧描述文本对齐方式 [text-align](https://www.w3school.com.cn/cssref/pr_text_text-align.asp)
*/
descTextAlign: makeStringProp<'right' | 'left' | 'center' | 'justify' | 'inherit'>('right'),
/**
* @description 是否展示右侧箭头并开启点击反馈
*/
isLink: Boolean,
/**
* @description 点击后跳转的目标路由对象,
*/
to: String,
/**
* @description 圆角半径
*/
roundRadius: makeNumericProp(undefined),
/**
* @description 是否使内容垂直居中
*/
center: Boolean,
/**
* @description 单元格大小,可选值为 `large`
*/
size: makeStringProp(''),
/**
* @description 是否启用点击效果
*/
clickable: Boolean,
/**
* @description 左侧图标
*/
icon: String,
/**
* @description 标题宽度
*/
titleWidth: makeNumericProp(undefined),
}
export type CellProps = ExtractPropTypes<typeof cellProps>
export const cellEmits = {
[CLICK_EVENT]: (event: Event) => event instanceof Object,
}
export type CellEmits = typeof cellEmits

View File

@@ -0,0 +1,129 @@
<script lang="ts" setup>
import type { CSSProperties } from 'vue'
import { computed, defineComponent, useSlots } from 'vue'
import { CLICK_EVENT, PREFIX } from '../_constants'
import { getMainClass, getMainStyle, pxCheck } from '../_utils'
import NutIcon from '../icon/icon.vue'
import { cellEmits, cellProps } from './cell'
const props = defineProps(cellProps)
const emit = defineEmits(cellEmits)
const slots = useSlots()
const classes = computed(() => {
return getMainClass(props, componentName, {
[`${componentName}--center`]: props.center,
[`${componentName}--large`]: props.size === 'large',
[`${componentName}--clickable`]: props.isLink || props.to || props.clickable,
})
})
const styles = computed(() => {
const value: CSSProperties = {}
if (props.roundRadius != null)
value.borderRadius = pxCheck(props.roundRadius)
return getMainStyle(props, value)
})
const titleStyles = computed(() => {
const value: CSSProperties = {}
if (props.titleWidth != null) {
value.flex = '0 0 auto'
value.width = pxCheck(props.titleWidth)
value.minWidth = 0
}
return value
})
const descClasses = computed<Record<string, boolean>>(() => {
return {
[`${componentName}__value--alone`]: !(props.title || props.subTitle || slots.title),
}
})
const descStyles = computed<CSSProperties>(() => {
return {
textAlign: props.descTextAlign,
}
})
function handleClick(event: any) {
emit(CLICK_EVENT, event)
if (props.to) {
uni.navigateTo({
url: props.to,
})
}
}
</script>
<script lang="ts">
const componentName = `${PREFIX}-cell`
export default defineComponent({
name: componentName,
options: {
virtualHost: true,
addGlobalClass: true,
// #ifndef H5
styleIsolation: 'shared',
// #endif
},
})
</script>
<template>
<view :class="classes" :style="styles" @click="handleClick">
<slot v-if="slots.default" />
<template v-else>
<view v-if="props.icon || slots.icon" class="nut-cell__icon">
<slot v-if="slots.icon" name="icon" />
<NutIcon v-else custom-class="nut-cell__icon__inner" :name="props.icon" />
</view>
<view v-if="props.title || props.subTitle || slots.title" class="nut-cell__title" :style="titleStyles">
<slot v-if="slots.title" name="title" />
<view v-else class="title">
{{ props.title }}
</view>
<view v-if="props.subTitle" class="nut-cell__title-desc">
{{ props.subTitle }}
</view>
</view>
<view
v-if="props.desc || slots.desc"
class="nut-cell__value"
:class="descClasses"
:style="descStyles"
>
<slot v-if="slots.desc" name="desc" />
<template v-else>
{{ props.desc }}
</template>
</view>
<slot v-if="slots.link" name="link" />
<template v-else>
<NutIcon v-if="props.isLink || props.to" custom-class="nut-cell__link" name="right" />
</template>
</template>
</view>
</template>
<style lang="scss">
@import "./index";
</style>

View File

@@ -0,0 +1,110 @@
.nut-theme-dark {
.nut-cell {
color: $dark-color;
background: $dark-background2;
box-shadow: none;
}
}
.nut-cell {
position: relative;
box-sizing: border-box;
display: flex;
width: 100%;
padding: $cell-padding;
margin: 10px 0;
font-size: $cell-title-font;
line-height: $cell-line-height;
color: $cell-color;
background: $cell-background;
border-radius: $cell-border-radius;
box-shadow: $cell-box-shadow;
&--center {
align-items: center;
}
&--large {
padding: $cell-large-padding;
font-size: $cell-large-title-font;
.nut-cell__title-desc {
font-size: $cell-large-title-desc-font;
}
}
&:last-child {
&::after {
border: 0 !important;
}
}
&::after {
position: absolute;
right: $cell-after-right;
bottom: 0;
left: 16px;
box-sizing: border-box;
pointer-events: none;
content: "";
transform: scaleY(0.5);
}
&:active::before {
opacity: 0.1;
}
&--clickable {
cursor: pointer;
&::before {
position: absolute;
top: 50%;
left: 50%;
width: 100%;
height: 100%;
content: "";
background-color: $black;
border: inherit;
border-color: $black;
border-radius: inherit;
opacity: 0;
transform: translate(-50%, -50%);
}
}
&__icon {
display: flex;
flex-direction: row;
align-items: center;
margin: $cell-default-icon-margin;
}
&__title {
display: flex;
flex: 1;
flex-direction: column;
min-width: 80px;
&-desc {
font-size: $cell-title-desc-font;
}
}
&__value {
display: inline-block;
flex: 1;
font-size: $cell-desc-font;
color: $cell-desc-color;
text-align: right;
&--alone {
color: $cell-color;
}
}
&__link {
align-self: center;
color: #979797;
}
}

View File

@@ -0,0 +1 @@
export * from './cell'