feat: style improvements

This commit is contained in:
2025-05-05 15:15:25 +03:00
parent be7a58b93f
commit db73f498f6
6 changed files with 109 additions and 38 deletions

View File

@@ -5,9 +5,9 @@ import { Dispatch, StateUpdater, useState } from "preact/hooks";
import { Calendar, CalendarPassThroughMethodOptions } from "primereact/calendar";
import { FormEvent } from "primereact/ts-helpers";
import Button from "./ui/Button";
import ModalWindow from "./ui/Modal";
import ModalWindow, { ModalWindowProps } from "./ui/Modal";
interface ModalCalendarProps {
interface ModalCalendarProps extends ModalWindowProps {
isOpen?: boolean;
setIsOpen?: Dispatch<StateUpdater<boolean>>;
onClose?: () => void;
@@ -27,10 +27,18 @@ const TRANSITIONS = {
},
};
const ModalCalendar: FunctionComponent<ModalCalendarProps> = ({ isOpen, setIsOpen, onClose, onChange, value }) => {
const ModalCalendar: FunctionComponent<ModalCalendarProps> = ({
isOpen,
setIsOpen,
onClose,
onChange,
value,
...rest
}) => {
const [showTime, setShowTime] = useState(false);
return (
<ModalWindow
{...rest}
isOpen={isOpen}
setIsOpen={setIsOpen}
onClose={() => {
@@ -38,7 +46,6 @@ const ModalCalendar: FunctionComponent<ModalCalendarProps> = ({ isOpen, setIsOpe
setShowTime(false);
}}
className="md:h-[40rem] md:w-[30rem]"
zIndex={60}
>
<div class="w-full flex-1 self-start">
<Calendar

View File

@@ -3,14 +3,14 @@ import { BookOpenIcon, DocumentDuplicateIcon } from "@heroicons/react/24/outline
import { FunctionComponent } from "preact";
import { Dispatch, StateUpdater, useEffect, useState } from "preact/hooks";
import Button from "./ui/Button";
import ModalWindow from "./ui/Modal";
import ModalWindow, { ModalWindowProps } from "./ui/Modal";
export interface ITags {
first: string;
second: string;
}
interface ModalTagsProps {
interface ModalTagsProps extends ModalWindowProps {
isOpen?: boolean;
setIsOpen?: Dispatch<StateUpdater<boolean>>;
onClose?: () => void;
@@ -22,7 +22,15 @@ interface ModalTagsProps {
};
}
const ModalTags: FunctionComponent<ModalTagsProps> = ({ isOpen, setIsOpen, onClose, onChange, value, tagsList }) => {
const ModalTags: FunctionComponent<ModalTagsProps> = ({
isOpen,
setIsOpen,
onClose,
onChange,
value,
tagsList,
...rest
}) => {
const [showFirstTags, setShowFirstTags] = useState(false);
const [showSecondTags, setShowSecondTags] = useState(false);
useEffect(() => {
@@ -34,6 +42,7 @@ const ModalTags: FunctionComponent<ModalTagsProps> = ({ isOpen, setIsOpen, onClo
return (
<ModalWindow
isOpen={isOpen}
{...rest}
setIsOpen={setIsOpen}
onClose={() => {
onClose!();

View File

@@ -23,15 +23,12 @@ const Dialog: FunctionComponent<DialogProps> = ({
if (!isOpen) return null;
return (
<div class="fixed inset-0 z-50 flex items-center justify-center bg-black/50">
<div class="fixed inset-0 z-150 flex items-center justify-center bg-black/50">
<div class="w-full max-w-md rounded-[4rem] bg-white p-6 shadow-lg">
<h2 class="mb-4 text-xl font-semibold">{title}</h2>
<p class="mb-6">{content}</p>
<p class="mb-6 text-sm sm:text-[1rem]">{content}</p>
<div class="flex justify-end gap-4">
<Button
onClick={() => setIsOpen(false)}
className="bg-gray-200 text-gray-800 hover:bg-gray-300"
>
<Button onClick={() => setIsOpen(false)} className="bg-gray-200 text-gray-800 hover:bg-gray-300">
{cancelText}
</Button>
<Button
@@ -49,4 +46,4 @@ const Dialog: FunctionComponent<DialogProps> = ({
);
};
export default Dialog;
export default Dialog;

View File

@@ -2,7 +2,7 @@ import { cn } from "@/utils/class-merge";
import { FunctionComponent } from "preact";
import { Dispatch, StateUpdater, useEffect } from "preact/hooks";
interface ModalWindowProps {
export interface ModalWindowProps {
isOpen?: boolean;
setIsOpen?: Dispatch<StateUpdater<boolean>>;
onClose?: () => void;

View File

@@ -5,7 +5,7 @@
}
.header {
@apply mb-3 w-full text-3xl font-semibold md:mb-12 md:text-5xl;
@apply mb-3 flex w-full flex-row items-center justify-between text-xl font-semibold sm:text-3xl md:mb-12 md:text-5xl;
}
.tasks_container {

View File

@@ -1,3 +1,4 @@
//! Файл большой, потому что было лень делить на компоненты
import Task from "@/components/task";
import ModalCalendar from "@/components/ModalCalendar";
@@ -211,6 +212,7 @@ const ProfileTasks: FunctionComponent = () => {
return (
<div class={classes.container}>
<ModalTags
zIndex={70}
isOpen={openModalTags}
setIsOpen={setOpenModalTags}
tagsList={example_tags}
@@ -221,6 +223,7 @@ const ProfileTasks: FunctionComponent = () => {
onChange={setTags}
/>
<ModalCalendar
zIndex={80}
isOpen={openModalCalendar}
setIsOpen={setOpenModalCalendar}
onClose={() => {
@@ -230,6 +233,7 @@ const ProfileTasks: FunctionComponent = () => {
value={calendarDate!}
/>
<ModalWindow
zIndex={60}
isOpen={openModal}
setIsOpen={setIsOpen}
onClose={() => {
@@ -428,7 +432,33 @@ const ProfileTasks: FunctionComponent = () => {
{!searchQuery && !filterTags.first && !filterTags.second ? (
filteredTasks.length > 0 ? (
<>
<div class={classes.header}>Сегодня: {getDate}</div>
<div class={classes.header}>
Сегодня: {getDate}
<div class="flex flex-row items-center gap-2 md:hidden">
{!openSearchModal && (
<div
class="flex aspect-square h-12 cursor-pointer flex-col items-center justify-center rounded-full bg-[rgba(206,232,251,0.7)] text-xl text-gray-600 shadow-[0px_4px_4px_0px_rgba(0,0,0,0.25)] hover:bg-[rgba(206,232,251,0.9)]"
onClick={(e) => {
e.stopPropagation();
if (!openSearchModal) setOpenFilterModal(false);
setOpenSearchModal(!openSearchModal);
}}
>
<MagnifyingGlassIcon class="size-6" />
</div>
)}
<div class="flex aspect-square h-12 cursor-pointer flex-col items-center justify-center rounded-full bg-[rgba(206,232,251,0.7)] text-xl text-gray-600 shadow-[0px_4px_4px_0px_rgba(0,0,0,0.25)] hover:bg-[rgba(206,232,251,0.9)]">
<FunnelIcon
class="size-6"
onClick={(e) => {
e.stopPropagation();
if (!openFilterModal) setOpenSearchModal(false);
setOpenFilterModal(!openFilterModal);
}}
/>
</div>
</div>
</div>
<div class={classes.tasks_container}>
{groupTasksByDate.today.length > 0 ? (
<div class="w-full">
@@ -501,8 +531,32 @@ const ProfileTasks: FunctionComponent = () => {
)
) : (
<div class={classes.tasks_container}>
<div class="mb-8 w-full text-3xl font-semibold md:text-5xl">
<div class="mb-8 flex w-full flex-row items-center justify-between text-xl font-semibold sm:text-3xl md:text-5xl">
{searchQuery ? "Результаты поиска" : "Результаты фильтрации"}
<div class="flex flex-row items-center gap-2 md:hidden">
{!openSearchModal && (
<div
class="flex aspect-square h-12 cursor-pointer flex-col items-center justify-center rounded-full bg-[rgba(206,232,251,0.7)] text-xl text-gray-600 shadow-[0px_4px_4px_0px_rgba(0,0,0,0.25)] hover:bg-[rgba(206,232,251,0.9)]"
onClick={(e) => {
e.stopPropagation();
if (!openSearchModal) setOpenFilterModal(false);
setOpenSearchModal(!openSearchModal);
}}
>
<MagnifyingGlassIcon class="size-6" />
</div>
)}
<div class="flex aspect-square h-12 cursor-pointer flex-col items-center justify-center rounded-full bg-[rgba(206,232,251,0.7)] text-xl text-gray-600 shadow-[0px_4px_4px_0px_rgba(0,0,0,0.25)] hover:bg-[rgba(206,232,251,0.9)]">
<FunnelIcon
class="size-6"
onClick={(e) => {
e.stopPropagation();
if (!openFilterModal) setOpenSearchModal(false);
setOpenFilterModal(!openFilterModal);
}}
/>
</div>
</div>
</div>
{filteredTasks.length > 0 ? (
filteredTasks.map((task) => (
@@ -562,7 +616,7 @@ const ProfileTasks: FunctionComponent = () => {
</div>
</div>
{openSearchModal && (
<div class="absolute right-24 bottom-28 z-50 w-80 rounded-lg bg-white p-4 shadow-lg md:right-[24rem] md:bottom-28">
<div class="fixed bottom-28 z-50 w-full rounded-lg bg-white p-4 shadow-lg md:absolute md:right-[24rem] md:mx-0 md:w-80">
{/* Пофиксить разфокус при вводе */}
<div class="flex items-center gap-2">
<MagnifyingGlassIcon class="size-6 text-gray-400" />
@@ -576,28 +630,29 @@ const ProfileTasks: FunctionComponent = () => {
setSearchQuery((e.target as HTMLInputElement).value);
}}
/>
{searchQuery && (
<XMarkIcon
class="size-5 cursor-pointer text-gray-400 hover:text-gray-600"
onClick={() => {
setSearchQuery("");
setOpenSearchModal(false);
}}
/>
)}
<XMarkIcon
class="size-5 cursor-pointer text-gray-400 hover:text-gray-600"
onClick={() => {
setSearchQuery("");
setOpenSearchModal(false);
}}
/>
</div>
</div>
)}
{openFilterModal && (
<div class="absolute right-24 bottom-28 z-50 w-80 rounded-lg bg-white p-4 shadow-lg md:right-[24rem] md:bottom-28">
<div class="fixed top-[50%] z-50 w-full rounded-[2rem] bg-white p-4 shadow-lg md:absolute md:top-auto md:right-[24rem] md:bottom-28 md:w-80">
<div class="flex flex-col gap-4">
<div class="text-lg font-semibold">Фильтры</div>
<div class="text-center text-lg font-semibold">Фильтры</div>
<div class="flex flex-col gap-2">
<div class="relative">
<div
class={cn("flex cursor-pointer items-center gap-2 rounded-lg bg-[rgba(206,232,251,0.7)] px-4 py-2", {
"bg-[rgba(206,232,251,0.9)]": filterTags.first,
})}
class={cn(
"flex cursor-pointer items-center justify-center gap-2 rounded-lg bg-[rgba(206,232,251,0.7)] px-4 py-2",
{
"bg-[rgba(206,232,251,0.9)]": filterTags.first,
}
)}
onClick={() => {
setOpenFirstList(!openFirstList);
setOpenSecondList(false);
@@ -607,7 +662,7 @@ const ProfileTasks: FunctionComponent = () => {
<span>{filterTags.first || "Предмет"}</span>
</div>
{openFirstList && (
<div class="absolute top-0 right-full z-50 mr-2 w-64 rounded-lg bg-white p-2 shadow-lg">
<div class="absolute top-full right-0 z-50 w-64 rounded-lg bg-white p-2 shadow-lg md:top-0 md:right-full md:mr-2">
{example_tags.first.map((tag) => (
<div
key={tag}
@@ -634,9 +689,12 @@ const ProfileTasks: FunctionComponent = () => {
<div class="relative">
<div
class={cn("flex cursor-pointer items-center gap-2 rounded-lg bg-[rgba(206,232,251,0.7)] px-4 py-2", {
"bg-[rgba(206,232,251,0.9)]": filterTags.second,
})}
class={cn(
"flex cursor-pointer items-center justify-center gap-2 rounded-lg bg-[rgba(206,232,251,0.7)] px-4 py-2",
{
"bg-[rgba(206,232,251,0.9)]": filterTags.second,
}
)}
onClick={() => {
setOpenSecondList(!openSecondList);
setOpenFirstList(false);
@@ -646,7 +704,7 @@ const ProfileTasks: FunctionComponent = () => {
<span>{filterTags.second || "Задача"}</span>
</div>
{openSecondList && (
<div class="absolute top-0 right-full z-50 mr-2 w-64 rounded-lg bg-white p-2 shadow-lg">
<div class="absolute top-full right-0 z-50 w-64 rounded-lg bg-white p-2 shadow-lg md:top-0 md:right-full md:mr-2">
{example_tags.second.map((tag) => (
<div
key={tag}