mirror of
https://github.com/jeffvli/feishin.git
synced 2026-05-08 13:00:13 +02:00
Refactor add to playlist modal (#1236)
* Refactor add to playlist modal * redesign base modal component, add ModalButton component * improve visibility of filled button focus --------- Co-authored-by: jeffvli <jeffvictorli@gmail.com>
This commit is contained in:
@@ -47,6 +47,11 @@
|
||||
&:focus-visible {
|
||||
background: darken(var(--theme-colors-primary-filled), 10%);
|
||||
}
|
||||
|
||||
&:focus-visible {
|
||||
outline: 1px solid var(--theme-colors-primary-filled);
|
||||
outline-offset: 2px;
|
||||
}
|
||||
}
|
||||
|
||||
&[data-variant='state-error'] {
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import clsx from 'clsx';
|
||||
import { MotionConfigProps } from 'motion/react';
|
||||
import { ForwardedRef, forwardRef, type ImgHTMLAttributes } from 'react';
|
||||
import { ForwardedRef, forwardRef, HTMLAttributes, type ImgHTMLAttributes, ReactNode } from 'react';
|
||||
import { Img } from 'react-image';
|
||||
|
||||
import styles from './image.module.css';
|
||||
@@ -9,9 +8,8 @@ import { Icon } from '/@/shared/components/icon/icon';
|
||||
import { Skeleton } from '/@/shared/components/skeleton/skeleton';
|
||||
import { useInViewport } from '/@/shared/hooks/use-in-viewport';
|
||||
|
||||
interface ImageContainerProps extends MotionConfigProps {
|
||||
children: React.ReactNode;
|
||||
className?: string;
|
||||
interface ImageContainerProps extends HTMLAttributes<HTMLDivElement> {
|
||||
children: ReactNode;
|
||||
enableAnimation?: boolean;
|
||||
}
|
||||
|
||||
@@ -44,6 +42,7 @@ export function Image({
|
||||
includeLoader = true,
|
||||
includeUnloader = true,
|
||||
src,
|
||||
...props
|
||||
}: ImageProps) {
|
||||
const { inViewport, ref } = useInViewport();
|
||||
|
||||
@@ -78,6 +77,7 @@ export function Image({
|
||||
</ImageContainer>
|
||||
) : null
|
||||
}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,17 +1,26 @@
|
||||
.title {
|
||||
font-size: var(--theme-font-size-lg);
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.body {
|
||||
padding: var(--theme-spacing-sm) var(--theme-spacing-md);
|
||||
}
|
||||
|
||||
.header {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
padding: none;
|
||||
background: var(--theme-colors-background);
|
||||
border-bottom: none;
|
||||
border-radius: 0;
|
||||
}
|
||||
|
||||
.header h2 {
|
||||
width: 100%;
|
||||
font-size: var(--theme-font-size-2xl);
|
||||
font-weight: 700;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
.content {
|
||||
overflow: hidden;
|
||||
background: var(--theme-colors-background);
|
||||
border: 2px solid var(--theme-colors-border);
|
||||
}
|
||||
|
||||
.close {
|
||||
position: absolute;
|
||||
top: var(--theme-spacing-md);
|
||||
right: var(--theme-spacing-md);
|
||||
}
|
||||
|
||||
@@ -12,6 +12,7 @@ import { Button } from '/@/shared/components/button/button';
|
||||
import { Flex } from '/@/shared/components/flex/flex';
|
||||
import { Group } from '/@/shared/components/group/group';
|
||||
import { Icon } from '/@/shared/components/icon/icon';
|
||||
import { ScrollArea } from '/@/shared/components/scroll-area/scroll-area';
|
||||
import { Stack } from '/@/shared/components/stack/stack';
|
||||
|
||||
export interface ModalProps extends Omit<MantineModalProps, 'onClose'> {
|
||||
@@ -113,15 +114,23 @@ export const ModalsProvider = ({ children, ...rest }: ModalsProviderProps) => {
|
||||
centered: true,
|
||||
classNames: {
|
||||
body: styles.body,
|
||||
close: styles.close,
|
||||
content: styles.content,
|
||||
header: styles.header,
|
||||
inner: styles.inner,
|
||||
overlay: styles.overlay,
|
||||
root: styles.root,
|
||||
title: styles.title,
|
||||
},
|
||||
closeButtonProps: {
|
||||
icon: <Icon icon="x" />,
|
||||
icon: <Icon icon="x" size="xl" />,
|
||||
},
|
||||
radius: 'lg',
|
||||
overlayProps: {
|
||||
backgroundOpacity: 0.8,
|
||||
blur: 4,
|
||||
},
|
||||
radius: 'xl',
|
||||
scrollAreaComponent: ScrollArea,
|
||||
transitionProps: {
|
||||
duration: 300,
|
||||
exitDuration: 300,
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
import { Button, ButtonProps } from '/@/shared/components/button/button';
|
||||
|
||||
export const ModalButton = ({ children, ...props }: ButtonProps) => {
|
||||
return (
|
||||
<Button px="2xl" uppercase variant="subtle" {...props}>
|
||||
{children}
|
||||
</Button>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,32 @@
|
||||
.label {
|
||||
font-family: var(--theme-content-font-family);
|
||||
}
|
||||
|
||||
.label.sm {
|
||||
font-size: var(--theme-font-size-sm);
|
||||
}
|
||||
|
||||
.label.md {
|
||||
font-size: var(--theme-font-size-md);
|
||||
}
|
||||
|
||||
.label.lg {
|
||||
font-size: var(--theme-font-size-lg);
|
||||
}
|
||||
|
||||
.label.xl {
|
||||
font-size: var(--theme-font-size-xl);
|
||||
}
|
||||
|
||||
.label.xs {
|
||||
font-size: var(--theme-font-size-xs);
|
||||
}
|
||||
|
||||
|
||||
.remove {
|
||||
transition: color 0.1s ease-in-out;
|
||||
|
||||
&:hover {
|
||||
color: var(--theme-colors-foreground-muted);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
import { Pill as MantinePill, PillProps as MantinePillProps } from '@mantine/core';
|
||||
import clsx from 'clsx';
|
||||
|
||||
import styles from './pill.module.css';
|
||||
|
||||
export const Pill = ({ children, size = 'md', ...props }: MantinePillProps) => {
|
||||
return (
|
||||
<MantinePill
|
||||
classNames={{
|
||||
label: clsx({
|
||||
[styles.label]: true,
|
||||
[styles.lg]: size === 'lg',
|
||||
[styles.md]: size === 'md',
|
||||
[styles.sm]: size === 'sm',
|
||||
[styles.xl]: size === 'xl',
|
||||
[styles.xs]: size === 'xs',
|
||||
}),
|
||||
remove: styles.remove,
|
||||
root: styles.root,
|
||||
}}
|
||||
size="md"
|
||||
{...props}
|
||||
>
|
||||
{children}
|
||||
</MantinePill>
|
||||
);
|
||||
};
|
||||
|
||||
Pill.Group = MantinePill.Group;
|
||||
Reference in New Issue
Block a user