From 3bc453601da7c0cfc352c403d438bd1bc9bb4c47 Mon Sep 17 00:00:00 2001
From: Damien Schneider <74979845+damien-schneider@users.noreply.github.com>
Date: Thu, 31 Oct 2024 02:00:01 +0100
Subject: [PATCH] Add-new-bottom-navigation-menu-&-home-page (#50)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
* :sparkles: add new floating dock menu
* :art: improve scrollarea to accept viewport
* :sparkles: display sidemenu corresponding to category selected
* ✅ remove outdated HomePage tests and update Sidemenu tests to include InfoMenuList
* :art: add components to preview only variants
* :sparkles: update dev script to use turbo mode for improved performance
---
apps/website/__tests__/home-h1.test.tsx | 35 ---
apps/website/__tests__/sidemenu.test.tsx | 13 +-
apps/website/package.json | 2 +-
apps/website/src/app/(components)/layout.tsx | 26 +-
.../src/app/floating-docks-component.tsx | 261 ++++++++++++++++++
apps/website/src/app/layout-floating-dock.tsx | 92 ++++++
apps/website/src/app/layout.tsx | 33 +--
apps/website/src/app/page.tsx | 132 +++++----
.../component-tab-renderer.tsx | 25 +-
.../component-wrapper/github-edit-button.tsx | 2 +-
.../main-menus/menu-category-wrapper.tsx | 18 +-
.../components/navigation/desktop-menu.tsx | 12 +-
.../components/navigation/info-menu-list.tsx | 31 +++
.../src/components/navigation/mobile-menu.tsx | 79 ------
.../components/navigation/navigation-item.tsx | 60 +---
.../components/navigation/navigation-menu.tsx | 23 +-
...opy-to-clipboard-code-snippet-dropdown.tsx | 146 +++++-----
apps/website/src/ui/shadcn/scrollarea.tsx | 110 ++++----
.../src/ui/star-github-project-button.tsx | 6 +-
apps/website/src/ui/theme-switcher.tsx | 46 ---
.../battery-indicator/battery-indicator.tsx | 2 +-
.../common-ui/buttons/buttons.category.tsx | 10 +-
...component.shiny-rotating-border-button.tsx | 73 +++++
.../preview.shiny-rotating-border-button.tsx | 5 +
.../shiny-rotating-border-button/variant1.tsx | 62 -----
.../hooks/use-step/preview-use-step.tsx | 4 +-
.../mock-ups/laptops/component.mackbook.tsx | 39 +++
.../mock-ups/laptops/preview.mackbook.tsx | 5 +
.../other/mock-ups/laptops/variant1.tsx | 22 --
.../other/mock-ups/mock-ups.category.tsx | 7 +-
30 files changed, 820 insertions(+), 561 deletions(-)
delete mode 100644 apps/website/__tests__/home-h1.test.tsx
create mode 100644 apps/website/src/app/floating-docks-component.tsx
create mode 100644 apps/website/src/app/layout-floating-dock.tsx
create mode 100644 apps/website/src/components/navigation/info-menu-list.tsx
delete mode 100644 apps/website/src/components/navigation/mobile-menu.tsx
delete mode 100644 apps/website/src/ui/theme-switcher.tsx
create mode 100644 packages/ui/cuicui/common-ui/buttons/shiny-rotating-border-button/component.shiny-rotating-border-button.tsx
create mode 100644 packages/ui/cuicui/common-ui/buttons/shiny-rotating-border-button/preview.shiny-rotating-border-button.tsx
delete mode 100644 packages/ui/cuicui/common-ui/buttons/shiny-rotating-border-button/variant1.tsx
create mode 100644 packages/ui/cuicui/other/mock-ups/laptops/component.mackbook.tsx
create mode 100644 packages/ui/cuicui/other/mock-ups/laptops/preview.mackbook.tsx
delete mode 100644 packages/ui/cuicui/other/mock-ups/laptops/variant1.tsx
diff --git a/apps/website/__tests__/home-h1.test.tsx b/apps/website/__tests__/home-h1.test.tsx
deleted file mode 100644
index 6312b9e..0000000
--- a/apps/website/__tests__/home-h1.test.tsx
+++ /dev/null
@@ -1,35 +0,0 @@
-import { render, screen } from "@testing-library/react";
-import { describe, expect, it } from "vitest";
-import HomePage from "#/src/app/page";
-
-const gettingStartedRegex = /getting-started$/;
-
-describe("Page", () => {
- render();
- it("should have a heading", () => {
- const heading = screen.getByRole("heading", {
- level: 1,
- name: "CuiCui - Copy Paste quality React component",
- });
- expect(heading).toBeDefined();
- });
- it("should have href attribute of the 'Contribute' element set to https://cuicui.featurebase.app/", () => {
- const contributeElement = screen.getByTestId(
- "home-navigation-link-Contribute",
- );
-
- // Check if the href attribute of the 'Contribute' element is https://cuicui.featurebase.app/
- const hrefValue = contributeElement.getAttribute("href");
- expect(hrefValue).toBe("https://cuicui.featurebase.app/");
- });
-
- it("should have href attribute of the 'Getting started' element to finish by getting-started", () => {
- const contributeElement = screen.getByTestId(
- "home-navigation-link-Getting Started",
- );
-
- // Check if the href attribute of the 'Getting started' element finishes by getting-started
- const hrefValue = contributeElement.getAttribute("href");
- expect(hrefValue).toMatch(gettingStartedRegex);
- });
-});
diff --git a/apps/website/__tests__/sidemenu.test.tsx b/apps/website/__tests__/sidemenu.test.tsx
index fef637c..8590a6d 100644
--- a/apps/website/__tests__/sidemenu.test.tsx
+++ b/apps/website/__tests__/sidemenu.test.tsx
@@ -1,16 +1,25 @@
import { render, screen } from "@testing-library/react";
import { describe, expect, it, vi } from "vitest";
import NavigationMenu from "#/src/components/navigation/navigation-menu";
+import InfoMenuList from "#/src/components/navigation/info-menu-list";
const gettingStartedRegex = /getting-started$/;
vi.mock("next/navigation", () => ({
- usePathname: () => [],
+ usePathname: () => {
+ return "/common-ui";
+ },
useSelectedLayoutSegments: () => [],
}));
describe("Sidemenu component", () => {
- render();
+ render(
+
+
+
+
,
+ );
+
it("should have href attribute of the 'Contribute' element set to https://cuicui.featurebase.app/", () => {
const contributeElement = screen.getByTestId("navigation-link-Contribute");
diff --git a/apps/website/package.json b/apps/website/package.json
index fd00cfb..ebcf925 100644
--- a/apps/website/package.json
+++ b/apps/website/package.json
@@ -89,7 +89,7 @@
"publisher": "Damien Schneider",
"scripts": {
"build": "next build",
- "dev": "next dev",
+ "dev": "next dev --turbo",
"start": "next start",
"format:check": "biome format --check ./src",
"format:write": "biome format --write ./src",
diff --git a/apps/website/src/app/(components)/layout.tsx b/apps/website/src/app/(components)/layout.tsx
index 8cf35fe..17d9353 100644
--- a/apps/website/src/app/(components)/layout.tsx
+++ b/apps/website/src/app/(components)/layout.tsx
@@ -1,7 +1,29 @@
+import { DesktopSideMenu } from "#/src/components/navigation/desktop-menu";
+
+import { AddressBar } from "#/src/ui/address-bar";
+import StarGithubProjectButton from "#/src/ui/star-github-project-button";
import type React from "react";
export default function ComponentsLayout({
- children,
+ children,
}: Readonly<{ children: React.ReactNode }>) {
- return {children}
;
+ return (
+
+
+
+
+ {/* Add overflow-auto if layout width problems */}
+
+
+
+
+ {children}
+
+
+
+
+
+
+
+ );
}
diff --git a/apps/website/src/app/floating-docks-component.tsx b/apps/website/src/app/floating-docks-component.tsx
new file mode 100644
index 0000000..2530cd0
--- /dev/null
+++ b/apps/website/src/app/floating-docks-component.tsx
@@ -0,0 +1,261 @@
+"use client";
+import { useOnClickOutside } from "@/cuicui/hooks/use-click-outside/use-click-outside";
+/**
+ * Note: Use position fixed according to your needs
+ * Desktop navbar is better positioned at the bottom
+ * Mobile navbar is better positioned at bottom right.
+ **/
+
+import { cn } from "@/cuicui/utils/cn/cn";
+import {
+ AnimatePresence,
+ type MotionValue,
+ motion,
+ useMotionValue,
+ useSpring,
+ useTransform,
+} from "framer-motion";
+import { ListCollapseIcon, type LucideIcon } from "lucide-react";
+import Link from "next/link";
+import { usePathname } from "next/navigation";
+import { useEffect, useRef, useState } from "react";
+
+export const FloatingDock = ({
+ items,
+ desktopClassName,
+ mobileClassName,
+}: {
+ items: {
+ title: string;
+ Icon: LucideIcon;
+ href: string;
+ }[];
+ desktopClassName?: string;
+ mobileClassName?: string;
+}) => {
+ return (
+ <>
+
+
+ >
+ );
+};
+
+const FloatingDockMobile = ({
+ items,
+ className,
+}: {
+ items: {
+ title: string;
+ Icon: LucideIcon;
+ href: string;
+ }[];
+ className?: string;
+}) => {
+ const ref = useRef(null);
+ const handleClickOutside = (event: MouseEvent | TouchEvent | FocusEvent) => {
+ setOpen(false);
+ };
+
+ const pathname = usePathname();
+
+ useEffect(() => {
+ if (!pathname) {
+ return;
+ }
+ setOpen(false);
+ }, [pathname]);
+
+ useOnClickOutside(ref, handleClickOutside);
+ const [open, setOpen] = useState(false);
+ return (
+
+
+ {open && (
+
+ {items.map((item, idx) => (
+
+ setOpen(false)}
+ >
+
+
+ {item.title}
+
+
+
+ ))}
+
+ )}
+
+
+
+ );
+};
+
+const FloatingDockDesktop = ({
+ items,
+ className,
+}: {
+ items: { title: string; Icon: LucideIcon; href: string }[];
+ className?: string;
+}) => {
+ const mouseX = useMotionValue(Number.POSITIVE_INFINITY);
+ return (
+ mouseX.set(e.pageX)}
+ onMouseLeave={() => mouseX.set(Number.POSITIVE_INFINITY)}
+ className={cn(
+ "mx-auto hidden md:flex h-14 gap-2 items-end rounded-full bg-neutral-50 dark:bg-neutral-900 px-2 pb-2 border border-neutral-500/20",
+ className,
+ )}
+ >
+ {items.map((item) => (
+
+ ))}
+
+ );
+};
+
+function IconContainer({
+ mouseX,
+ title,
+ Icon,
+ href,
+}: Readonly<{
+ mouseX: MotionValue;
+ title: string;
+ Icon: LucideIcon;
+ href: string;
+}>) {
+ const pathname = usePathname();
+ const [isActive, setIsActive] = useState(false);
+
+ useEffect(() => {
+ if (href === "/") {
+ setIsActive(href === pathname);
+ } else {
+ setIsActive(pathname.includes(href));
+ }
+ }, [pathname, href]);
+
+ const ref = useRef(null);
+
+ const distance = useTransform(mouseX, (val) => {
+ const bounds = ref.current?.getBoundingClientRect() ?? { x: 0, width: 0 };
+
+ return val - bounds.x - bounds.width / 2;
+ });
+
+ const widthTransform = useTransform(distance, [-150, 0, 150], [60, 80, 60]);
+ const heightTransform = useTransform(distance, [-150, 0, 150], [40, 60, 40]);
+
+ const widthTransformIcon = useTransform(
+ distance,
+ [-150, 0, 150],
+ [20, 40, 20],
+ );
+ const heightTransformIcon = useTransform(
+ distance,
+ [-150, 0, 150],
+ [20, 40, 20],
+ );
+
+ const width = useSpring(widthTransform, {
+ mass: 0.1,
+ stiffness: 300,
+ damping: 12,
+ });
+ const height = useSpring(heightTransform, {
+ mass: 0.1,
+ stiffness: 300,
+ damping: 12,
+ });
+
+ const widthIcon = useSpring(widthTransformIcon, {
+ mass: 0.1,
+ stiffness: 300,
+ damping: 12,
+ });
+ const heightIcon = useSpring(heightTransformIcon, {
+ mass: 0.1,
+ stiffness: 300,
+ damping: 12,
+ });
+
+ const [hovered, setHovered] = useState(false);
+
+ return (
+
+ setHovered(true)}
+ onMouseLeave={() => setHovered(false)}
+ className={cn(
+ "aspect-square rounded-full border border-neutral-400/20 backdrop-blur-2xl flex items-center justify-center relative",
+ isActive
+ ? "bg-neutral-800 dark:bg-neutral-100"
+ : "bg-neutral-100 dark:bg-neutral-800",
+ )}
+ >
+
+ {hovered && (
+ // ------ Tooltip ------ //
+
+ {title}
+
+ )}
+
+
+
+
+
+
+ );
+}
diff --git a/apps/website/src/app/layout-floating-dock.tsx b/apps/website/src/app/layout-floating-dock.tsx
new file mode 100644
index 0000000..a2ec42a
--- /dev/null
+++ b/apps/website/src/app/layout-floating-dock.tsx
@@ -0,0 +1,92 @@
+"use client";
+
+import { SectionsList } from "@cuicui/ui";
+
+import { FloatingDock } from "#/src/app/floating-docks-component";
+import { HomeIcon, MoonIcon, SunIcon } from "lucide-react";
+import { usePathname } from "next/navigation";
+import { useTheme } from "next-themes";
+import { cn } from "#/src/utils/cn";
+import Link from "next/link";
+
+export function CuicuiFloatingDock() {
+ const pathName = usePathname();
+ const { setTheme, theme, resolvedTheme } = useTheme();
+
+ const handleSwitchTheme = () => {
+ if (resolvedTheme === "dark") {
+ setTheme("light");
+ }
+ if (resolvedTheme === "light") {
+ setTheme("dark");
+ }
+ };
+ return (
+
+ );
+}
+
+const sectionLinks = SectionsList.map((section) => {
+ return {
+ title: section.name,
+ Icon: section.icon,
+ href: `/${section.slug}`,
+ };
+});
+
+const homeLink = {
+ title: "Home",
+ icon: (
+
+ ),
+ href: "/",
+};
+const links = [homeLink, ...sectionLinks];
diff --git a/apps/website/src/app/layout.tsx b/apps/website/src/app/layout.tsx
index cb25c45..6481f0d 100644
--- a/apps/website/src/app/layout.tsx
+++ b/apps/website/src/app/layout.tsx
@@ -3,13 +3,13 @@ import { Toaster } from "sonner";
import "#/src/styles/globals.css";
import { DesktopSideMenu } from "#/src/components/navigation/desktop-menu";
import { AddressBar } from "#/src/ui/address-bar";
-import { MobileMenu } from "../components/navigation/mobile-menu";
import { DM_Sans } from "next/font/google";
import type { ReactNode } from "react";
import Providers from "#/src/app/providers";
import StarGithubProjectButton from "#/src/ui/star-github-project-button";
import PlausibleScripts from "#/src/components/analytics/plausible-scripts";
+import { CuicuiFloatingDock } from "#/src/app/layout-floating-dock";
const font = DM_Sans({
subsets: ["latin"],
display: "swap",
@@ -79,35 +79,8 @@ export default function RootLayout({
-
-
- {/*
*/}
-
- {/* Add overflow-auto if layout width problems */}
-
-
- {/*
*/}
-
- {/* Move overflow-auto to the previous comment if problems occurs */}
- {children}
-
- {/* */}
-
-
-
-
-
-
-
+ {children}
+