feat: add dialog
This commit is contained in:
committed by
Mathias Schopmans
parent
86c1d9090b
commit
38a59b029b
98
src/components/Dialog/Dialog.module.css
Normal file
98
src/components/Dialog/Dialog.module.css
Normal file
@@ -0,0 +1,98 @@
|
||||
.overlay {
|
||||
background: var(--overlay);
|
||||
position: fixed;
|
||||
inset: 0;
|
||||
backdrop-filter: blur(2px);
|
||||
animation: overlayShow 300ms cubic-bezier(0.16, 1, 0.3, 1);
|
||||
|
||||
&[data-state="closed"] {
|
||||
animation: overlayHide 300ms cubic-bezier(0.16, 1, 0.3, 1);
|
||||
}
|
||||
}
|
||||
|
||||
.content {
|
||||
background-color: var(--dialog-bg);
|
||||
border-radius: 6px;
|
||||
box-shadow:
|
||||
rgba(0, 0, 0, 0.2) 0px 10px 38px -10px,
|
||||
rgba(0, 0, 0, 0.2) 0px 10px 20px -15px;
|
||||
position: fixed;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
width: 90vw;
|
||||
max-width: 450px;
|
||||
max-height: 85vh;
|
||||
padding: 25px;
|
||||
animation: contentShow 150ms cubic-bezier(0.16, 1, 0.3, 1);
|
||||
|
||||
&[data-state="closed"] {
|
||||
animation: contentHide 150ms cubic-bezier(0.16, 1, 0.3, 1);
|
||||
}
|
||||
}
|
||||
|
||||
.content:focus {
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.close {
|
||||
position: absolute;
|
||||
top: 22px;
|
||||
right: 22px;
|
||||
width: 22px;
|
||||
height: 22px;
|
||||
cursor: pointer;
|
||||
background: none;
|
||||
border: none;
|
||||
}
|
||||
|
||||
.title {
|
||||
margin: 0;
|
||||
font-size: 17px;
|
||||
}
|
||||
|
||||
.description {
|
||||
margin: 10px 0 20px;
|
||||
font-size: 15px;
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
@keyframes overlayShow {
|
||||
from {
|
||||
opacity: 0;
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes overlayHide {
|
||||
from {
|
||||
opacity: 1;
|
||||
}
|
||||
to {
|
||||
opacity: 0;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes contentShow {
|
||||
from {
|
||||
opacity: 0;
|
||||
transform: translate(-50%, -40%) scale(0.9);
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
transform: translate(-50%, -50%) scale(1);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes contentHide {
|
||||
from {
|
||||
opacity: 1;
|
||||
transform: translate(-50%, -50%) scale(1);
|
||||
}
|
||||
to {
|
||||
opacity: 0;
|
||||
transform: translate(-50%, -40%) scale(0.9);
|
||||
}
|
||||
}
|
||||
102
src/components/Dialog/Dialog.tsx
Normal file
102
src/components/Dialog/Dialog.tsx
Normal file
@@ -0,0 +1,102 @@
|
||||
import {
|
||||
ComponentPropsWithoutRef,
|
||||
ElementRef,
|
||||
HTMLAttributes,
|
||||
forwardRef,
|
||||
} from "react";
|
||||
|
||||
import styles from "./Dialog.module.css";
|
||||
|
||||
import Close from "@/components/Icons/Close";
|
||||
import { cn } from "@/lib/utils";
|
||||
import * as DialogPrimitive from "@radix-ui/react-dialog";
|
||||
|
||||
const Dialog = DialogPrimitive.Root;
|
||||
const DialogTrigger = DialogPrimitive.Trigger;
|
||||
const DialogPortal = DialogPrimitive.Portal;
|
||||
const DialogClose = DialogPrimitive.Close;
|
||||
|
||||
const DialogOverlay = forwardRef<
|
||||
ElementRef<typeof DialogPrimitive.Overlay>,
|
||||
ComponentPropsWithoutRef<typeof DialogPrimitive.Overlay>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<DialogPrimitive.Overlay
|
||||
ref={ref}
|
||||
className={cn(styles.overlay, className)}
|
||||
{...props}
|
||||
/>
|
||||
));
|
||||
DialogOverlay.displayName = DialogPrimitive.Overlay.displayName;
|
||||
|
||||
const DialogContent = forwardRef<
|
||||
ElementRef<typeof DialogPrimitive.Content>,
|
||||
ComponentPropsWithoutRef<typeof DialogPrimitive.Content>
|
||||
>(({ className, children, ...props }, ref) => (
|
||||
<DialogPortal
|
||||
container={
|
||||
typeof document != "undefined"
|
||||
? document.getElementById("layout")
|
||||
: undefined
|
||||
}
|
||||
>
|
||||
<DialogOverlay />
|
||||
<DialogPrimitive.Content
|
||||
ref={ref}
|
||||
className={cn(styles.content, className)}
|
||||
{...props}
|
||||
>
|
||||
{children}
|
||||
<DialogPrimitive.Close asChild>
|
||||
<button type="button" className={styles.close} aria-label="Close">
|
||||
<Close />
|
||||
</button>
|
||||
</DialogPrimitive.Close>
|
||||
</DialogPrimitive.Content>
|
||||
</DialogPortal>
|
||||
));
|
||||
DialogContent.displayName = DialogPrimitive.Content.displayName;
|
||||
|
||||
const DialogHeader = ({
|
||||
className,
|
||||
...props
|
||||
}: HTMLAttributes<HTMLDivElement>) => (
|
||||
<div className={cn(className)} {...props} />
|
||||
);
|
||||
DialogHeader.displayName = "DialogHeader";
|
||||
|
||||
const DialogFooter = ({
|
||||
className,
|
||||
...props
|
||||
}: HTMLAttributes<HTMLDivElement>) => (
|
||||
<div className={cn(className)} {...props} />
|
||||
);
|
||||
DialogFooter.displayName = "DialogFooter";
|
||||
|
||||
const DialogTitle = forwardRef<
|
||||
ElementRef<typeof DialogPrimitive.Title>,
|
||||
ComponentPropsWithoutRef<typeof DialogPrimitive.Title>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<DialogPrimitive.Title ref={ref} className={cn(className)} {...props} />
|
||||
));
|
||||
DialogTitle.displayName = DialogPrimitive.Title.displayName;
|
||||
|
||||
const DialogDescription = forwardRef<
|
||||
ElementRef<typeof DialogPrimitive.Description>,
|
||||
ComponentPropsWithoutRef<typeof DialogPrimitive.Description>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<DialogPrimitive.Description ref={ref} className={cn(className)} {...props} />
|
||||
));
|
||||
DialogDescription.displayName = DialogPrimitive.Description.displayName;
|
||||
|
||||
export {
|
||||
Dialog,
|
||||
DialogPortal,
|
||||
DialogOverlay,
|
||||
DialogClose,
|
||||
DialogTrigger,
|
||||
DialogContent,
|
||||
DialogHeader,
|
||||
DialogFooter,
|
||||
DialogTitle,
|
||||
DialogDescription,
|
||||
};
|
||||
@@ -22,7 +22,10 @@ export const Layout: FC<LayoutProps> = ({
|
||||
layoutClass = "default",
|
||||
}) => {
|
||||
return (
|
||||
<div className={cn(styles.layout, font.className, styles[layoutClass])}>
|
||||
<div
|
||||
id="layout"
|
||||
className={cn(styles.layout, font.className, styles[layoutClass])}
|
||||
>
|
||||
<header className={cn(styles.container, styles.header)}>
|
||||
<Logo />
|
||||
<Navigation />
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
display: inline-block;
|
||||
vertical-align: middle;
|
||||
width: 22px;
|
||||
margin: 0 10px 0 0;
|
||||
margin: 0 6px 0 0;
|
||||
}
|
||||
|
||||
@media (max-width: 900px) {
|
||||
|
||||
@@ -1,7 +1,17 @@
|
||||
import Link from "next/link";
|
||||
import { useRouter } from "next/router";
|
||||
|
||||
import styles from "./Navigation.module.css";
|
||||
|
||||
import {
|
||||
Dialog,
|
||||
DialogContent,
|
||||
DialogDescription,
|
||||
DialogFooter,
|
||||
DialogHeader,
|
||||
DialogTitle,
|
||||
DialogTrigger,
|
||||
} from "@/components/Dialog/Dialog";
|
||||
import IconFilter from "@/components/Icons/Filter";
|
||||
import IconOverview from "@/components/Icons/Overview";
|
||||
import IconQuestion from "@/components/Icons/Question";
|
||||
@@ -19,8 +29,19 @@ export function Navigation() {
|
||||
</Link>
|
||||
</li>
|
||||
<li className={styles.item}>
|
||||
<IconFilter className={styles.icon} />
|
||||
<span className={styles.label}>Filter</span>
|
||||
<Dialog>
|
||||
<DialogTrigger asChild>
|
||||
<a href="#">
|
||||
<IconFilter className={styles.icon} />
|
||||
<span className={styles.label}>Filter</span>
|
||||
</a>
|
||||
</DialogTrigger>
|
||||
<DialogContent>
|
||||
<DialogHeader>
|
||||
<DialogTitle>Filter by Tags</DialogTitle>
|
||||
</DialogHeader>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
</li>
|
||||
<li className={styles.item}>
|
||||
<Link href="/overview">
|
||||
|
||||
@@ -9,6 +9,10 @@
|
||||
--background: #173d7a;
|
||||
--highlight: #029df7;
|
||||
--border: rgba(255, 255, 255, 0.1);
|
||||
|
||||
--overlay: #081a37b5;
|
||||
--dialog-bg: #173d7a;
|
||||
|
||||
--badge: #333; /* local color which get's overridden by the element */
|
||||
}
|
||||
|
||||
@@ -25,7 +29,8 @@ html {
|
||||
html,
|
||||
body {
|
||||
max-width: 100vw;
|
||||
overflow-x: hidden;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
body {
|
||||
|
||||
Reference in New Issue
Block a user