Compare commits
10 Commits
258c010f4d
...
13419e5313
Author | SHA1 | Date | |
---|---|---|---|
|
13419e5313 | ||
|
ad408b9b2a | ||
|
abc7b0a29e | ||
|
55ff7331d0 | ||
|
20aefb48ce | ||
|
fc3bc6f210 | ||
|
47ed4f7de6 | ||
|
fceeb92c06 | ||
|
c0815b0a21 | ||
|
9d534f5f37 |
53
src/components/ActionIcon/ActionIcon.jsx
Normal file
53
src/components/ActionIcon/ActionIcon.jsx
Normal file
|
@ -0,0 +1,53 @@
|
|||
import cx from "clsx";
|
||||
import { prop } from "ramda";
|
||||
import { mergeProps } from "solid-js";
|
||||
import classes from "./ActionIcon.module.css";
|
||||
|
||||
/**
|
||||
* @typedef {object} ActionIconProps
|
||||
* @property {"s" | "m" | "l" | "xl" | "xxl"} [size]
|
||||
* @property {"filled" | "subtle" | "transparent"} [variant]
|
||||
* @property {"primary" | "secondary" | "danger" | "warn" | "success" | "info"} [color]
|
||||
* @property {string[]} [additionalClasses]
|
||||
* @property {boolean} [disabled]
|
||||
* @property {JSX.EventHandler<HTMLButtonElement, PointerEvent>} [onClick]
|
||||
*/
|
||||
|
||||
/**
|
||||
* @param {import("solid-js").ParentProps<ActionIconProps>} props
|
||||
*/
|
||||
export default function ActionIcon(props) {
|
||||
const mergedProps = mergeProps(
|
||||
{
|
||||
size: "m",
|
||||
color: "secondary",
|
||||
variant: "transparent",
|
||||
additionalClasses: [],
|
||||
disabled: false,
|
||||
onClick: (e) => {},
|
||||
},
|
||||
props
|
||||
);
|
||||
const handleClick = (e) => {
|
||||
if (mergedProps.disabled) {
|
||||
return;
|
||||
}
|
||||
mergedProps.onClick(e);
|
||||
};
|
||||
|
||||
return (
|
||||
<button
|
||||
class={cx(
|
||||
prop("action-icon-button", classes),
|
||||
prop(`size-${mergedProps.size}`, classes),
|
||||
prop(`variant-${mergedProps.variant}`, classes),
|
||||
prop(`color-${mergedProps.color}`, classes),
|
||||
...mergedProps.additionalClasses
|
||||
)}
|
||||
disabled={mergedProps.disabled}
|
||||
onClick={handleClick}
|
||||
>
|
||||
{mergedProps.children}
|
||||
</button>
|
||||
);
|
||||
}
|
80
src/components/ActionIcon/ActionIcon.module.css
Normal file
80
src/components/ActionIcon/ActionIcon.module.css
Normal file
|
@ -0,0 +1,80 @@
|
|||
@import "@/mixins.css";
|
||||
|
||||
.action-icon-button {
|
||||
--size: calc(var(--border-radius-xxs) * 2);
|
||||
border: none;
|
||||
@util padding(0);
|
||||
@each $size in (s, m, l, xl, xxl) {
|
||||
&.size-#{$size} {
|
||||
--size: calc(var(--border-radius-#{$size}) * 2);
|
||||
@util size(calc(var(--size) * 2), calc(var(--size) * 2));
|
||||
border-radius: var(--size);
|
||||
& svg {
|
||||
@util size(calc(var(--size) * 1.4), calc(var(--size) * 1.4));
|
||||
}
|
||||
}
|
||||
}
|
||||
@each $color in (primary, secondary, danger, warn, success, info) {
|
||||
&.color-#{$color} {
|
||||
color: var(--palette-white-3);
|
||||
&.variant-transparent {
|
||||
color: var(--color-#{$color});
|
||||
background-color: transparent;
|
||||
&[disabled] {
|
||||
color: var(--palette-gray-4);
|
||||
@include dark-mode {
|
||||
color: var(--palette-gray-8);
|
||||
}
|
||||
}
|
||||
}
|
||||
&.variant-subtle {
|
||||
background-color: color-mod(var(--color-#{$color}) a(50%));
|
||||
&[disabled] {
|
||||
color: var(--palette-gray-4);
|
||||
background-color: color-mod(var(--palette-gray-6) a(50%));
|
||||
@include dark-mode {
|
||||
color: var(--palette-gray-8);
|
||||
background-color: color-mod(var(--palette-gray-6) a(50%));
|
||||
}
|
||||
}
|
||||
}
|
||||
&.variant-fill {
|
||||
background-color: var(--color-#{$color});
|
||||
&[disabled] {
|
||||
color: var(--palette-gray-4);
|
||||
background-color: var(--palette-gray-6);
|
||||
@include dark-mode {
|
||||
color: var(--palette-gray-8);
|
||||
background-color: var(--palette-gray-6);
|
||||
}
|
||||
}
|
||||
}
|
||||
&:hover {
|
||||
color: var(--palette-white-0);
|
||||
&.variant-transparent,
|
||||
&.variant-subtle,
|
||||
&.variant-fill {
|
||||
background-color: var(--color-#{$color}-hover);
|
||||
}
|
||||
}
|
||||
&:active {
|
||||
color: var(--palette-white-2);
|
||||
&.variant-transparent {
|
||||
color: var(--color-#{$color}-active);
|
||||
background-color: transparent;
|
||||
}
|
||||
&.variant-subtle {
|
||||
background-color: color-mod(var(--color-#{$color}-active) a(50%));
|
||||
}
|
||||
&.variant-fill {
|
||||
background-color: var(--color-#{$color}-active);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
&[disabled] {
|
||||
border: none;
|
||||
background: none;
|
||||
pointer-events: none;
|
||||
}
|
||||
}
|
|
@ -1,6 +1,6 @@
|
|||
import { A } from "@solidjs/router";
|
||||
import { defaultTo, isNil, pick, pipe, prop } from "ramda";
|
||||
import { Show } from "solid-js";
|
||||
import { Show, mergeProps } from "solid-js";
|
||||
import classes from "./ActivatableLink.module.css";
|
||||
|
||||
/**
|
||||
|
@ -24,17 +24,21 @@ const defaultActivatable = pipe(defaultTo(true), prop("activatable"));
|
|||
* @returns {import("solid-js").Component<ActivatableLinkProps>}
|
||||
*/
|
||||
export default function ActivatableLink(props) {
|
||||
const mergedProps = mergeProps(
|
||||
{ activatable: true, leftIcon: null, rightIcon: null },
|
||||
props
|
||||
);
|
||||
return (
|
||||
<A
|
||||
class={prop("activatable-link", classes)}
|
||||
{...(defaultActivatable(props) && {
|
||||
{...(prop("activatable", mergedProps) && {
|
||||
activeClass: "activated",
|
||||
})}
|
||||
{...pick(["replace", "end", "href"], props)}
|
||||
{...pick(["replace", "end", "href"], mergedProps)}
|
||||
>
|
||||
<Show when={!isNil(props.leftIcon)}>{props.leftIcon}</Show>
|
||||
<Show when={!isNil(props.children)}>{props.children}</Show>
|
||||
<Show when={!isNil(props.rightIcon)}>{props.rightIcon}</Show>
|
||||
<Show when={!isNil(mergedProps.leftIcon)}>{mergedProps.leftIcon}</Show>
|
||||
<Show when={!isNil(mergedProps.children)}>{mergedProps.children}</Show>
|
||||
<Show when={!isNil(mergedProps.rightIcon)}>{mergedProps.rightIcon}</Show>
|
||||
</A>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import { prop } from "ramda";
|
||||
import classes from "./Spacer.module.css";
|
||||
|
||||
export default function Spacer() {
|
||||
return <div class={classes.Spacer}></div>;
|
||||
return <div class={prop("spacer", classes)}></div>;
|
||||
}
|
||||
|
|
39
src/layout/ContentLayout.jsx
Normal file
39
src/layout/ContentLayout.jsx
Normal file
|
@ -0,0 +1,39 @@
|
|||
import ActionIcon from "@/components/ActionIcon/ActionIcon";
|
||||
import { useNavigate } from "@solidjs/router";
|
||||
import { IconX } from "@tabler/icons-solidjs";
|
||||
import { prop } from "ramda";
|
||||
import { children, mergeProps } from "solid-js";
|
||||
import classes from "./ContentLayout.module.css";
|
||||
|
||||
/**
|
||||
* @typedef {Object} ContentLayoutProps
|
||||
* @property {boolean} [disableClose]
|
||||
* @property {JSX.Element} [title]
|
||||
*/
|
||||
|
||||
/**
|
||||
* @param {import("solid-js").ParentProps<ContentLayoutProps>} props
|
||||
*/
|
||||
export default function ContentLayout(props) {
|
||||
const mergedProps = mergeProps({ disableClose: false, title: "" }, props);
|
||||
const childContent = children(() => props.children);
|
||||
const navigate = useNavigate();
|
||||
|
||||
return (
|
||||
<div class={prop("content-layout", classes)}>
|
||||
<section class={prop("title", classes)}>
|
||||
<div class={prop("title-content", classes)}>{mergedProps.title}</div>
|
||||
<ActionIcon
|
||||
size="s"
|
||||
color="secondary"
|
||||
variant="transparent"
|
||||
disabled={mergedProps.disableClose}
|
||||
onClick={() => navigate("/", { replace: true })}
|
||||
>
|
||||
<IconX stroke="1.5" />
|
||||
</ActionIcon>
|
||||
</section>
|
||||
<section>{childContent()}</section>
|
||||
</div>
|
||||
);
|
||||
}
|
22
src/layout/ContentLayout.module.css
Normal file
22
src/layout/ContentLayout.module.css
Normal file
|
@ -0,0 +1,22 @@
|
|||
@import "@/mixins.css";
|
||||
|
||||
.content-layout {
|
||||
@util size(100%, 100%);
|
||||
@include flex(column, flex-start, stretch);
|
||||
z-index: 100;
|
||||
.title {
|
||||
@util size(100%, 32px);
|
||||
@util padding(var(--spacing-xs) var(--spacing-sm));
|
||||
@include flex(row, flex-start, center, --spacing-xs);
|
||||
@util border-bottom-radius(0px);
|
||||
.title-content {
|
||||
flex-grow: 1;
|
||||
font-size: var(--font-size-s);
|
||||
}
|
||||
}
|
||||
.content {
|
||||
@util size(100%);
|
||||
flex: 1;
|
||||
overflow: hidden;
|
||||
}
|
||||
}
|
|
@ -1,10 +1,14 @@
|
|||
import ActionIcon from "@/components/ActionIcon/ActionIcon";
|
||||
import ActivatableLink from "@/components/ActivatableLink/ActivatableLink";
|
||||
import Divider from "@/components/Divider/Divider";
|
||||
import Spacer from "@/components/Spacer/Spacer";
|
||||
import {
|
||||
IconBrandGithub,
|
||||
IconDna2,
|
||||
IconFileExport,
|
||||
IconFileImport,
|
||||
IconFolderOpen,
|
||||
IconHelp,
|
||||
IconKeyboard,
|
||||
IconListSearch,
|
||||
IconTextPlus,
|
||||
|
@ -39,6 +43,15 @@ export default function NavigationSection() {
|
|||
<ActivatableLink href="/" leftIcon={<IconKeyboard stroke="1.5" />}>
|
||||
码表配置
|
||||
</ActivatableLink>
|
||||
<Spacer />
|
||||
<div class={prop("footer", classes)}>
|
||||
<ActionIcon size="m" color="primary" variant="transparent">
|
||||
<IconBrandGithub stroke="1.5" />
|
||||
</ActionIcon>
|
||||
<ActionIcon size="m" color="secondary" variant="transparent">
|
||||
<IconHelp stroke="1.5" />
|
||||
</ActionIcon>
|
||||
</div>
|
||||
</aside>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -9,4 +9,8 @@
|
|||
.library-name {
|
||||
font-size: var(--font-size-xs);
|
||||
}
|
||||
.footer {
|
||||
width: 100%;
|
||||
@include flex(row, flex-start, center);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,7 +8,28 @@
|
|||
line-height: 1.5;
|
||||
|
||||
--color-primary: var(--palette-bright-blue-6);
|
||||
--color-danger: var(--palette-tomato-6);
|
||||
--color-primary-hover: var(--palette-bright-blue-3);
|
||||
--color-primary-active: var(--palette-bright-blue-4);
|
||||
|
||||
--color-secondary: var(--palette-gray-6);
|
||||
--color-secondary-hover: var(--palette-gray-3);
|
||||
--color-secondary-active: var(--palette-gray-4);
|
||||
|
||||
--color-danger: var(--palette-red-6);
|
||||
--color-danger-hover: var(--palette-red-3);
|
||||
--color-danger-active: var(--palette-red-4);
|
||||
|
||||
--color-warn: var(--palette-orange-6);
|
||||
--color-warn-hover: var(--palette-orange-3);
|
||||
--color-warn-active: var(--palette-orange-4);
|
||||
|
||||
--color-success: var(--palette-green-6);
|
||||
--color-success-hover: var(--palette-green-3);
|
||||
--color-success-active: var(--palette-green-4);
|
||||
|
||||
--color-info: var(--palette-blue-6);
|
||||
--color-info-hover: var(--palette-blue-3);
|
||||
--color-info-active: var(--palette-blue-4);
|
||||
|
||||
color: var(--color-light-fg);
|
||||
background-color: var(--color-light-bg);
|
||||
|
|
Loading…
Reference in New Issue
Block a user