Adaptive header for modile and tablet

This commit is contained in:
2024-05-09 14:55:24 +04:00
parent a634c194fe
commit 4f8301d1e8
13 changed files with 192 additions and 101 deletions

9
package-lock.json generated
View File

@@ -8,6 +8,7 @@
"name": "torrent_frontend", "name": "torrent_frontend",
"version": "0.1.0", "version": "0.1.0",
"dependencies": { "dependencies": {
"clsx": "^2.1.1",
"next": "14.2.3", "next": "14.2.3",
"next-themes": "^0.3.0", "next-themes": "^0.3.0",
"react": "^18", "react": "^18",
@@ -1088,6 +1089,14 @@
"resolved": "https://registry.npmjs.org/client-only/-/client-only-0.0.1.tgz", "resolved": "https://registry.npmjs.org/client-only/-/client-only-0.0.1.tgz",
"integrity": "sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==" "integrity": "sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA=="
}, },
"node_modules/clsx": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz",
"integrity": "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==",
"engines": {
"node": ">=6"
}
},
"node_modules/color-convert": { "node_modules/color-convert": {
"version": "2.0.1", "version": "2.0.1",
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",

View File

@@ -9,6 +9,7 @@
"lint": "next lint" "lint": "next lint"
}, },
"dependencies": { "dependencies": {
"clsx": "^2.1.1",
"next": "14.2.3", "next": "14.2.3",
"next-themes": "^0.3.0", "next-themes": "^0.3.0",
"react": "^18", "react": "^18",

View File

@@ -41,3 +41,15 @@ body {
color: var(--color-fg1); color: var(--color-fg1);
background-color: var(--color-bg0); background-color: var(--color-bg0);
} }
@media (max-width: 1280px) {
:root {
--app-width: 100%;
}
}
@media (max-width: 640px) {
:root {
font-size: calc((100vh / 1080) * 16);
}
}

View File

@@ -1,9 +1,6 @@
import { GameCard } from "@/features/gameCard";
import { Section } from "@/widgets/section"; import { Section } from "@/widgets/section";
export default function Home() { export default function Home() {
return ( return <div className="w-full max-w-[var(--app-width)] m-auto"></div>;
<div className="w-full max-w-[var(--app-width)] m-auto">
<Section name="Игры">a</Section>
</div>
);
} }

View File

@@ -0,0 +1,17 @@
"use client";
import { SunIcon } from "@/shared/assets/icons";
import { useTheme } from "next-themes";
export const ColorSchemeSwitch = () => {
const { theme, setTheme } = useTheme();
return (
<>
<SunIcon
className="mr-5 h-8 w-8 cursor-pointer"
onClick={() => setTheme(theme == "light" ? "dark" : "light")}
/>
</>
);
};

View File

@@ -0,0 +1,3 @@
import { ColorSchemeSwitch } from "./colorSchemeSwitch";
export { ColorSchemeSwitch as SchemeSwitch };

View File

@@ -1,3 +1,3 @@
export const GameCard = () => { export const GameCard = () => {
return <></>; return <></>;
}; };

View File

@@ -1,3 +0,0 @@
import { SchemeSwitch } from "./schemeSwitch";
export { SchemeSwitch };

View File

@@ -1,17 +0,0 @@
"use client";
import { SunIcon } from "@/shared/assets/icons";
import { useTheme } from "next-themes";
export const SchemeSwitch = () => {
const { theme, setTheme } = useTheme();
return (
<>
<SunIcon
className="mr-5 h-8 w-8 cursor-pointer"
onClick={() => setTheme(theme == "light" ? "dark" : "light")}
/>
</>
);
};

View File

@@ -1,45 +1,62 @@
import { SchemeSwitch } from "@/features/schemeSwitch"; import { SchemeSwitch } from "@/features/colorSchemeSwitch";
import { PersonIcon, SearchIcon } from "@/shared/assets/icons"; import { PersonIcon, SearchIcon } from "@/shared/assets/icons";
import { MobileMenu } from "./mobileMenu/mobileMenu";
import Link from "next/link";
const sections = [
{ title: "Игры", href: "/games" },
{ title: "Фильмы", href: "/films" },
{ title: "Аудиокниги", href: "/audiobooks" },
];
export const Header = () => { export const Header = () => {
return ( return (
<header className="w-full h-20 flex justify-around bg-bg1"> <header className="w-full h-20 bg-bg1">
<div <div
className="w-full h-full max-w-[var(--app-width)] className="w-full h-full max-w-[var(--app-width)] m-auto px-5
flex items-center justify-between" flex items-center justify-between"
> >
<h1 className="text-5xl font-bold">.Torrent</h1> <h1 className="text-4xl font-bold flex items-center">
<div className="text-3xl"> <div className="lp:hidden">
{["Игры", "Фильмы", "Аудиокниги"].map((section) => ( <MobileMenu sections={sections} />
<a key={section} className="px-2 cursor-pointer hover:underline"> </div>
{section} <Link href="/">.Torrent</Link>
</a> </h1>
))} <div className="hidden text-2xl dsk:block">
</div> {sections.map((section) => (
<div className="flex flex-col items-end"> <Link
<span className="flex items-center mb-1 "> key={section.title}
<SchemeSwitch /> className="px-5 cursor-pointer hover:underline"
<span className="cursor-pointer flex items-center"> href={section.href}
<PersonIcon className="mr-1 h-4 w-4" /> >
Войти {section.title}
</span> </Link>
</span> ))}
<label className="flex flex-col items-start relative w-36"> </div>
<input <div className="flex flex-col items-end">
className="peer/search w-full rounded-lg bg-bg4 px-2" <span className="flex items-center mb-1 ">
placeholder=" " <SchemeSwitch />
/> <span className="cursor-pointer flex items-center">
<span <PersonIcon className="mr-1 h-4 w-4" />
className="peer-focus/search:opacity-0 Войти
peer-[:not(:placeholder-shown)]/search:opacity-0 </span>
transition-all h-0 flex items-center relative bottom-3" </span>
> <label className="flex flex-col items-start relative w-36">
<SearchIcon className="w-4 h-4 mx-2" /> <input
Поиск className="peer/search w-full rounded-lg bg-bg4 px-2"
</span> placeholder=" "
</label> />
</div> <span
</div> className="peer-focus/search:opacity-0
</header> peer-[:not(:placeholder-shown)]/search:opacity-0
); transition-all h-0 flex items-center relative bottom-3"
>
<SearchIcon className="w-4 h-4 mx-2" />
Поиск
</span>
</label>
</div>
</div>
</header>
);
}; };

View File

@@ -0,0 +1,50 @@
"use client";
import clsx from "clsx";
import Link from "next/link";
import { useState } from "react";
export const MobileMenu = ({
sections,
}: {
sections: { title: string; href: string }[];
}) => {
const [open, changeMenuOpen] = useState<boolean>(false);
return (
<div className="relative">
<button
className="peer w-16 h-16 *:w-12 *:h-1 *:bg-fg1 *:my-3
*:transition-all *:duration-300 *:relative"
onClick={() => changeMenuOpen(!open)}
onBlur={() => changeMenuOpen(false)}
>
<div
className={clsx(open && "rotate-45 top-4", !open && "top-0")}
></div>
<div className={clsx(open && "opacity-0")}></div>
<div
className={clsx(open && "-rotate-45 bottom-4", !open && "bottom-0")}
></div>
</button>
<div
className={clsx(
"h-0 absolute transition-all duration-300 overflow-hidden\
bg-bg4 rounded-lg px-4 flex flex-col",
open && "h-32"
)}
onClick={() => changeMenuOpen(false)}
>
{sections.map((section) => (
<Link
key={section.title}
className="text-xl py-2 cursor-pointer hover:underline"
href={section.href}
>
{section.title}
</Link>
))}
</div>
</div>
);
};

View File

@@ -1,15 +1,15 @@
export const Section = ({ export const Section = ({
name, name,
children, children,
}: { }: {
name: string; name: string;
children: React.ReactNode; children: React.ReactNode;
}) => { }) => {
return ( return (
// open section onClick // open section onClick
<section className="w-full mt-8 cursor-pointer"> <section className="w-full m-5 mt-8 cursor-pointer">
<h2 className="text-4xl">{name}</h2> <h2 className="text-4xl">{name}</h2>
<div>{children}</div> <div>{children}</div>
</section> </section>
); );
}; };

View File

@@ -1,29 +1,34 @@
import type { Config } from "tailwindcss"; import type { Config } from "tailwindcss";
const config: Config = { const config: Config = {
content: [ content: [
"./src/pages/**/*.{js,ts,jsx,tsx,mdx}", "./src/pages/**/*.{js,ts,jsx,tsx,mdx}",
"./src/components/**/*.{js,ts,jsx,tsx,mdx}", "./src/components/**/*.{js,ts,jsx,tsx,mdx}",
"./src/app/**/*.{js,ts,jsx,tsx,mdx}", "./src/app/**/*.{js,ts,jsx,tsx,mdx}",
"./src/**/*.{js,ts,jsx,tsx,mdx}", "./src/**/*.{js,ts,jsx,tsx,mdx}",
], ],
theme: { theme: {
extend: { extend: {
backgroundImage: { backgroundImage: {
"gradient-radial": "radial-gradient(var(--tw-gradient-stops))", "gradient-radial": "radial-gradient(var(--tw-gradient-stops))",
"gradient-conic": "gradient-conic":
"conic-gradient(from 180deg at 50% 50%, var(--tw-gradient-stops))", "conic-gradient(from 180deg at 50% 50%, var(--tw-gradient-stops))",
}, },
colors: { colors: {
bg0: "var(--color-bg0)", bg0: "var(--color-bg0)",
bg1: "var(--color-bg1)", bg1: "var(--color-bg1)",
bg4: "var(--color-bg4)", bg4: "var(--color-bg4)",
fg0: "var(--color-fg0)", fg0: "var(--color-fg0)",
fg1: "var(--color-fg1)", fg1: "var(--color-fg1)",
fg4: "var(--color-fg4)", fg4: "var(--color-fg4)",
}, },
}, },
}, screens: {
plugins: [], tb: "640px",
lp: "1024px",
dsk: "1280px",
},
},
plugins: [],
}; };
export default config; export default config;