diff --git a/src/app/animations.css b/src/app/animations.css new file mode 100644 index 0000000..f10fc5e --- /dev/null +++ b/src/app/animations.css @@ -0,0 +1,24 @@ +.underscore-anim { + position: relative; +} + +.underscore-anim::after { + content: ""; + position: absolute; + left: 0; + bottom: -0.1rem; + height: 2px; + width: 100%; + display: block; + box-sizing: border-box; + border-radius: 100px; + @apply bg-black; + transition: 200ms transform, 0ms transform-origin ease-in; + transform: scaleX(0); + transform-origin: bottom right; +} + +.underscore-anim:hover::after { + transform: scaleX(1); + transform-origin: bottom left; +} \ No newline at end of file diff --git a/src/app/globals.css b/src/app/globals.css index 59f91d3..033697a 100644 --- a/src/app/globals.css +++ b/src/app/globals.css @@ -1,3 +1,5 @@ +@import "./animations.css"; + @tailwind base; @tailwind components; @tailwind utilities; @@ -34,6 +36,9 @@ body { --chart-4: 43 74% 66%; --chart-5: 27 87% 67%; --radius: 0.5rem; + + --gradient-green: #58c473; + --gradient-blue: #049bad; } .dark { --background: 20 14.3% 4.1%; diff --git a/src/app/posts-fb/components/share-button.tsx b/src/app/posts-fb/components/share-button.tsx index 5d2a390..22b020a 100644 --- a/src/app/posts-fb/components/share-button.tsx +++ b/src/app/posts-fb/components/share-button.tsx @@ -3,7 +3,7 @@ import { ClipboardCheckIcon, Share2Icon } from "lucide-react"; import { useState } from "react"; -import { Button } from "@/components/ui/button"; +import { Button } from "@/components/button"; export function ShareButton({ link }: { link: string }) { const [clicked, setClicked] = useState(false); diff --git a/src/components/button.tsx b/src/components/button.tsx new file mode 100644 index 0000000..0c3a0a1 --- /dev/null +++ b/src/components/button.tsx @@ -0,0 +1,124 @@ +"use client"; + +import { Slot } from "@radix-ui/react-slot"; +import { type VariantProps, cva } from "class-variance-authority"; +import { ArrowRight } from "lucide-react"; +import * as React from "react"; + +import { cn } from "@/lib/utils"; + +const buttonVariants = cva( + "relative overflow-hidden inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-full border text-[14px] md:text-[16px] font-semibold ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0", + { + variants: { + variant: { + default: "text-foreground", + secondary: "", + gradient: "", + destructive: + "bg-destructive text-destructive-foreground hover:bg-destructive/90", + ghost: + "border-0 bg-slate-500/0 transition-colors hover:bg-slate-500/10", + link: "border-0 !py-1 !px-2", + }, + color: { + default: "border-black", + black: "border-black", + white: "!border-white", + }, + size: { + default: "px-6 py-3 md:px-8 md:py-3", + sm: "px-5 py-1 !text-[14px]", + lg: "px-12 py-5", + icon: "h-12 w-12", + }, + }, + defaultVariants: { + variant: "default", + size: "default", + color: "default", + }, + }, +); + +export interface ButtonProps + extends React.ButtonHTMLAttributes, + VariantProps { + asChild?: boolean; +} + +const Button = React.forwardRef( + ( + { + children, + className, + variant = "default", + size, + color = "black", + asChild = false, + ...props + }, + ref, + ) => { + const Comp = asChild ? Slot : "button"; + + return ( + +
+ + {children} + + + {(variant === "gradient" || variant === "secondary") && ( +
+
+
+ +
+
+ )} +
+ + ); + }, +); +Button.displayName = "Button"; + +export { Button, buttonVariants }; diff --git a/src/components/homepage-header.tsx b/src/components/homepage-header.tsx index 0928eaf..7f681f7 100644 --- a/src/components/homepage-header.tsx +++ b/src/components/homepage-header.tsx @@ -1,6 +1,6 @@ export function HomepageHeader({ children }: { children: React.ReactNode }) { return ( -

+

{children}

); diff --git a/src/components/horizontal-rule.tsx b/src/components/horizontal-rule.tsx index f396feb..b31547b 100644 --- a/src/components/horizontal-rule.tsx +++ b/src/components/horizontal-rule.tsx @@ -1,3 +1,3 @@ export function HorizontalRule() { - return
; + return
; } diff --git a/src/components/latest-news/post-preview.tsx b/src/components/latest-news/post-preview.tsx index 7154b40..b018318 100644 --- a/src/components/latest-news/post-preview.tsx +++ b/src/components/latest-news/post-preview.tsx @@ -6,7 +6,7 @@ import { useState } from "react"; import type { FacebookPost } from "@/lib/types"; -import { Button } from "../ui/button"; +import { Button } from "../button"; export function PostPreview({ post }: { post: FacebookPost }) { const date = format(post.updated_time, "dd MMMM yyyy", { locale: pl }); @@ -34,8 +34,8 @@ export function PostPreview({ post }: { post: FacebookPost }) {

diff --git a/src/components/no-data-info.tsx b/src/components/no-data-info.tsx index ece5456..e4d5065 100644 --- a/src/components/no-data-info.tsx +++ b/src/components/no-data-info.tsx @@ -2,7 +2,7 @@ import type { NoDataInfoProps } from "@/lib/types"; -import { Button } from "./ui/button"; +import { Button } from "./button"; const handleReload = () => { window.location.reload(); @@ -12,14 +12,8 @@ function NoDataInfo({ errorTitle, errorMessage }: NoDataInfoProps) { return (

{errorTitle}

-

{errorMessage}

- +

{errorMessage}

+
); } diff --git a/src/components/static-map.tsx b/src/components/static-map.tsx index 291425a..9fc70e0 100644 --- a/src/components/static-map.tsx +++ b/src/components/static-map.tsx @@ -3,7 +3,7 @@ import { useState } from "react"; import { cn } from "@/lib/utils"; -import { Button } from "./ui/button"; +import { Button } from "./button"; export function StaticMap() { const [outside, setOutside] = useState(true); diff --git a/src/components/ui/button.tsx b/src/components/ui/button.tsx deleted file mode 100644 index 56cbbe3..0000000 --- a/src/components/ui/button.tsx +++ /dev/null @@ -1,57 +0,0 @@ -import { Slot } from "@radix-ui/react-slot"; -import { cva } from "class-variance-authority"; -import type { VariantProps } from "class-variance-authority"; -import * as React from "react"; - -import { cn } from "@/lib/utils"; - -const buttonVariants = cva( - "inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0", - { - variants: { - variant: { - default: "bg-primary text-primary-foreground hover:bg-primary/90", - destructive: - "bg-destructive text-destructive-foreground hover:bg-destructive/90", - outline: - "border border-input bg-background hover:bg-accent hover:text-accent-foreground", - secondary: - "bg-secondary text-secondary-foreground hover:bg-secondary/80", - ghost: "hover:bg-accent hover:text-accent-foreground", - link: "text-primary underline-offset-4 hover:underline", - }, - size: { - default: "h-10 px-4 py-2", - sm: "h-9 rounded-md px-3", - lg: "h-11 rounded-md px-8", - icon: "h-10 w-10", - }, - }, - defaultVariants: { - variant: "default", - size: "default", - }, - }, -); - -export interface ButtonProps - extends React.ButtonHTMLAttributes, - VariantProps { - asChild?: boolean; -} - -const Button = React.forwardRef( - ({ className, variant, size, asChild = false, ...props }, ref) => { - const Comp = asChild ? Slot : "button"; - return ( - - ); - }, -); -Button.displayName = "Button"; - -export { Button, buttonVariants }; diff --git a/tailwind.config.ts b/tailwind.config.ts index cb6a5d8..92fc673 100644 --- a/tailwind.config.ts +++ b/tailwind.config.ts @@ -11,6 +11,10 @@ export default { ], theme: { extend: { + backgroundImage: { + "gradient-green-blue": + "radial-gradient(94.87% 94.87% at 90% 70%, hsl(var(--primary)) 0%, hsl(var(--secondary)) 100%)", + }, fontFamily: { sans: ["var(--font-montserrat)", "sans-serif"], }, @@ -61,18 +65,15 @@ export default { md: "calc(var(--radius) - 2px)", sm: "calc(var(--radius) - 4px)", }, - backgroundImage: { - "gradient-main": - "radial-gradient(circle at top left, hsl(var(--primary)), hsl(var(--secondary)))", - "gradient-secondary": - "radial-gradient(circle at bottom right, hsl(var(--primary)), hsl(var(--secondary)))", - }, - spacing: { - "90": "22rem", + keyframes: { + "bouncy-arrow-reveal": { + "0%": { transform: "scale3d(0,0,1) rotate(45deg)" }, + "100%": { transform: "scaleX(1) rotate(0deg)" }, + }, }, - gridTemplateRows: { - "animate-height-open": "1fr", - "animate-height-closed": "0fr", + animation: { + "reveal-arrow": + "bouncy-arrow-reveal 0.17s cubic-bezier(.2, 1.2, .3, 1.4) forwards", }, }, },