chore: initial commit
This commit is contained in:
20
packages/materials/package.json
Normal file
20
packages/materials/package.json
Normal file
@@ -0,0 +1,20 @@
|
||||
{
|
||||
"name": "@sa/materials",
|
||||
"version": "1.3.15",
|
||||
"exports": {
|
||||
".": "./src/index.ts"
|
||||
},
|
||||
"typesVersions": {
|
||||
"*": {
|
||||
"*": [
|
||||
"./src/*"
|
||||
]
|
||||
}
|
||||
},
|
||||
"scripts": {
|
||||
"gen:css-types": "bunx --bun typed-css-modules src --pattern '**/*.module.css'"
|
||||
},
|
||||
"dependencies": {
|
||||
"simplebar-vue": "2.4.2"
|
||||
}
|
||||
}
|
||||
6
packages/materials/src/index.ts
Normal file
6
packages/materials/src/index.ts
Normal file
@@ -0,0 +1,6 @@
|
||||
import AdminLayout, { LAYOUT_MAX_Z_INDEX, LAYOUT_SCROLL_EL_ID } from './libs/admin-layout';
|
||||
|
||||
import SimpleScrollbar from './libs/simple-scrollbar';
|
||||
|
||||
export { AdminLayout, LAYOUT_SCROLL_EL_ID, LAYOUT_MAX_Z_INDEX, SimpleScrollbar };
|
||||
export * from './types';
|
||||
63
packages/materials/src/libs/admin-layout/index.module.css
Normal file
63
packages/materials/src/libs/admin-layout/index.module.css
Normal file
@@ -0,0 +1,63 @@
|
||||
/* @type */
|
||||
|
||||
.layout-header,
|
||||
.layout-header-placement {
|
||||
height: var(--soy-header-height);
|
||||
}
|
||||
|
||||
.layout-header {
|
||||
z-index: var(--soy-header-z-index);
|
||||
}
|
||||
|
||||
.layout-tab {
|
||||
top: var(--soy-header-height);
|
||||
z-index: var(--soy-tab-z-index);
|
||||
height: var(--soy-tab-height);
|
||||
}
|
||||
|
||||
.layout-tab-placement {
|
||||
height: var(--soy-tab-height);
|
||||
}
|
||||
|
||||
.layout-sider {
|
||||
z-index: var(--soy-sider-z-index);
|
||||
width: var(--soy-sider-width);
|
||||
}
|
||||
|
||||
.layout-mobile-sider {
|
||||
z-index: var(--soy-sider-z-index);
|
||||
}
|
||||
|
||||
.layout-mobile-sider-mask {
|
||||
z-index: var(--soy-mobile-sider-z-index);
|
||||
}
|
||||
|
||||
.layout-sider-collapsed {
|
||||
z-index: var(--soy-sider-z-index);
|
||||
width: var(--soy-sider-collapsed-width);
|
||||
}
|
||||
|
||||
.layout-footer,
|
||||
.layout-footer-placement {
|
||||
height: var(--soy-footer-height);
|
||||
}
|
||||
|
||||
.layout-footer {
|
||||
z-index: var(--soy-footer-z-index);
|
||||
}
|
||||
|
||||
.left-gap {
|
||||
padding-left: var(--soy-sider-width);
|
||||
}
|
||||
|
||||
.left-gap-collapsed {
|
||||
padding-left: var(--soy-sider-collapsed-width);
|
||||
}
|
||||
|
||||
.sider-padding-top {
|
||||
padding-top: var(--soy-header-height);
|
||||
}
|
||||
|
||||
.sider-padding-bottom {
|
||||
padding-bottom: var(--soy-footer-height);
|
||||
}
|
||||
17
packages/materials/src/libs/admin-layout/index.module.css.d.ts
vendored
Normal file
17
packages/materials/src/libs/admin-layout/index.module.css.d.ts
vendored
Normal file
@@ -0,0 +1,17 @@
|
||||
declare const styles: {
|
||||
readonly 'layout-footer': string;
|
||||
readonly 'layout-footer-placement': string;
|
||||
readonly 'layout-header': string;
|
||||
readonly 'layout-header-placement': string;
|
||||
readonly 'layout-mobile-sider': string;
|
||||
readonly 'layout-mobile-sider-mask': string;
|
||||
readonly 'layout-sider': string;
|
||||
readonly 'layout-sider-collapsed': string;
|
||||
readonly 'layout-tab': string;
|
||||
readonly 'layout-tab-placement': string;
|
||||
readonly 'left-gap': string;
|
||||
readonly 'left-gap-collapsed': string;
|
||||
readonly 'sider-padding-bottom': string;
|
||||
readonly 'sider-padding-top': string;
|
||||
};
|
||||
export = styles;
|
||||
5
packages/materials/src/libs/admin-layout/index.ts
Normal file
5
packages/materials/src/libs/admin-layout/index.ts
Normal file
@@ -0,0 +1,5 @@
|
||||
import AdminLayout from './index.vue';
|
||||
import { LAYOUT_MAX_Z_INDEX, LAYOUT_SCROLL_EL_ID } from './shared';
|
||||
|
||||
export default AdminLayout;
|
||||
export { LAYOUT_SCROLL_EL_ID, LAYOUT_MAX_Z_INDEX };
|
||||
238
packages/materials/src/libs/admin-layout/index.vue
Normal file
238
packages/materials/src/libs/admin-layout/index.vue
Normal file
@@ -0,0 +1,238 @@
|
||||
<script setup lang="ts">
|
||||
import { computed } from 'vue';
|
||||
import type { AdminLayoutProps } from '../../types';
|
||||
import { LAYOUT_MAX_Z_INDEX, LAYOUT_SCROLL_EL_ID, createLayoutCssVars } from './shared';
|
||||
import style from './index.module.css';
|
||||
|
||||
defineOptions({
|
||||
name: 'AdminLayout',
|
||||
});
|
||||
|
||||
const props = withDefaults(defineProps<AdminLayoutProps>(), {
|
||||
mode: 'vertical',
|
||||
scrollMode: 'content',
|
||||
scrollElId: LAYOUT_SCROLL_EL_ID,
|
||||
commonClass: 'transition-all-300',
|
||||
fixedTop: true,
|
||||
maxZIndex: LAYOUT_MAX_Z_INDEX,
|
||||
headerVisible: true,
|
||||
headerHeight: 56,
|
||||
tabVisible: true,
|
||||
tabHeight: 48,
|
||||
siderVisible: true,
|
||||
siderCollapse: false,
|
||||
siderWidth: 220,
|
||||
siderCollapsedWidth: 64,
|
||||
footerVisible: true,
|
||||
footerHeight: 48,
|
||||
rightFooter: false,
|
||||
});
|
||||
|
||||
const emit = defineEmits<Emits>();
|
||||
|
||||
const slots = defineSlots<Slots>();
|
||||
|
||||
interface Emits {
|
||||
/** Update siderCollapse */
|
||||
(e: 'update:siderCollapse', collapse: boolean): void;
|
||||
}
|
||||
|
||||
type SlotFn = (props?: Record<string, unknown>) => any;
|
||||
|
||||
type Slots = {
|
||||
/** Main */
|
||||
default?: SlotFn;
|
||||
/** Header */
|
||||
header?: SlotFn;
|
||||
/** Tab */
|
||||
tab?: SlotFn;
|
||||
/** Sider */
|
||||
sider?: SlotFn;
|
||||
/** Footer */
|
||||
footer?: SlotFn;
|
||||
};
|
||||
|
||||
const cssVars = computed(() => createLayoutCssVars(props));
|
||||
|
||||
// config visible
|
||||
const showHeader = computed(() => Boolean(slots.header) && props.headerVisible);
|
||||
const showTab = computed(() => Boolean(slots.tab) && props.tabVisible);
|
||||
const showSider = computed(() => !props.isMobile && Boolean(slots.sider) && props.siderVisible);
|
||||
const showMobileSider = computed(
|
||||
() => props.isMobile && Boolean(slots.sider) && props.siderVisible,
|
||||
);
|
||||
const showFooter = computed(() => Boolean(slots.footer) && props.footerVisible);
|
||||
|
||||
// scroll mode
|
||||
const isWrapperScroll = computed(() => props.scrollMode === 'wrapper');
|
||||
const isContentScroll = computed(() => props.scrollMode === 'content');
|
||||
|
||||
// layout direction
|
||||
const isVertical = computed(() => props.mode === 'vertical');
|
||||
const isHorizontal = computed(() => props.mode === 'horizontal');
|
||||
|
||||
const fixedHeaderAndTab = computed(
|
||||
() => props.fixedTop || (isHorizontal.value && isWrapperScroll.value),
|
||||
);
|
||||
|
||||
// css
|
||||
const leftGapClass = computed(() => {
|
||||
if (!props.fullContent && showSider.value) {
|
||||
return props.siderCollapse ? style['left-gap-collapsed'] : style['left-gap'];
|
||||
}
|
||||
|
||||
return '';
|
||||
});
|
||||
|
||||
const headerLeftGapClass = computed(() => (isVertical.value ? leftGapClass.value : ''));
|
||||
|
||||
const footerLeftGapClass = computed(() => {
|
||||
const condition1 = isVertical.value;
|
||||
const condition2 = isHorizontal.value && isWrapperScroll.value && !props.fixedFooter;
|
||||
const condition3 = Boolean(isHorizontal.value && props.rightFooter);
|
||||
|
||||
if (condition1 || condition2 || condition3) {
|
||||
return leftGapClass.value;
|
||||
}
|
||||
|
||||
return '';
|
||||
});
|
||||
|
||||
const siderPaddingClass = computed(() => {
|
||||
let cls = '';
|
||||
|
||||
if (showHeader.value && !headerLeftGapClass.value) {
|
||||
cls += style['sider-padding-top'];
|
||||
}
|
||||
if (showFooter.value && !footerLeftGapClass.value) {
|
||||
cls += ` ${style['sider-padding-bottom']}`;
|
||||
}
|
||||
|
||||
return cls;
|
||||
});
|
||||
|
||||
function handleClickMask() {
|
||||
emit('update:siderCollapse', true);
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="relative h-full" :class="[commonClass]" :style="cssVars">
|
||||
<div
|
||||
:id="isWrapperScroll ? scrollElId : undefined"
|
||||
class="h-full flex flex-col"
|
||||
:class="[commonClass, scrollWrapperClass, { 'overflow-y-auto': isWrapperScroll }]"
|
||||
>
|
||||
<!-- Header -->
|
||||
<template v-if="showHeader">
|
||||
<header
|
||||
v-show="!fullContent"
|
||||
class="flex-shrink-0"
|
||||
:class="[
|
||||
style['layout-header'],
|
||||
commonClass,
|
||||
headerLeftGapClass,
|
||||
{ 'absolute top-0 left-0 w-full': fixedHeaderAndTab },
|
||||
]"
|
||||
>
|
||||
<slot name="header"></slot>
|
||||
</header>
|
||||
<div
|
||||
v-show="!fullContent && fixedHeaderAndTab"
|
||||
class="flex-shrink-0 overflow-hidden"
|
||||
:class="[style['layout-header-placement']]"
|
||||
></div>
|
||||
</template>
|
||||
|
||||
<!-- Tab -->
|
||||
<template v-if="showTab">
|
||||
<div
|
||||
class="flex-shrink-0 overflow-hidden"
|
||||
:class="[
|
||||
style['layout-tab'],
|
||||
commonClass,
|
||||
tabClass,
|
||||
{ 'top-0!': fullContent || !showHeader },
|
||||
leftGapClass,
|
||||
{ 'absolute left-0 w-full': fixedHeaderAndTab },
|
||||
]"
|
||||
>
|
||||
<slot name="tab"></slot>
|
||||
</div>
|
||||
<div
|
||||
v-show="fullContent || fixedHeaderAndTab"
|
||||
class="flex-shrink-0 overflow-hidden"
|
||||
:class="[style['layout-tab-placement']]"
|
||||
></div>
|
||||
</template>
|
||||
|
||||
<!-- Sider -->
|
||||
<template v-if="showSider">
|
||||
<aside
|
||||
v-show="!fullContent"
|
||||
class="absolute left-0 top-0 h-full"
|
||||
:class="[
|
||||
commonClass,
|
||||
siderClass,
|
||||
siderPaddingClass,
|
||||
siderCollapse ? style['layout-sider-collapsed'] : style['layout-sider'],
|
||||
]"
|
||||
>
|
||||
<slot name="sider"></slot>
|
||||
</aside>
|
||||
</template>
|
||||
|
||||
<!-- Mobile Sider -->
|
||||
<template v-if="showMobileSider">
|
||||
<aside
|
||||
class="absolute left-0 top-0 h-full w-0 bg-white"
|
||||
:class="[
|
||||
commonClass,
|
||||
mobileSiderClass,
|
||||
style['layout-mobile-sider'],
|
||||
siderCollapse ? 'overflow-hidden' : style['layout-sider'],
|
||||
]"
|
||||
>
|
||||
<slot name="sider"></slot>
|
||||
</aside>
|
||||
<div
|
||||
v-show="!siderCollapse"
|
||||
class="absolute left-0 top-0 h-full w-full bg-[rgba(0,0,0,0.2)]"
|
||||
:class="[style['layout-mobile-sider-mask']]"
|
||||
@click="handleClickMask"
|
||||
></div>
|
||||
</template>
|
||||
|
||||
<!-- Main Content -->
|
||||
<main
|
||||
:id="isContentScroll ? scrollElId : undefined"
|
||||
class="flex flex-col flex-grow"
|
||||
:class="[commonClass, contentClass, leftGapClass, { 'overflow-y-auto': isContentScroll }]"
|
||||
>
|
||||
<slot></slot>
|
||||
</main>
|
||||
|
||||
<!-- Footer -->
|
||||
<template v-if="showFooter">
|
||||
<footer
|
||||
v-show="!fullContent"
|
||||
class="flex-shrink-0"
|
||||
:class="[
|
||||
style['layout-footer'],
|
||||
commonClass,
|
||||
footerClass,
|
||||
footerLeftGapClass,
|
||||
{ 'absolute left-0 bottom-0 w-full': fixedFooter },
|
||||
]"
|
||||
>
|
||||
<slot name="footer"></slot>
|
||||
</footer>
|
||||
<div
|
||||
v-show="!fullContent && fixedFooter"
|
||||
class="flex-shrink-0 overflow-hidden"
|
||||
:class="[style['layout-footer-placement']]"
|
||||
></div>
|
||||
</template>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
68
packages/materials/src/libs/admin-layout/shared.ts
Normal file
68
packages/materials/src/libs/admin-layout/shared.ts
Normal file
@@ -0,0 +1,68 @@
|
||||
import type { AdminLayoutProps, LayoutCssVars, LayoutCssVarsProps } from '../../types';
|
||||
|
||||
/** The id of the scroll element of the layout */
|
||||
export const LAYOUT_SCROLL_EL_ID = '__SCROLL_EL_ID__';
|
||||
|
||||
/** The max z-index of the layout */
|
||||
export const LAYOUT_MAX_Z_INDEX = 100;
|
||||
|
||||
/**
|
||||
* Create layout css vars by css vars props
|
||||
*
|
||||
* @param props Css vars props
|
||||
*/
|
||||
function createLayoutCssVarsByCssVarsProps(props: LayoutCssVarsProps) {
|
||||
const cssVars: LayoutCssVars = {
|
||||
'--soy-header-height': `${props.headerHeight}px`,
|
||||
'--soy-header-z-index': props.headerZIndex,
|
||||
'--soy-tab-height': `${props.tabHeight}px`,
|
||||
'--soy-tab-z-index': props.tabZIndex,
|
||||
'--soy-sider-width': `${props.siderWidth}px`,
|
||||
'--soy-sider-collapsed-width': `${props.siderCollapsedWidth}px`,
|
||||
'--soy-sider-z-index': props.siderZIndex,
|
||||
'--soy-mobile-sider-z-index': props.mobileSiderZIndex,
|
||||
'--soy-footer-height': `${props.footerHeight}px`,
|
||||
'--soy-footer-z-index': props.footerZIndex
|
||||
};
|
||||
|
||||
return cssVars;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create layout css vars
|
||||
*
|
||||
* @param props
|
||||
*/
|
||||
export function createLayoutCssVars(props: AdminLayoutProps) {
|
||||
const {
|
||||
mode,
|
||||
isMobile,
|
||||
maxZIndex = LAYOUT_MAX_Z_INDEX,
|
||||
headerHeight,
|
||||
tabHeight,
|
||||
siderWidth,
|
||||
siderCollapsedWidth,
|
||||
footerHeight
|
||||
} = props;
|
||||
|
||||
const headerZIndex = maxZIndex - 3;
|
||||
const tabZIndex = maxZIndex - 5;
|
||||
const siderZIndex = mode === 'vertical' || isMobile ? maxZIndex - 1 : maxZIndex - 4;
|
||||
const mobileSiderZIndex = isMobile ? maxZIndex - 2 : 0;
|
||||
const footerZIndex = maxZIndex - 5;
|
||||
|
||||
const cssProps: LayoutCssVarsProps = {
|
||||
headerHeight,
|
||||
headerZIndex,
|
||||
tabHeight,
|
||||
tabZIndex,
|
||||
siderWidth,
|
||||
siderZIndex,
|
||||
mobileSiderZIndex,
|
||||
siderCollapsedWidth,
|
||||
footerHeight,
|
||||
footerZIndex
|
||||
};
|
||||
|
||||
return createLayoutCssVarsByCssVarsProps(cssProps);
|
||||
}
|
||||
3
packages/materials/src/libs/simple-scrollbar/index.ts
Normal file
3
packages/materials/src/libs/simple-scrollbar/index.ts
Normal file
@@ -0,0 +1,3 @@
|
||||
import SimpleScrollbar from './index.vue';
|
||||
|
||||
export default SimpleScrollbar;
|
||||
16
packages/materials/src/libs/simple-scrollbar/index.vue
Normal file
16
packages/materials/src/libs/simple-scrollbar/index.vue
Normal file
@@ -0,0 +1,16 @@
|
||||
<script setup lang="ts">
|
||||
import Simplebar from 'simplebar-vue';
|
||||
import 'simplebar-vue/dist/simplebar.min.css';
|
||||
|
||||
defineOptions({
|
||||
name: 'SimpleScrollbar',
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="h-full flex-1-hidden">
|
||||
<Simplebar class="h-full">
|
||||
<slot />
|
||||
</Simplebar>
|
||||
</div>
|
||||
</template>
|
||||
288
packages/materials/src/types/index.ts
Normal file
288
packages/materials/src/types/index.ts
Normal file
@@ -0,0 +1,288 @@
|
||||
/** Header config */
|
||||
interface AdminLayoutHeaderConfig {
|
||||
/**
|
||||
* Whether header is visible
|
||||
*
|
||||
* @default true
|
||||
*/
|
||||
headerVisible?: boolean;
|
||||
/**
|
||||
* Header height
|
||||
*
|
||||
* @default 56px
|
||||
*/
|
||||
headerHeight?: number;
|
||||
}
|
||||
|
||||
/** Tab config */
|
||||
interface AdminLayoutTabConfig {
|
||||
/**
|
||||
* Whether tab is visible
|
||||
*
|
||||
* @default true
|
||||
*/
|
||||
tabVisible?: boolean;
|
||||
/**
|
||||
* Tab class
|
||||
*
|
||||
* @default ''
|
||||
*/
|
||||
tabClass?: string;
|
||||
/**
|
||||
* Tab height
|
||||
*
|
||||
* @default 48px
|
||||
*/
|
||||
tabHeight?: number;
|
||||
}
|
||||
|
||||
/** Sider config */
|
||||
interface AdminLayoutSiderConfig {
|
||||
/**
|
||||
* Whether sider is visible
|
||||
*
|
||||
* @default true
|
||||
*/
|
||||
siderVisible?: boolean;
|
||||
/**
|
||||
* Sider class
|
||||
*
|
||||
* @default ''
|
||||
*/
|
||||
siderClass?: string;
|
||||
/**
|
||||
* Mobile sider class
|
||||
*
|
||||
* @default ''
|
||||
*/
|
||||
mobileSiderClass?: string;
|
||||
/**
|
||||
* Sider collapse status
|
||||
*
|
||||
* @default false
|
||||
*/
|
||||
siderCollapse?: boolean;
|
||||
/**
|
||||
* Sider width when collapse is false
|
||||
*
|
||||
* @default '220px'
|
||||
*/
|
||||
siderWidth?: number;
|
||||
/**
|
||||
* Sider width when collapse is true
|
||||
*
|
||||
* @default '64px'
|
||||
*/
|
||||
siderCollapsedWidth?: number;
|
||||
}
|
||||
|
||||
/** Content config */
|
||||
export interface AdminLayoutContentConfig {
|
||||
/**
|
||||
* Content class
|
||||
*
|
||||
* @default ''
|
||||
*/
|
||||
contentClass?: string;
|
||||
/**
|
||||
* Whether content is full the page
|
||||
*
|
||||
* If true, other elements will be hidden by `display: none`
|
||||
*/
|
||||
fullContent?: boolean;
|
||||
}
|
||||
|
||||
/** Footer config */
|
||||
export interface AdminLayoutFooterConfig {
|
||||
/**
|
||||
* Whether footer is visible
|
||||
*
|
||||
* @default true
|
||||
*/
|
||||
footerVisible?: boolean;
|
||||
/**
|
||||
* Whether footer is fixed
|
||||
*
|
||||
* @default true
|
||||
*/
|
||||
fixedFooter?: boolean;
|
||||
/**
|
||||
* Footer class
|
||||
*
|
||||
* @default ''
|
||||
*/
|
||||
footerClass?: string;
|
||||
/**
|
||||
* Footer height
|
||||
*
|
||||
* @default 48px
|
||||
*/
|
||||
footerHeight?: number;
|
||||
/**
|
||||
* Whether footer is on the right side
|
||||
*
|
||||
* When the layout is vertical, the footer is on the right side
|
||||
*/
|
||||
rightFooter?: boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
* Layout mode
|
||||
*
|
||||
* - Horizontal
|
||||
* - Vertical
|
||||
*/
|
||||
export type LayoutMode = 'horizontal' | 'vertical';
|
||||
|
||||
/**
|
||||
* The scroll mode when content overflow
|
||||
*
|
||||
* - Wrapper: the layout component's wrapper element has a scrollbar
|
||||
* - Content: the layout component's content element has a scrollbar
|
||||
*
|
||||
* @default 'wrapper'
|
||||
*/
|
||||
export type LayoutScrollMode = 'wrapper' | 'content';
|
||||
|
||||
/** Admin layout props */
|
||||
export interface AdminLayoutProps
|
||||
extends AdminLayoutHeaderConfig,
|
||||
AdminLayoutTabConfig,
|
||||
AdminLayoutSiderConfig,
|
||||
AdminLayoutContentConfig,
|
||||
AdminLayoutFooterConfig {
|
||||
/**
|
||||
* Layout mode
|
||||
*
|
||||
* - {@link LayoutMode}
|
||||
*/
|
||||
mode?: LayoutMode;
|
||||
/** Is mobile layout */
|
||||
isMobile?: boolean;
|
||||
/**
|
||||
* Scroll mode
|
||||
*
|
||||
* - {@link ScrollMode}
|
||||
*/
|
||||
scrollMode?: LayoutScrollMode;
|
||||
/**
|
||||
* The id of the scroll element of the layout
|
||||
*
|
||||
* It can be used to get the corresponding Dom and scroll it
|
||||
*
|
||||
* @example
|
||||
* use the default id by import
|
||||
* ```ts
|
||||
* import { adminLayoutScrollElId } from '@sa/vue-materials';
|
||||
* ```
|
||||
*
|
||||
* @default
|
||||
* ```ts
|
||||
* const adminLayoutScrollElId = '__ADMIN_LAYOUT_SCROLL_EL_ID__'
|
||||
* ```
|
||||
*/
|
||||
scrollElId?: string;
|
||||
/** The class of the scroll element */
|
||||
scrollElClass?: string;
|
||||
/** The class of the scroll wrapper element */
|
||||
scrollWrapperClass?: string;
|
||||
/**
|
||||
* The common class of the layout
|
||||
*
|
||||
* Is can be used to configure the transition animation
|
||||
*
|
||||
* @default 'transition-all-300'
|
||||
*/
|
||||
commonClass?: string;
|
||||
/**
|
||||
* Whether fix the header and tab
|
||||
*
|
||||
* @default true
|
||||
*/
|
||||
fixedTop?: boolean;
|
||||
/**
|
||||
* The max z-index of the layout
|
||||
*
|
||||
* The z-index of Header,Tab,Sider and Footer will not exceed this value
|
||||
*/
|
||||
maxZIndex?: number;
|
||||
}
|
||||
|
||||
type Kebab<S extends string> = S extends Uncapitalize<S> ? S : `-${Uncapitalize<S>}`;
|
||||
|
||||
type KebabCase<S extends string> = S extends `${infer Start}${infer End}`
|
||||
? `${Uncapitalize<Start>}${KebabCase<Kebab<End>>}`
|
||||
: S;
|
||||
|
||||
type Prefix = '--soy-';
|
||||
|
||||
export type LayoutCssVarsProps = Pick<
|
||||
AdminLayoutProps,
|
||||
'headerHeight' | 'tabHeight' | 'siderWidth' | 'siderCollapsedWidth' | 'footerHeight'
|
||||
> & {
|
||||
headerZIndex?: number;
|
||||
tabZIndex?: number;
|
||||
siderZIndex?: number;
|
||||
mobileSiderZIndex?: number;
|
||||
footerZIndex?: number;
|
||||
};
|
||||
|
||||
export type LayoutCssVars = {
|
||||
[K in keyof LayoutCssVarsProps as `${Prefix}${KebabCase<K>}`]: string | number;
|
||||
};
|
||||
|
||||
/**
|
||||
* The mode of the tab
|
||||
*
|
||||
* - Button: button style
|
||||
* - Chrome: chrome style
|
||||
*
|
||||
* @default chrome
|
||||
*/
|
||||
export type PageTabMode = 'button' | 'chrome';
|
||||
|
||||
export interface PageTabProps {
|
||||
/** Whether is dark mode */
|
||||
darkMode?: boolean;
|
||||
/**
|
||||
* The mode of the tab
|
||||
*
|
||||
* - {@link TabMode}
|
||||
*/
|
||||
mode?: PageTabMode;
|
||||
/**
|
||||
* The common class of the layout
|
||||
*
|
||||
* Is can be used to configure the transition animation
|
||||
*
|
||||
* @default 'transition-all-300'
|
||||
*/
|
||||
commonClass?: string;
|
||||
/** The class of the button tab */
|
||||
buttonClass?: string;
|
||||
/** The class of the chrome tab */
|
||||
chromeClass?: string;
|
||||
/** Whether the tab is active */
|
||||
active?: boolean;
|
||||
/** The color of the active tab */
|
||||
activeColor?: string;
|
||||
/**
|
||||
* Whether the tab is closable
|
||||
*
|
||||
* Show the close icon when true
|
||||
*/
|
||||
closable?: boolean;
|
||||
}
|
||||
|
||||
export type PageTabCssVarsProps = {
|
||||
primaryColor: string;
|
||||
primaryColor1: string;
|
||||
primaryColor2: string;
|
||||
primaryColorOpacity1: string;
|
||||
primaryColorOpacity2: string;
|
||||
primaryColorOpacity3: string;
|
||||
};
|
||||
|
||||
export type PageTabCssVars = {
|
||||
[K in keyof PageTabCssVarsProps as `${Prefix}${KebabCase<K>}`]: string | number;
|
||||
};
|
||||
20
packages/materials/tsconfig.json
Normal file
20
packages/materials/tsconfig.json
Normal file
@@ -0,0 +1,20 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"target": "ESNext",
|
||||
"jsx": "preserve",
|
||||
"lib": ["DOM", "ESNext"],
|
||||
"baseUrl": ".",
|
||||
"module": "ESNext",
|
||||
"moduleResolution": "node",
|
||||
"resolveJsonModule": true,
|
||||
"types": ["node"],
|
||||
"strict": true,
|
||||
"strictNullChecks": true,
|
||||
"noUnusedLocals": true,
|
||||
"allowSyntheticDefaultImports": true,
|
||||
"esModuleInterop": true,
|
||||
"forceConsistentCasingInFileNames": true
|
||||
},
|
||||
"include": ["src/**/*"],
|
||||
"exclude": ["node_modules", "dist"]
|
||||
}
|
||||
Reference in New Issue
Block a user