快乐的梦鱼 1 mesiac pred
rodič
commit
2e9ec9b47a
37 zmenil súbory, kde vykonal 806 pridanie a 259 odobranie
  1. 1 1
      src/components/README.md
  2. 4 4
      src/components/basic/Button.vue
  3. 1 0
      src/components/basic/ButtonGroup.vue
  4. 1 0
      src/components/basic/Cell.vue
  5. 13 7
      src/components/basic/Icon.vue
  6. 1 0
      src/components/basic/Image.vue
  7. 9 6
      src/components/demo/DemoPage.vue
  8. 1 1
      src/components/demo/DemoTitle.vue
  9. 1 1
      src/components/dialog/CommonRoot.ts
  10. 4 10
      src/components/dialog/Popup.vue
  11. 174 0
      src/components/display/Card.vue
  12. 165 0
      src/components/display/Preview.vue
  13. 72 0
      src/components/display/PreviewItem.vue
  14. 40 55
      src/components/display/block/BackgroundBox.vue
  15. 61 13
      src/components/display/block/IconTextBlock.vue
  16. 50 28
      src/components/display/block/ImageBlock.vue
  17. 37 29
      src/components/display/block/ImageBlock2.vue
  18. 37 42
      src/components/display/block/ImageBlock3.vue
  19. 2 1
      src/components/display/block/TextBlock.vue
  20. 1 0
      src/components/display/block/TextLeftRightBlock.vue
  21. 39 35
      src/components/display/title/SubTitle.vue
  22. 9 9
      src/components/feedback/Alert.vue
  23. 1 1
      src/components/feedback/DropdownMenu.vue
  24. 1 2
      src/components/feedback/DropdownMenuItem.vue
  25. 6 2
      src/components/feedback/Toast.vue
  26. 9 2
      src/components/feedback/Touchable.vue
  27. 1 0
      src/components/form/Field.vue
  28. 1 0
      src/components/form/NumberInputBox.vue
  29. 19 2
      src/components/form/Stepper.vue
  30. BIN
      src/components/images/icons/video-mark.png
  31. 5 0
      src/components/layout/BaseView.ts
  32. 21 1
      src/components/layout/FlexView.vue
  33. 1 0
      src/components/layout/grid/GridItem.vue
  34. 0 2
      src/components/nav/IndexBar.vue
  35. 12 3
      src/components/theme/Theme.ts
  36. 5 1
      src/components/theme/ThemeDefine.ts
  37. 1 1
      src/components/typography/HorizontalScrollText.vue

+ 1 - 1
src/components/README.md

@@ -6,7 +6,7 @@ NaEasy UI 是一款简单的 UniApp 移动端UI组件库。
 
 ## 版本
 
-当前版本:INDEV 0.0.1
+当前版本:INDEV 0.0.3-25121601
 
 ## 版权说明
 

+ 4 - 4
src/components/basic/Button.vue

@@ -337,7 +337,7 @@ const currentStyle = computed(() => {
         warning: themeStyles.buttonWarning.value,
         danger: themeStyles.buttonDanger.value,
         custom: {
-          backgroundColor: themeContext.resolveThemeColor(props.touchable ? props.color : props.disabledColor),
+          backgroundColor: themeContext.resolveThemeColor(touchable.value ? props.color : props.disabledColor),
           color: themeContext.resolveThemeColor(props.textColor),
         },
         text: {
@@ -367,7 +367,7 @@ const currentStyle = computed(() => {
         warning: themeStyles.lightButtonWarning.value,
         danger: themeStyles.lightButtonDanger.value,
         custom: {
-          backgroundColor: themeContext.resolveThemeColor(props.touchable ? props.color : props.disabledColor),
+          backgroundColor: themeContext.resolveThemeColor(touchable.value ? props.color : props.disabledColor),
           color: themeContext.resolveThemeColor(props.textColor),
         },
         text: {
@@ -378,7 +378,7 @@ const currentStyle = computed(() => {
   );
 
   const speicalStyle : ViewStyle = {
-    opacity: props.touchable ? 1 : themeVars.ButtonDisableOpacity,
+    opacity: touchable.value ? 1 : themeVars.ButtonDisableOpacity,
     borderRadius: props.shape === 'round' ? themeContext.resolveThemeSize(props.radius) : 0,
   };
 
@@ -394,7 +394,7 @@ const currentStyle = computed(() => {
   }
 
   //自定义状态下的禁用颜色
-  if (props.disabledColor && !props.touchable && props.type === 'custom')
+  if (props.disabledColor && !touchable.value && props.type === 'custom')
     speicalStyle.backgroundColor = themeContext.resolveThemeColor(props.disabledColor);
 
   const sizeStyle = selectStyleType<ViewStyle, ButtomSizeType>(props.size, 'medium', {

+ 1 - 0
src/components/basic/ButtonGroup.vue

@@ -30,6 +30,7 @@ defineOptions({
 })
 
 const props = withDefaults(defineProps<ButtonGroupProp>(), {
+  direction: 'row',
   disabled: false,
   gap: 0,
 });

+ 1 - 0
src/components/basic/Cell.vue

@@ -7,6 +7,7 @@
       ...viewStyle,
       ...style,
     }"
+    :setCursor="false"
     :flex="1" 
     :align="center ? 'center' : 'flex-start'"
     justify="space-between"

+ 13 - 7
src/components/basic/Icon.vue

@@ -43,6 +43,7 @@
     :innerStyle="style"
     :innerClass="innerClass"
     :src="iconData.value"
+    mode="aspectFill"
   />
 </template>
 
@@ -58,6 +59,10 @@ export interface IconProps {
    */
   icon?: string;
   /**
+   * 同 icon 属性
+   */
+  name?: string;
+  /**
    * 图标大小
    */
   size?: number|string;
@@ -83,18 +88,19 @@ const theme = useTheme();
 const props = withDefaults(defineProps<IconProps>(), {
   size: 45,
 });
+const icon = computed(() => props.icon || props.name);
 const iconData = computed(() => {
-  const data = props.icon ? IconUtils.getIconDataFromMap(props.icon) : undefined;
-  if (!data && props.icon && props.icon.startsWith('icon-')) {
+  const data = icon.value ? IconUtils.getIconDataFromMap(icon.value) : undefined;
+  if (!data && icon.value && icon.value.startsWith('icon-')) {
     return {
       type: 'iconfont',
-      value: props.icon,
+      value: icon.value,
       fontFamily: 'iconfont',
     } as IconItem
-  } else if (!data && props.icon) {
+  } else if (!data && icon.value) {
     return {
       type: 'image',
-      value: props.icon,
+      value: icon.value,
     } as IconItem
   } else if (!data) {
     return {
@@ -115,6 +121,7 @@ const style = computed(() => {
     color: theme.resolveThemeColor(props.color, 'text.content'),
     fill: theme.resolveThemeColor(props.color, 'text.content'),
     transform: props.rotate ? `rotate(${props.rotate}deg)` : undefined,
+    overflow: 'visible',
     ...props.innerStyle,
   };
 });
@@ -123,6 +130,5 @@ defineOptions({
   options: {
     virtualHost: true,
   }
-})
-
+});
 </script>

+ 1 - 0
src/components/basic/Image.vue

@@ -32,6 +32,7 @@
         :size="themeContext.resolveThemeSize(loadingSize)"
       />
     </view>
+    <slot />
   </view>
 </template>
 

+ 9 - 6
src/components/demo/DemoPage.vue

@@ -5,19 +5,22 @@ import FlexCol from '../layout/FlexCol.vue';
 import StatusBarSpace from '../layout/space/StatusBarSpace.vue';
 import NavBar from '../nav/NavBar.vue';
 
-const props = defineProps<{	
+const props = withDefaults(defineProps<{	
   title?: string,
   desc?: string,
   isHome?: boolean,
-}>();
+  customNavBar?: boolean,
+}>(), {
+  customNavBar: true,
+});
 
 </script>
 
 <template>
   <CommonRoot>
     <FlexCol innerClass="nana-demo-page" backgroundColor="background.page">
-      <StatusBarSpace />
-      <NavBar :title="title" leftButton="back" :showLeftButton="!isHome" />
+      <StatusBarSpace v-if="customNavBar" />
+      <NavBar v-if="customNavBar" :title="title" leftButton="back" :showLeftButton="!isHome" />
       <view v-if="title || desc" class="header">
         <Text color="primary" fontConfig="h3" :text="title" />
         <Text v-if="desc" color="text.second" :text="desc" />
@@ -30,10 +33,10 @@ const props = defineProps<{
 <style lang="scss">
 .nana-demo-page {
   /* #ifdef H5 */
-  min-height: calc(100vh - 44px - env(safe-area-inset-top));
+  min-height: calc(100vh - env(safe-area-inset-top));
   /* #endif */
   /* #ifndef H5 */
-  min-height: calc(100vh - 44px);
+  min-height: calc(100vh);
   /* #endif */
 
   & > .header {

+ 1 - 1
src/components/demo/DemoTitle.vue

@@ -3,7 +3,7 @@
     <view v-if="!small" class="line">
       <view class="line2"></view>
     </view>
-    <Text fontConfig="h4" color="text.content" :text="title" />
+    <Text :fontConfig="small ? 'subText' : 'h5'"  :text="title" />
   </view>
 </template>
 

+ 1 - 1
src/components/dialog/CommonRoot.ts

@@ -26,7 +26,7 @@ export function alert(options: DialogAlertOptions) {
 export function confirm(options: DialogAlertOptions) {
   return NaDialogRoot().confirm(options);
 }
-export function toast(options: ToastShowProps) {
+export function toast(options: ToastShowProps|string) {
   return NaDialogRoot().toast(options);
 }
 export function closeToast() {

+ 4 - 10
src/components/dialog/Popup.vue

@@ -219,13 +219,7 @@ const props = withDefaults(defineProps<PopupProps>(), {
   maskColor: 'background.mask',
   mask: true,
   margin: () => [0,0,0,0],
-  inset: () => {
-    const arr : (number|undefined|string)[] = [undefined,undefined,undefined,undefined]
-    // #ifdef H5
-    arr[0] = '44px';
-    // #endif
-    return arr;
-  },
+  inset: () => [undefined,undefined,undefined,undefined],
   backgroundColor: 'white',
   safeArea: true,
   duration: 230,
@@ -284,7 +278,7 @@ watch(() => props.show, (v) => {
   left: 0;
   right: 0; 
   bottom: 0;
-  z-index: 110;
+  z-index: 1010;
   display: flex;
   flex-direction: column;
   pointer-events: none;
@@ -311,14 +305,14 @@ watch(() => props.show, (v) => {
     left: 0;
     right: 0;
     bottom: 0;
-    z-index: 111;
+    z-index: 1011;
     pointer-events: none;
     opacity: 0;
     transition: opacity ease-in-out 0.3s;
   }
   .nana-popup-content {
     position: relative;
-    z-index: 112;
+    z-index: 1012;
     overflow: hidden;
     transition: all ease-in-out 0.3s;
     opacity: 0.3;

+ 174 - 0
src/components/display/Card.vue

@@ -0,0 +1,174 @@
+<script setup lang="ts">
+import { computed } from 'vue';
+import Icon, { type IconProps } from '../basic/Icon.vue';
+import Image, { type ImageProps } from '../basic/Image.vue';
+import Text from '../basic/Text.vue';
+import FlexCol from '../layout/FlexCol.vue';
+import FlexRow from '../layout/FlexRow.vue';
+import BackgroundBox from './block/BackgroundBox.vue';
+import Touchable from '../feedback/Touchable.vue';
+import { propGetThemeVar, useTheme } from '../theme/ThemeDefine';
+import type { FlexProps } from '../layout/FlexView.vue';
+import IconTextBlock from './block/IconTextBlock.vue';
+
+const themeContext = useTheme();
+const props = withDefaults(defineProps<{
+  /**
+   * 卡片标题
+   */
+  title?: string;
+  /**
+   * 卡片描述
+   */
+  desc?: string;
+  /**
+   * 卡片标题额外内容
+   */
+  extra?: string;
+  /**
+   * 卡片图标
+   */
+  icon?: string;
+  /**
+   * 卡片图标属性
+   */
+  iconProps?: IconProps;
+  /**
+   * 卡片圆角
+   * @default 20
+   */
+  radius?: number;
+  /**
+   * 卡片背景颜色
+   * @default 'white'
+   */
+  backgroundColor?: string;
+  /**
+   * 卡片视图属性
+   */
+  viewProps?: FlexProps;
+
+  /**
+   * 卡片内容
+   */
+  content?: string;
+
+  /**
+   * 卡片图片
+   */
+  image?: string;
+  /**
+   * 卡片图片属性
+   */
+  imageProps?: ImageProps;
+  /**
+   * 卡片图片高度
+   * @default 320
+   */
+  imageHeight?: number;
+  /**
+   * 卡片图片标题
+   */
+  imageTitle?: number;
+  /**
+   * 卡片图片描述
+   */
+  imageDesc?: string;
+  /**
+   * 卡片图片额外内容
+   */
+  imageExtra?: string;
+  /**
+   * 卡片图片信息位置
+   * * over 图片底部渐变显示
+   * * bottom 图片下方单独显示
+   * @default 'over'
+   */
+  imageInfoPosition?: 'over' | 'bottom';
+}>(), {
+  radius: () => propGetThemeVar('CardRadius', 15),
+  imageHeight: () => propGetThemeVar('CardImageDefaultHeight', 320),
+  imageInfoPosition: () => propGetThemeVar('CardImageInfoPosition', 'over'),
+  backgroundColor: () => propGetThemeVar('CardBackgroundColor', 'white'),
+});
+const emit = defineEmits([ 'click' ]);
+const padding = computed(() => themeContext.getVar('CardTitlePadding', 20));
+
+const hasImageInfo = computed(() => props.imageDesc || props.imageExtra || props.imageTitle);
+const hasTitle = computed(() => props.title || props.desc || props.extra);
+
+</script>
+
+<template>
+  <Touchable 
+    position="relative"
+    direction="column"
+    :backgroundColor="backgroundColor"
+    :radius="radius"
+    shadow="default"
+    overflow="hidden"
+    v-bind="viewProps"
+    @click="emit('click')"
+  >
+    <slot name="prefix" />
+
+    <!-- 标题区域 -->
+    <IconTextBlock
+      v-if="hasTitle" :padding="padding" :gap="20"
+      :icon="icon"
+      :iconProps="iconProps"
+      :title="title"
+      :desc="desc"
+      :extra="extra"
+    />
+    <!-- 图片区域 -->
+    <Image 
+      v-if="image" 
+      :src="image"
+      mode="aspectFill"
+      width="100%"
+      :height="imageHeight"
+      v-bind="imageProps"
+    >
+      <!-- 图片标题区域 -->
+      <BackgroundBox 
+        v-if="hasImageInfo && imageInfoPosition === 'over'"
+        direction="row"
+        align="center" 
+        justify="space-between"
+        position="absolute"
+        color2="background.mask"
+        color1="transparent"
+        :zIndex="2"
+        :bottom="0"
+        :left="0"
+        :right="0"
+        :padding="padding"
+      >
+        <FlexCol>
+          <Text fontConfig="subTitle" color="text.light" :text="imageTitle" />
+          <Text fontConfig="subText" color="text.light" :text="imageDesc" />
+        </FlexCol>
+        <Text fontConfig="subText" color="text.light" :text="imageExtra" />
+      </BackgroundBox>
+    </Image>
+    <!-- 底部区域 -->
+    <FlexCol>
+      <IconTextBlock 
+        v-if="hasImageInfo && imageInfoPosition === 'bottom'"
+        :padding="padding"
+        :title="imageTitle"
+        :desc="imageDesc"
+        :extra="imageExtra"
+      />
+      <!-- 内容区域 -->
+      <FlexCol v-if="content || $slots.default" :padding="padding">
+        <slot>
+          <Text fontConfig="content" :text="content" />
+        </slot>
+      </FlexCol>
+    </FlexCol>
+
+    <slot name="suffix" />
+  </Touchable>
+</template>

+ 165 - 0
src/components/display/Preview.vue

@@ -0,0 +1,165 @@
+<template>
+  <FlexCol :backgroundColor="backgroundColor">
+    <!-- 标题区域 -->
+    <slot name="title">
+      <IconTextBlock
+        :padding="padding"
+        :title="title"
+        :titleProps="titleProps"
+        :desc="desc"
+        :extra="extra"
+        :extraProps="extraProps"
+      />
+    </slot>
+    <Divider color="border.light" :size="2" />
+    <!-- 项目区域 -->
+    <slot name="items">
+      <FlexCol :padding="padding">
+        <PreviewItem
+          v-for="(item,k) in items"
+          :key="k"
+          :title="item.title"
+          :value="item.value"
+          :titleProps="titleProps"
+          :titleWidth="titleWidth"
+          :titleColor="titleColor"
+          :valueProps="valueProps"
+          :valueColor="valueColor"
+          :valueType="item.valueType"
+          :gap="itemGap"
+          :margin="itemVerticalPadding"
+        />
+      </FlexCol>
+    </slot>
+    <Divider color="border.light" :size="2" />
+    <!-- 操作区域 -->
+    <slot name="actions">
+      <FlexRow align="stretch">
+        <Button
+          v-for="(item,k) in actions"
+          :key="k"
+          :text="item.text"
+          :textColor="item.color"
+          :innerStyle="{ flex: 1, minHeight: '60rpx' }"
+          :radius="0"
+          @click="item.onClick?.(item)"
+          type="text"
+          v-bind="item.props"
+        />
+      </FlexRow>
+    </slot>
+  </FlexCol>
+</template>
+
+<script setup lang="ts">
+import { computed } from 'vue';
+import { propGetThemeVar, useTheme } from '../theme/ThemeDefine';
+import FlexCol from '../layout/FlexCol.vue';
+import IconTextBlock from './block/IconTextBlock.vue';
+import PreviewItem, { type PreviewItemType } from './PreviewItem.vue';
+import type { TextProps } from '../basic/Text.vue';
+import Divider from './Divider.vue';
+import FlexRow from '../layout/FlexRow.vue';
+import type { ButtonProp } from '../basic/Button.vue';
+import Button from '../basic/Button.vue';
+
+const props = withDefaults(defineProps<{
+  /**
+   * 大标题
+   */
+  title?: string,
+  /**
+   * 副标题
+   */
+  desc?: string,
+  /**
+   * 大标题右侧额外信息
+   */
+  extra?: string,
+  /**
+   * 大标题右侧额外信息文字属性
+   */
+  extraProps?: TextProps,
+  /**
+   * 卡片背景颜色
+   */
+  backgroundColor?: string,
+  /**
+   * 项目列表
+   */
+  items?: {
+    /**
+     * 项目标题
+     */
+    title: string,
+    /**
+     * 项目值
+     */
+    value: string | string[],
+    /**
+     * 项目值类型
+     * * text:普通文本
+     * * image:图片
+     */
+    valueType?: PreviewItemType,
+  }[],
+  /**
+   * 操作按钮列表
+   */
+  actions?: {
+    /**
+     * 操作按钮文字
+     */
+    text: string,
+    /**
+     * 操作按钮文字颜色
+     */
+    color?: string,
+    /**
+     * 操作按钮文字属性
+     */
+    props?: ButtonProp,
+    /**
+     * 操作按钮点击事件
+     */
+    onClick?: (item: { text: string, color?: string, props?: ButtonProp }) => void,
+  }[],
+  /**
+   * 项目标题文字属性
+   */
+  titleProps?: TextProps,
+  /**
+   * 项目标题文字颜色
+   * @default text.second
+   */
+  titleColor?: string,
+  /**
+   * 项目标题宽度
+   * @default 300
+   */
+  titleWidth?: string|number,
+  /**
+   * 项目值文字颜色
+   * @default text.content
+   */
+  valueColor?: string,
+  /**
+   * 项目值文字属性
+   */
+  valueProps?: TextProps,
+
+}>(), {
+  backgroundColor: () => propGetThemeVar('PreviewBackgroundColor', 'white'),
+  extraProps: () => propGetThemeVar('PreviewExtraTextProps', {}),
+  titleColor: () => propGetThemeVar('PreviewTitleColor', 'text.second'),
+  valueColor: () => propGetThemeVar('PreviewValueColor', 'text.content'),
+  titleWidth: () => propGetThemeVar('PreviewItemTitleWidth', 300),
+  titleProps: () => propGetThemeVar('PreviewItemTitleTextProps', {}),
+  valueProps: () => propGetThemeVar('PreviewItemValueTextProps', {}),
+});
+const theme = useTheme();
+const padding = computed(() => theme.getVar('PreviewPadding', 30));
+const itemVerticalPadding = computed(() => theme.getVar('PreviewItemVerticalPadding', 10));
+const itemGap = computed(() => theme.getVar('PreviewItemGap', 20));
+
+</script>

+ 72 - 0
src/components/display/PreviewItem.vue

@@ -0,0 +1,72 @@
+<template>
+  <FlexRow justify="space-between" align="flex-start" :gap="gap" :padding="[margin??0,0]">
+    <FlexRow :width="titleWidth">
+      <Text v-bind="titleProps" :color="titleColor" :text="title" />
+    </FlexRow>
+    <template v-if="valueType === 'text'">
+      <FlexCol v-if="Array.isArray(value)">
+        <Text 
+          v-for="(item,k) in value"
+          :key="k" 
+          v-bind="valueProps"
+          :color="valueColor"
+          :text="item"
+        />
+      </FlexCol>
+      <Text v-else v-bind="valueProps" :color="valueColor" :text="value || emptyText" />
+    </template>
+    
+    <template v-else-if="valueType === 'image'">
+      <FlexRow v-if="Array.isArray(value)" wrap>
+        <Image 
+          v-for="(item,k) in value" 
+          :key="k" 
+          :width="100" 
+          :height="100"
+          :radius="12"
+          round
+          v-bind="(valueProps as ImageProps)" 
+          :src="item"
+          clickPreview
+        />
+      </FlexRow>
+      <Image 
+        v-else
+        :width="100"
+        :height="100"
+        :radius="12"
+        round
+        v-bind="(valueProps as ImageProps)"
+        :src="value"
+        clickPreview
+      />
+    </template>
+  </FlexRow>
+</template>
+
+<script setup lang="ts">
+import FlexRow from '../layout/FlexRow.vue';
+import Text,{ type TextProps } from '../basic/Text.vue';
+import FlexCol from '../layout/FlexCol.vue';
+import Image, { type ImageProps } from '../basic/Image.vue';
+
+export type PreviewItemType = 'text' | 'image';
+
+const props = withDefaults(defineProps<{
+  title?: string,
+  titleColor?: string,
+  titleWidth?: string|number,
+  titleProps?: TextProps,
+  value?: string | string[],
+  valueColor?: string,
+  valueType?: PreviewItemType,
+  valueProps?: TextProps|ImageProps,
+  emptyText?: string,
+  gap?: number,
+  margin?: number,
+}>(), {
+  emptyText: '空',
+  valueType: 'text',
+});
+
+</script>

+ 40 - 55
src/components/display/block/BackgroundBox.vue

@@ -1,9 +1,9 @@
 <template>
   <!-- 组件:背景图显示盒子 -->
   <FlexView
+    v-bind="$props"
     center
     :flexShrink="0"
-    v-bind="$props"
     :innerStyle="style" 
   >
     <slot />
@@ -38,64 +38,39 @@ export default {}
 </script>
 
 <script setup lang="ts">
-import FlexView from '@/components/layout/FlexView.vue';
+import FlexView, { type FlexProps } from '@/components/layout/FlexView.vue';
 import { useTheme, type ViewStyle } from '@/components/theme/ThemeDefine';
 import { solveUrl } from '@/components/theme/ThemeTools';
 import { computed, type PropType } from 'vue';
 
-defineOptions({
-  options: {
-    virtualHost: true,
-    styleIsolation: "shared",
-  },
-});
-
-/**
- * 内容积木组件:背景盒子,
- */
-const props = defineProps({
+export interface BackgroundBoxProps extends FlexProps {
   /**
    * 背景颜色(1)。
    * 
-   * 格式:字符串格式或主题中定义的 background 颜色预设。
+   * 格式:字符串格式或主题中定义的颜色预设。
    */
-  color1: {
-    type: String,
-    default: undefined
-  },
+  color1?: string;
   /**
    * 背景颜色(2)。
    * 
-   * 格式:字符串格式或主题中定义的 background 颜色预设。
+   * 格式:字符串格式或主题中定义的颜色预设。
    */
-  color2: {
-    type: String,
-    default: undefined
-  },
+  color2?: string;
   /**
    * 圆角。
    */
-  radius: {
-    type: [String, Number],
-    default: undefined
-  },
+  radius?: string | number;
   /**
    * 背景渐变角度。
    * 只有 color1 和 color2 都定义时有效。
    *
    * 格式:角度(0-360)。
    */
-  gradientAngle: {
-    type: Number,
-    default: undefined
-  },
+  gradientAngle?: number;
   /**
    * 背景图片。
    */
-  backgroundImage: {
-    type: String,
-    default: undefined
-  },
+  backgroundImage?: string;
   /**
    * 背景填充方式。
    *
@@ -104,50 +79,60 @@ const props = defineProps({
    * - fillH:纵向填充,宽度变化。
    * - none:不填充。
    */
-  backgroundFillType: {
-    type: String as PropType<'none'|'fillH'|'fillW'>,
-    default: "fillW"
-  },
+  backgroundFillType?: 'none'|'fillH'|'fillW';
   /**
    * 背景填充大小。
    */
-  backgroundSize: {
-    type: String,
-    default: "100%"
-  },
+  backgroundSize?: string;
   /**
    * 背景填充位置。
    */
-  backgroundPosition: {
-    type: String,
-    default: undefined
-  },
+  backgroundPosition?: string;
   /**
    * 背景图片九宫格裁剪大小。
    *
    * 格式:
    * - 数组:[ top, right, bottom, left ]
    */
-  backgroundCutBorder: {
-    type: Object as PropType<Array<number|string>>,
-    default: undefined
-  },
+  backgroundCutBorder?: Array<number|string>;
   /**
    * 背景图片九宫格渲染大小。
    *
    * 格式:
    * - 数组:[ top, right, bottom, left ]
    */
-  backgroundCutBorderSize: {
-    type: Object as PropType<Array<number|string>>,
-    default: () => ([ 'auto' ])
+  backgroundCutBorderSize?: Array<number|string>;
+}
+
+defineOptions({
+  options: {
+    virtualHost: true,
+    styleIsolation: "shared",
   },
 });
 
+/**
+ * 内容积木组件:背景盒子,
+ */
+const props = withDefaults(defineProps<BackgroundBoxProps>(), {
+  color1: undefined,
+  color2: undefined,
+  radius: undefined,
+  gradientAngle: undefined,
+  backgroundImage: undefined,
+  backgroundFillType: "fillW",
+  backgroundSize: "100%",
+  backgroundPosition: undefined,
+  backgroundCutBorder: undefined,
+  backgroundCutBorderSize: () => ([ 'auto' ]),
+});
+
 const theme = useTheme();
 
 const style = computed(() => {
-  const o : ViewStyle = {}
+  const o : ViewStyle = {
+    ...props.innerStyle,
+  }
   if (props.radius) {
     o.borderRadius = theme.resolveThemeSize(props.radius);
   }

+ 61 - 13
src/components/display/block/IconTextBlock.vue

@@ -2,9 +2,11 @@
 import Icon from '@/components/basic/Icon.vue';
 import Text from '@/components/basic/Text.vue';
 import FlexRow from '@/components/layout/FlexRow.vue';
+import FlexCol from '@/components/layout/FlexCol.vue';
 import type { IconProps } from '@/components/basic/Icon.vue';
 import type { TextProps } from '@/components/basic/Text.vue';
 import type { PropType } from 'vue';
+import type { FlexProps } from '@/components/layout/FlexView.vue';
 
 defineOptions({
   options: {
@@ -13,38 +15,84 @@ defineOptions({
   },
 });
 defineProps({
+  /**
+   * 图标名称
+   */
   icon: {
     type: String,
     default: '',
   },
+  /**
+   * 图标属性
+   */
   iconProps: {
     type: Object as PropType<IconProps>,
     default: () => ({
       color: 'text.content',
-      size: 30,
+      size: 60,
     }),
   },
-  text: {
+  /**
+   * 标题
+   */
+  title: {
     type: [String,Number],
     default: '',
   },
-  textLines: {
-    type: Number,
-    default: 1,
+  /**
+   * 描述
+   */
+  desc: {
+    type: [String,Number],
+    default: '',
+  },
+  /**
+   * 额外信息
+   */
+  extra: {
+    type: [String,Number],
+    default: '',
   },
-  textProps: {
+  /**
+   * 标题文字属性
+   */
+  titleProps: {
     type: Object as PropType<TextProps>,
-    default: () => ({
-      color: 'text.content',
-      fontSize: '30rpx',
-    }),
+  },
+  /**
+   * 描述文字属性
+   */
+  descProps: {
+    type: Object as PropType<TextProps>,
+  },
+  /**
+   * 额外信息文字属性
+   */ 
+  extraProps: {
+    type: Object as PropType<TextProps>,
+  },  
+  /**
+   * 卡片属性
+   */
+  viewProps: {
+    type: Object as PropType<FlexProps>,
   },
 })
 </script>
 
 <template>
-  <FlexRow gap="10" align="center">
-    <Icon v-bind="iconProps" :icon="icon"  />
-    <Text :lines="textLines" v-bind="textProps" :text="text" />
+  <FlexRow :gap="20" align="center" justify="space-between" v-bind="viewProps">
+    <FlexRow :gap="20" align="center" justify="space-between">
+      <Icon v-if="icon" :name="icon" v-bind="iconProps" />
+      <FlexCol>
+        <Text fontConfig="subTitle" :text="title" v-bind="titleProps" />
+        <Text fontConfig="subText" :text="desc" v-bind="descProps" />
+      </FlexCol>
+    </FlexRow>
+    <slot name="extra">
+      <FlexRow :flexShrink="0">
+        <Text fontConfig="subText" :text="extra" v-bind="extraProps" />
+      </FlexRow>
+    </slot>
   </FlexRow>
 </template>

+ 50 - 28
src/components/display/block/ImageBlock.vue

@@ -10,30 +10,32 @@
     :height="height"
     @click="$emit('click')"
   >
-    <image 
+    <Image 
       :src="src"
       mode="aspectFill"
-      style="width:100%;height:100%;"
-    />
-    <image 
-      v-if="videoMark" 
-      :src="VideoMark" 
-      :width="60"
-      :height="60"
-      class="nana-image-block-video-mark"
-    />
-    <BackgroundBox
-      color1="background.mask"
-      position="absolute"
-      :left="0"
-      :right="0"
-      :bottom="0"
-      :padding="[10,15]"
+      width="100%"
+      height="100%"
     >
-      <slot name="desc">
-        <text class="nana-image-desc">{{ desc }}</text>
-      </slot>
-    </BackgroundBox>
+      <Image 
+        v-if="videoMark" 
+        :src="videoMarkImage" 
+        :width="videoMarkSize"
+        :height="videoMarkSize"
+        innerClass="nana-image-block-video-mark"
+      />
+    </Image>
+    <slot name="desc">
+      <BackgroundBox
+        color1="background.mask"
+        position="absolute"
+        :left="0"
+        :right="0"
+        :bottom="0"
+        :padding="[10,15]"
+      >
+        <Text class="nana-image-desc" color="text.second" v-bind="descProps" :text="desc" />
+      </BackgroundBox>
+    </slot>
   </Touchable>
 </template>
 
@@ -51,8 +53,11 @@ export default {}
 <script setup lang="ts">
 import { useTheme } from '@/components/theme/ThemeDefine';
 import BackgroundBox from './BackgroundBox.vue';
-import VideoMark from '/static/images/VideoMark.png';
+import VideoMark from '../../images/icons/video-mark.png';
 import Touchable from '@/components/feedback/Touchable.vue';
+import Image from '@/components/basic/Image.vue';
+import Text, { type TextProps } from '@/components/basic/Text.vue';
+import type { PropType } from 'vue';
 
 const theme = useTheme();
 
@@ -99,12 +104,33 @@ defineProps({
     default: null
   },
   /**
+   * 图片下方显示描述的文字属性。
+   */
+  descProps: {
+    type: Object as PropType<TextProps>,
+    default: () => ({})
+  },
+  /**
    * 是否显示播放视频标记。
    */
   videoMark: {
     type: Boolean,
     default: false
   },
+  /**
+   * 播放视频标记的图片路径。
+   */
+  videoMarkImage: {
+    type: String,
+    default: VideoMark
+  },
+  /**
+   * 播放视频标记的大小。
+   */
+  videoMarkSize: {
+    type: [ String, Number ],
+    default: 80
+  }
 })
 
 defineEmits([	
@@ -114,19 +140,15 @@ defineEmits([
 
 <style lang="scss">
 .nana-image-desc {
-  color: #fff;
-  font-size: 25rpx;
   white-space: nowrap;
   overflow: hidden;
   text-overflow: ellipsis;
 }
 .nana-image-block-video-mark {
-  width: 44rpx;
-  height: 44rpx;
   position: absolute;
   left: 50%;
   top: 40%;
-  margin-left: -22rpx;
-  margin-top: -22rpx;
+  z-index: 100;
+  transform: translate(-50%, -50%);
 }
 </style>

+ 37 - 29
src/components/display/block/ImageBlock2.vue

@@ -1,11 +1,9 @@
 <template>
   <Touchable
     touchable
-    backgroundColor="white"
-    overflow="hidden"
-    v-bind="$props"
+    v-bind="props"
     :flexShrink="0"
-    :innerStyle="{ borderRadius: theme.resolveThemeSize(radius), overflow: 'hidden', }"
+    :innerStyle="{ borderRadius: theme.resolveThemeSize(imageRadius), overflow: 'hidden', }"
     :width="width"
     @click="$emit('click')"
   >
@@ -13,10 +11,17 @@
       :src="src" 
       width="100%"
       :height="imageHeight"
+      :radius="imageRadius"
       mode="aspectFill"
     />
     <slot name="desc">
-      <Text class="nana-image-desc">{{ desc }}</Text>
+      <FlexCol :padding="15">
+        <IconTextBlock
+          :title="title"
+          :desc="desc"
+          :extra="extra"
+        />
+      </FlexCol>
     </slot>
   </Touchable>
 </template>
@@ -35,47 +40,50 @@ export default {}
 <script setup lang="ts">
 import { useTheme } from '@/components/theme/ThemeDefine';
 import Image from '../../basic/Image.vue';
-import Text from '../../basic/Text.vue';
 import Touchable from '@/components/feedback/Touchable.vue';
+import type { FlexProps } from '../../layout/FlexView.vue';
+import IconTextBlock from './IconTextBlock.vue';
+import FlexCol from '@/components/layout/FlexCol.vue';
 
-const theme = useTheme();
-
-defineProps({	
+export interface ImageBlock2Props extends Partial<FlexProps> {
   /**
    * 宽度。
    */
-  width: {
-    type: [ String, Number ],
-    default: 400
-  },
+  width?: string | number;
   /**
    * 高度。
    */
-  imageHeight: {
-    type: [ String, Number ],
-    default: 250
-  },
+  imageHeight?: string | number;
   /**
    * 图片的路径。
    */
-  src: {
-    type: String,
-    default: null
-  },
+  src?: string;
   /**
    * 图片的圆角。
    */
-  radius: {
-    type: [ String, Number ],
-    default: undefined
-  },
+  imageRadius?: string | number;
+  /**
+   * 图片下方显示标题。
+   */
+  title?: string;
   /**
    * 图片下方显示描述。
    */
-  desc: {
-    type: String,
-    default: null
-  },
+  desc?: string;
+  /**
+   * 图片下方显示额外信息。
+   */
+  extra?: string;
+}
+
+const theme = useTheme();
+const props = withDefaults(defineProps<ImageBlock2Props>(), {
+  width: 400,
+  imageHeight: 250,
+  imageRadius: 0,
+  direction: 'column',
+  backgroundColor: "white",
+  overflow: "hidden",
 })
 
 defineEmits([	

+ 37 - 42
src/components/display/block/ImageBlock3.vue

@@ -1,10 +1,7 @@
 <template>
   <Touchable
     touchable
-    backgroundColor="white"
-    direction="row"
-    overflow="hidden"
-    v-bind="$props"
+    v-bind="props"
     :flexShrink="0"
     :innerStyle="{ borderRadius: theme.resolveThemeSize(radius), overflow: 'hidden', }"
     @click="$emit('click')"
@@ -13,13 +10,17 @@
       :src="src" 
       :width="imageWidth"
       :height="imageHeight"
-      :radius="radius"
+      :radius="imageRadius"
       round
       mode="aspectFill"
     />
     <FlexView direction="column">
       <slot name="desc">
-        <Text class="nana-image-desc">{{ desc }}</Text>
+        <IconTextBlock
+          :title="title"
+          :desc="desc"
+          :extra="extra"
+        />
       </slot>
     </FlexView>
   </Touchable>
@@ -38,62 +39,56 @@ export default {}
 
 <script setup lang="ts">
 import { useTheme } from '@/components/theme/ThemeDefine';
-import FlexView from '../../layout/FlexView.vue';
+import FlexView, { type FlexProps } from '../../layout/FlexView.vue';
 import Image from '../../basic/Image.vue';
-import Text from '../../basic/Text.vue';
 import Touchable from '@/components/feedback/Touchable.vue';
+import IconTextBlock from './IconTextBlock.vue';
 
-const theme = useTheme();
-
-defineProps({	
+export interface ImageBlock3Props extends Partial<FlexProps> {
   /**
    * 宽度
    */
-  imageWidth: {
-    type: [ String, Number ],
-    default: 150
-  },
+  imageWidth?: string | number;
   /**
    * 高度。
    */
-  imageHeight: {
-    type: [ String, Number ],
-    default: 150
-  },
+  imageHeight?: string | number;
   /**
    * 图片的路径。
    */
-  src: {
-    type: String,
-    default: null
-  },
+  src?: string;
   /**
    * 图片的圆角。
    */
-  radius: {
-    type: [ String, Number ],
-    default: undefined
-  },
+  imageRadius?: string | number;
+  /**
+   * 图片下方显示标题。
+   */
+  title?: string | number;
   /**
    * 图片下方显示描述。
    */
-  desc: {
-    type: String,
-    default: null
-  },
+  desc?: string | number;
+  /**
+   * 图片下方显示额外信息。
+   */
+  extra?: string | number;
+}
+
+const theme = useTheme();
+
+const props = withDefaults(defineProps<ImageBlock3Props>(), {
+  imageWidth: 150,
+  imageHeight: 150,
+  imageRadius: 0,
+  backgroundColor: "white",
+  direction: "row",
+  align: "center",
+  overflow: "hidden",
+  gap:20,
 })
 
 defineEmits([	
   "click"	
 ])
-</script>
-
-<style lang="scss">
-.nana-image-desc {
-  color: #fff;
-  font-size: 25rpx;
-  white-space: nowrap;
-  overflow: hidden;
-  text-overflow: ellipsis;
-}
-</style>
+</script>

+ 2 - 1
src/components/display/block/TextBlock.vue

@@ -137,6 +137,7 @@ defineProps({
     justify="space-between"
     align="center"
     direction="row"
+    :setCursor="false"
     v-bind="viewProps"
     @click="$emit('click')"
   >
@@ -170,7 +171,7 @@ defineProps({
           'nana-text',
           wrap ? 'wrap' : '',
         ]" 
-        :v-bind="textProps"
+        v-bind="textProps"
         :text="text"
       />
     </slot>

+ 1 - 0
src/components/display/block/TextLeftRightBlock.vue

@@ -101,6 +101,7 @@ defineProps({
 <template>
   <Touchable
     :touchable="touchable"
+    :setCursor="false"
     justify="space-between"
     align="flex-start"
     width="fill"

+ 39 - 35
src/components/display/title/SubTitle.vue

@@ -1,61 +1,65 @@
 <script setup lang="ts">
+import { useTheme, type ThemePaddingMargin, type ThemePaddingMarginProp } from '@/components/theme/ThemeDefine';
 import Icon from '@/components/basic/Icon.vue';
-import Text from '@/components/basic/Text.vue';
+import Text, { type TextProps } from '@/components/basic/Text.vue';
 import Touchable from '@/components/feedback/Touchable.vue';
 import FlexRow from '@/components/layout/FlexRow.vue';
 import Width from '@/components/layout/space/Width.vue';
-import { useTheme } from '@/components/theme/ThemeDefine';
-import { DynamicColor } from '@/components/theme/ThemeTools';
 
 defineEmits([ 'moreClicked' ])
-defineProps({
-  title: {
-    type: String,
-    default: ''
-  },
-  moreText: {
-    type: String,
-    default: '更多'
-  },
-  showMore: {
-    type: Boolean,
-    default: false
-  },
-  badgeColor: {
-    type: String,
-    default: 'primary'
-  },
+const props = withDefaults(defineProps<{
+  title?: string,
+  moreText?: string,
+  showMore?: boolean,
+  badgeColor?: string,
+  backgroundColor?: string,
+  padding?: ThemePaddingMarginProp,
+  titleProps?: TextProps,
+  badgeStyle?: object,
+}>(), {
+  title: '',
+  moreText: '更多',
+  showMore: false,
+  badgeColor: 'primary',
+  padding: () => [ 0, 0, 30, 0 ],
 })
 
 const theme = useTheme();
 
-const badgeStyle = theme.useThemeStyle({
+const finalBadgeStyle = theme.useThemeStyle({
   width: '10rpx',
   height: '32rpx',
   borderRadius: '5rpx',
   marginRight: '14rpx',
+  ...props.badgeStyle,
 })
 </script>
 
 <template>
-  <FlexRow justify="space-between" align="center" :padding="[ 0, 0, 30, 0 ]">
-    <slot name="left">
-      <FlexRow align="center">
-        <slot name="icon">
-          <view :style="{
-            ...badgeStyle,
-            backgroundColor: theme.resolveThemeColor(badgeColor),
-          }"></view>
-        </slot>
-        <Text fontConfig="h4" :text="title" />
-      </FlexRow>
-    </slot>
-    <slot name="right">
+  <FlexRow 
+    justify="space-between"
+    align="center" 
+    :padding="padding" 
+    :backgroundColor="backgroundColor"
+  >
+    <FlexRow align="center">
+      <slot name="icon">
+        <view :style="{
+          ...finalBadgeStyle,
+          backgroundColor: theme.resolveThemeColor(badgeColor),
+        }"></view>
+      </slot>
+      <slot name="titlePrefix" />
+      <Text fontConfig="h4" :text="title" v-bind="titleProps" />
+      <slot name="titleSuffix" />
+    </FlexRow>
+    <FlexRow align="center">
+      <slot name="right" />
       <Touchable v-if="showMore" align="center" touchable @click="$emit('moreClicked')">
         <Text fontConfig="subText" :text="moreText" />
         <Width :size="10" />
         <Icon icon="arrow-right" :size="26" />
       </Touchable>
-    </slot>
+    </FlexRow>
   </FlexRow>
 </template>

+ 9 - 9
src/components/feedback/Alert.vue

@@ -14,16 +14,16 @@
           info: 'background.info',
         }
       )),
-      borderStyle:'solid',
+      borderStyle: 'solid',
       borderColor: themeContext.resolveThemeColor(borderColor || selectStyleType(
         type, 'default', {
           default: 'border.default',
-          primary: 'primary',
-          success: 'success',
-          warning: 'warning',
-          danger: 'danger',
-          error: 'danger',
-          info: 'info',
+          primary: 'mask.primary',
+          success: 'mask.success',
+          warning: 'mask.warning',
+          danger: 'mask.danger',
+          error: 'mask.danger',
+          info: 'mask.info',
         }
       )),
       borderRadius: themeContext.resolveThemeSize('AlertBorderRadius', 16),
@@ -98,7 +98,7 @@
 <script setup lang="ts">
 import { computed } from 'vue';
 import { useTheme, type TextStyle, type ViewStyle } from '../theme/ThemeDefine';
-import { DynamicSize, DynamicColor, selectStyleType } from '../theme/ThemeTools';
+import { DynamicSize, DynamicColor, selectStyleType, DynamicVar } from '../theme/ThemeTools';
 import Text from '../basic/Text.vue';
 import Icon from '../basic/Icon.vue';
 import IconButton from '../basic/IconButton.vue';
@@ -212,7 +212,7 @@ const themeStyles = themeContext.useThemeStyles({
     alignItems: 'center',
     padding: DynamicSize('AlertPadding', 16),
     borderWidth: DynamicSize('AlertBorderWidth', '1px'),
-    borderStyle: 'solid',
+    borderStyle: DynamicVar('AlertBorderStyle', 'solid'),
   } as ViewStyle,
   icon: {
     fontSize: DynamicSize('AlertIconSize', 20),

+ 1 - 1
src/components/feedback/DropdownMenu.vue

@@ -44,7 +44,7 @@ export interface DropdownMenuProps {
    */
   duration?: number;
   /**
-   * 是否包含导航栏空间,这会影响弹出菜单的定位
+   * 是否包含导航栏空间,这会影响弹出菜单的定位。H5并且去掉系统导航栏需要设置为false
    * @default true
    */
   includeNavBarSpace?: boolean;

+ 1 - 2
src/components/feedback/DropdownMenuItem.vue

@@ -229,9 +229,7 @@ async function updateDialogMargin() {
 
   const d = await new Promise<UniApp.NodeInfo>((resolve, reject) => {
     uni.createSelectorQuery()
-      // #ifdef MP
       .in(instance)
-      // #endif
       .select(`#${id}`)
       .fields({
         id: true,
@@ -248,6 +246,7 @@ async function updateDialogMargin() {
       .exec();
   });
   const systemInfo = uni.getSystemInfoSync();
+  const pages = getCurrentPages();
   let v = 0
   if (topContext.direction.value === 'up') {
     if (topContext.includeNavBarSpace.value) {

+ 6 - 2
src/components/feedback/Toast.vue

@@ -164,7 +164,11 @@ const showProps = ref<ToastShowProps>({
 });
 let showTimer = 0;
 
-function show(options: ToastShowProps) {
+function show(options: ToastShowProps|string) {
+
+  if (typeof options === 'string')
+    options = { content: options };
+
   const { 
     duration = 0,
     type = 'text',
@@ -223,7 +227,7 @@ function handleClick() {
 }
 
 export interface ToastInstance {
-  show(options: ToastShowProps) : void;
+  show(options: ToastShowProps|string) : void;
   info(options?: ToastShowProps|string): void;
   success(options?: ToastShowProps|string): void;
   fail(options?: ToastShowProps|string): void;

+ 9 - 2
src/components/feedback/Touchable.vue

@@ -45,11 +45,17 @@ export interface TouchableFlexProps extends FlexProps {
    * @default 0.7
    */
   activeOpacity?: number,
+  /**
+   * 是否设置鼠标指针为指针
+   * @default true
+   */
+  setCursor?: boolean,
 }
 
 const props = withDefaults(defineProps<TouchableFlexProps>(), {
   activeOpacity: 0.7,
   touchable: true,
+  setCursor: true,
 });
 
 const themeContext = useTheme();
@@ -62,9 +68,10 @@ const finalStyle = computed(() => {
       obj.backgroundColor = themeContext.resolveThemeColor(props.pressedColor);
   } else if (props.activeOpacity != undefined) 
     obj.opacity = isPressed.value ? props.activeOpacity : 1;
-  const o = {
+  const o : Record<string, any> = {
     ...commonStyle.value,
-    ...obj
+    ...obj,
+    cursor: props.setCursor ? (props.touchable ? 'pointer' : 'not-allowed') : 'default',
   } 
   for (const key in o) {
     if (o[key] === undefined)

+ 1 - 0
src/components/form/Field.vue

@@ -10,6 +10,7 @@
       ...(focused ? activeFieldStyle : {}),
       ...(error || finalErrorMessage ? errorFieldStyle : {})
     }"
+    :setCursor="false"
     :direction="labelPosition === 'top' ? 'column' : 'row'"
     :justify="labelPosition === 'top' ? 'flex-start' : 'center'"
     @click="onClick"

+ 1 - 0
src/components/form/NumberInputBox.vue

@@ -7,6 +7,7 @@
       ...finalBoxStyle,
       ...boxStyle,
     }"
+    :setCursor="false"
     :pressedColor="themeContext.resolveThemeColor('pressed.white')"
     :touchable="!disableKeyPad"
     direction="column"

+ 19 - 2
src/components/form/Stepper.vue

@@ -10,13 +10,15 @@
       <IconButton
         :icon="minusIcon"
         :disabled="disabled || value <= min"
+        :color="buttonColor"
         :buttonStyle="{ 
           ...themeStyles.button.value,
           ...selectObjectByType(size, 'medium', {
             small: themeStyles.buttonSmall.value,
             medium: themeStyles.buttonMedium.value,
             large: themeStyles.buttonLarge.value,
-          })
+          }),
+          ...buttonStyle,
         }"
         :padding="5"
         :size="iconSize"
@@ -39,6 +41,7 @@
           medium: themeStyles.inputWrapperMedium.value,
           large: themeStyles.inputWrapperLarge.value,
         }),
+        ...inputStyle,
       }">
         <input
           :style="{
@@ -62,13 +65,15 @@
       <IconButton
         :icon="addIcon"
         :disabled="disabled || (max ? value >= max : undefined)"
+        :color="buttonColor"
         :buttonStyle="{ 
           ...themeStyles.button.value,
           ...selectObjectByType(size, 'medium', {
             small: themeStyles.buttonSmall.value,
             medium: themeStyles.buttonMedium.value,
             large: themeStyles.buttonLarge.value,
-          })
+          }),
+          ...buttonStyle,
         }"
         :padding="5"
         :size="iconSize"
@@ -180,6 +185,18 @@ export interface StepperProps {
    * 组件右侧添加的文本
    */
   addonAfter?: string,
+  /**
+   * 按钮颜色
+   */
+  buttonColor?: string,
+  /**
+   * 自定义按钮样式
+   */
+  buttonStyle?: Record<string, any>,
+  /**
+   * 自定义输入框样式
+   */
+  inputStyle?: Record<string, any>,
 }
 
 const emit = defineEmits([ 'update:modelValue' ])

BIN
src/components/images/icons/video-mark.png


+ 5 - 0
src/components/layout/BaseView.ts

@@ -24,7 +24,12 @@ export function useBaseViewStyleBuilder(props: FlexProps) {
       gap: themeContext.resolveThemeSize(props.gap),
       borderRadius: themeContext.resolveThemeSize(props.radius),
       overflow: props.overflow,
+      border: props.border && !props.border.includes(' ') ? themeContext.getVar('border.' + props.border, undefined) : props.border,
+      borderColor: themeContext.resolveThemeColor(props.borderColor),
+      borderWidth: themeContext.resolveThemeSize(props.borderWidth),
+      borderStyle: props.borderStyle,
       boxShadow: props.shadow ? themeContext.getVar('shadow.' + props.shadow, undefined) : undefined,
+      zIndex: props.zIndex,
       ...(props.innerStyle ? props.innerStyle : {}),
     }
 

+ 21 - 1
src/components/layout/FlexView.vue

@@ -111,10 +111,26 @@ export interface FlexProps {
    */
   backgroundColor?: string,
   /**
-   * 阴影。使用主中的阴影预设。
+   * 阴影。使用主中的阴影预设。
    */
   shadow?: string,
   /**
+   * 阴影。使用主题中的阴影预设。
+   */
+  border?: string,
+  /**
+   * 边框颜色
+   */
+  borderColor?: string,
+  /**
+   * 边框宽度
+   */
+  borderWidth?: number|string,
+  /**
+   * 边框样式
+   */
+  borderStyle?: string,
+  /**
    * 宽度
    */
   width?: number|string,
@@ -123,6 +139,10 @@ export interface FlexProps {
    */
   height?: number|string,
   overflow?: 'visible'|'hidden'|'scroll'|'auto'
+  /**
+   * 层级
+   */
+  zIndex?: number,
 }
 
 const props = withDefaults(defineProps<FlexProps>(), {

+ 1 - 0
src/components/layout/grid/GridItem.vue

@@ -4,6 +4,7 @@
     :direction="flexDirection"
     :innerStyle="style"
     :touchable="touchable"
+    :setCursor="false"
     :radius="themeContext.resolveThemeSize(radius)"
     @click="emit('click')"
   >

+ 0 - 2
src/components/nav/IndexBar.vue

@@ -190,9 +190,7 @@ function handleTouchStart(e: any) {
   e.stopPropagation();
   const query = uni.createSelectorQuery();
   query
-    // #ifdef MP
     .in(instance)
-    // #endif
     .select('#' + id)
     .boundingClientRect((res) => {
       if (res)

+ 12 - 3
src/components/theme/Theme.ts

@@ -17,9 +17,14 @@ export const DefaultTheme : ThemeConfig = {
       larger: 46,
     },
     shadow: {
-      default: '0 0 10rpx rgba(0, 0, 0, 0.1)',
-      light: '0 0 10rpx rgba(0, 0, 0, 0.05)',
-      dark: '0 0 10rpx rgba(0, 0, 0, 0.2)',
+      default: '0 0 10px rgba(0, 0, 0, 0.1)',
+      light: '0 0 10px rgba(0, 0, 0, 0.05)',
+      dark: '0 0 10px rgba(0, 0, 0, 0.2)',
+      none: 'none',
+    },
+    border: {
+      default: '1px solid #dddddd',
+      none: 'none',
     },
   },
   colorConfigs: {
@@ -134,6 +139,10 @@ export const DefaultTheme : ThemeConfig = {
       color: 'text.content',
       fontSize: '24rpx',
     },
+    subTitle: {
+      color: 'text.content',
+      fontSize: '34rpx',
+    },
     subText: {
       color: 'text.content',
       fontSize: '26rpx',

+ 5 - 1
src/components/theme/ThemeDefine.ts

@@ -140,7 +140,9 @@ export function useTheme() {
     if (key === undefined)
       return defaultValue;
     let type = '';
-    key = getVar(key, key);
+    let keyResolve = getVar(key, key);
+    if (typeof keyResolve === 'string')
+      key = keyResolve;
     if (key.includes('.'))
       [type, key] = key.split('.');
     let group = theme.value.colorConfigs[type || 'default'];
@@ -280,6 +282,8 @@ export function resolveSize(inValue: string|number|undefined) : string|undefined
   return undefined;
 }
 
+export type ThemePaddingMarginProp = number | number[] | ThemePaddingMargin
+
 export interface ThemePaddingMargin {
   l?: number,
   r?: number,

+ 1 - 1
src/components/typography/HorizontalScrollText.vue

@@ -83,7 +83,7 @@ async function lodScrollInfo() {
   })
 
   let textWidth = await realTextRef.value.measureTextWidth();
-  console.log('textWidth', textWidth, 'conWidth', conWidth);
+  //console.log('textWidth', textWidth, 'conWidth', conWidth);
   
   if (textWidth == conWidth) { 
     await waitTimeOut(200);