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 { A } from "@solidjs/router";
|
||||||
import { defaultTo, isNil, pick, pipe, prop } from "ramda";
|
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";
|
import classes from "./ActivatableLink.module.css";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -24,17 +24,21 @@ const defaultActivatable = pipe(defaultTo(true), prop("activatable"));
|
||||||
* @returns {import("solid-js").Component<ActivatableLinkProps>}
|
* @returns {import("solid-js").Component<ActivatableLinkProps>}
|
||||||
*/
|
*/
|
||||||
export default function ActivatableLink(props) {
|
export default function ActivatableLink(props) {
|
||||||
|
const mergedProps = mergeProps(
|
||||||
|
{ activatable: true, leftIcon: null, rightIcon: null },
|
||||||
|
props
|
||||||
|
);
|
||||||
return (
|
return (
|
||||||
<A
|
<A
|
||||||
class={prop("activatable-link", classes)}
|
class={prop("activatable-link", classes)}
|
||||||
{...(defaultActivatable(props) && {
|
{...(prop("activatable", mergedProps) && {
|
||||||
activeClass: "activated",
|
activeClass: "activated",
|
||||||
})}
|
})}
|
||||||
{...pick(["replace", "end", "href"], props)}
|
{...pick(["replace", "end", "href"], mergedProps)}
|
||||||
>
|
>
|
||||||
<Show when={!isNil(props.leftIcon)}>{props.leftIcon}</Show>
|
<Show when={!isNil(mergedProps.leftIcon)}>{mergedProps.leftIcon}</Show>
|
||||||
<Show when={!isNil(props.children)}>{props.children}</Show>
|
<Show when={!isNil(mergedProps.children)}>{mergedProps.children}</Show>
|
||||||
<Show when={!isNil(props.rightIcon)}>{props.rightIcon}</Show>
|
<Show when={!isNil(mergedProps.rightIcon)}>{mergedProps.rightIcon}</Show>
|
||||||
</A>
|
</A>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
|
import { prop } from "ramda";
|
||||||
import classes from "./Spacer.module.css";
|
import classes from "./Spacer.module.css";
|
||||||
|
|
||||||
export default function Spacer() {
|
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 ActivatableLink from "@/components/ActivatableLink/ActivatableLink";
|
||||||
import Divider from "@/components/Divider/Divider";
|
import Divider from "@/components/Divider/Divider";
|
||||||
|
import Spacer from "@/components/Spacer/Spacer";
|
||||||
import {
|
import {
|
||||||
|
IconBrandGithub,
|
||||||
IconDna2,
|
IconDna2,
|
||||||
IconFileExport,
|
IconFileExport,
|
||||||
IconFileImport,
|
IconFileImport,
|
||||||
IconFolderOpen,
|
IconFolderOpen,
|
||||||
|
IconHelp,
|
||||||
IconKeyboard,
|
IconKeyboard,
|
||||||
IconListSearch,
|
IconListSearch,
|
||||||
IconTextPlus,
|
IconTextPlus,
|
||||||
|
@ -39,6 +43,15 @@ export default function NavigationSection() {
|
||||||
<ActivatableLink href="/" leftIcon={<IconKeyboard stroke="1.5" />}>
|
<ActivatableLink href="/" leftIcon={<IconKeyboard stroke="1.5" />}>
|
||||||
码表配置
|
码表配置
|
||||||
</ActivatableLink>
|
</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>
|
</aside>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,4 +9,8 @@
|
||||||
.library-name {
|
.library-name {
|
||||||
font-size: var(--font-size-xs);
|
font-size: var(--font-size-xs);
|
||||||
}
|
}
|
||||||
|
.footer {
|
||||||
|
width: 100%;
|
||||||
|
@include flex(row, flex-start, center);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,7 +8,28 @@
|
||||||
line-height: 1.5;
|
line-height: 1.5;
|
||||||
|
|
||||||
--color-primary: var(--palette-bright-blue-6);
|
--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);
|
color: var(--color-light-fg);
|
||||||
background-color: var(--color-light-bg);
|
background-color: var(--color-light-bg);
|
||||||
|
|
Loading…
Reference in New Issue
Block a user