diff --git a/repomix-output.xml b/repomix-output.xml
new file mode 100644
index 0000000..7245ce0
--- /dev/null
+++ b/repomix-output.xml
@@ -0,0 +1,678 @@
+This file is a merged representation of a subset of the codebase, containing files not matching ignore patterns, combined into a single document by Repomix.
+
+
+This section contains a summary of this file.
+
+
+This file contains a packed representation of the entire repository's contents.
+It is designed to be easily consumable by AI systems for analysis, code review,
+or other automated processes.
+
+
+
+The content is organized as follows:
+1. This summary section
+2. Repository information
+3. Directory structure
+4. Repository files, each consisting of:
+ - File path as an attribute
+ - Full contents of the file
+
+
+
+- This file should be treated as read-only. Any changes should be made to the
+ original repository files, not this packed version.
+- When processing this file, use the file path to distinguish
+ between different files in the repository.
+- Be aware that this file may contain sensitive information. Handle it with
+ the same level of security as you would the original repository.
+
+
+
+- Some files may have been excluded based on .gitignore rules and Repomix's configuration
+- Binary files are not included in this packed representation. Please refer to the Repository Structure section for a complete list of file paths, including binary files
+- Files matching these patterns are excluded: bun.lock, node_modules/, .vscode/
+- Files matching patterns in .gitignore are excluded
+- Files matching default ignore patterns are excluded
+- Files are sorted by Git change count (files with more changes are at the bottom)
+
+
+
+
+
+
+
+
+
+public/
+ vite.svg
+src/
+ assets/
+ preact.svg
+ components/
+ ui/
+ Button.module.scss
+ Button.tsx
+ Input.module.scss
+ Input.tsx
+ layout.tsx
+ menu.module.scss
+ menu.tsx
+ pages/
+ login.module.scss
+ login.tsx
+ profile.module.scss
+ profile.tsx
+ providers/
+ AuthProvider.tsx
+ utils/
+ class-merge.ts
+ app.module.scss
+ app.tsx
+ index.scss
+ main.tsx
+ vite-env.d.ts
+.gitattributes
+.gitignore
+.prettierrc
+eslint.config.mjs
+index.html
+package.json
+postcss.config.mts
+tsconfig.app.json
+tsconfig.json
+tsconfig.node.json
+vite.config.ts
+
+
+
+This section contains the contents of the repository's files.
+
+
+import { signal, Signal } from "@preact/signals";
+import { createContext, JSX } from "preact";
+import { useContext } from "preact/hooks";
+
+interface AppContextValue {
+ isLoggedIn: Signal;
+}
+
+const AppContext = createContext({
+ isLoggedIn: signal(false),
+});
+
+const AppProvider = ({ children }: { children: JSX.Element }) => {
+ const value: AppContextValue = {
+ isLoggedIn: signal(false),
+ };
+
+ return {children} ;
+};
+
+const useAppContext = () => {
+ const context = useContext(AppContext);
+ if (!context) {
+ throw new Error("useAppContext must be used within AppProvider");
+ }
+ return context;
+};
+
+export { AppProvider, useAppContext };
+
+
+
+
+
+
+
+
+
+
+
+import { useAppContext } from "@/providers/AuthProvider";
+import { FunctionComponent } from "preact";
+import { Route, Router, useLocation } from "preact-iso";
+import { useEffect } from "preact/hooks";
+import Menu from "./menu";
+
+const Layout: FunctionComponent = () => {
+ const { isLoggedIn } = useAppContext();
+ const location = useLocation();
+ useEffect(() => {
+ console.log(isLoggedIn.value);
+ }, [isLoggedIn]);
+ return (
+
+
+
+ {
+ // location.route("/settings");
+ return Home ;
+ }}
+ />
+ Test } />
+ Test2 } />
+ 404 } />
+
+
+
+
+ );
+};
+
+export default Layout;
+
+
+
+@reference "../index.scss";
+
+
+
+import Layout from "@/components/layout";
+import { FunctionComponent } from "preact";
+
+const ProfilePage: FunctionComponent = () => {
+ return ;
+};
+
+export default ProfilePage;
+
+
+
+import { ClassValue, clsx } from "clsx";
+import { twMerge } from "tailwind-merge";
+
+export function cn(...inputs: ClassValue[]) {
+ return twMerge(clsx(...inputs));
+}
+
+
+
+@reference "./index.scss";
+
+.text {
+ @apply text-9xl text-red-500;
+}
+
+
+
+import { render } from "preact";
+import { App } from "./app.tsx";
+import "./index.scss";
+
+render( , document.getElementById("app")!);
+
+
+
+///
+
+
+
+* text=auto
+bun.lock binary
+
+
+
+# Logs
+logs
+*.log
+npm-debug.log*
+yarn-debug.log*
+yarn-error.log*
+pnpm-debug.log*
+lerna-debug.log*
+
+node_modules
+dist
+dist-ssr
+*.local
+
+# Editor directories and files
+.vscode/*
+!.vscode/extensions.json
+!.vscode/settings.json
+.idea
+.DS_Store
+*.suo
+*.ntvs*
+*.njsproj
+*.sln
+*.sw?
+
+
+
+// @ts-check
+
+import eslint from "@eslint/js";
+import tseslint from "typescript-eslint";
+
+export default tseslint.config({
+ extends: [eslint.configs.recommended, tseslint.configs.recommended],
+ ignores: ["*.d.ts"],
+ languageOptions: {
+ ecmaVersion: "latest",
+ sourceType: "module",
+ parserOptions: { ecmaFeatures: { jsx: true } },
+ },
+ settings: {
+ env: {
+ browser: true,
+ es6: true,
+ },
+ },
+});
+
+
+
+export default {
+ plugins: {
+ "@tailwindcss/postcss": {},
+ },
+};
+
+
+
+{
+ "compilerOptions": {
+ "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo",
+ "target": "ES2020",
+ "useDefineForClassFields": true,
+ "module": "ESNext",
+ "lib": [
+ "ES2020",
+ "DOM",
+ "DOM.Iterable"
+ ],
+ "skipLibCheck": true,
+ "paths": {
+ "react": [
+ "./node_modules/preact/compat/"
+ ],
+ "react-dom": [
+ "./node_modules/preact/compat/"
+ ],
+ "@/*": [
+ "./src/*"
+ ]
+ },
+ /* Bundler mode */
+ "moduleResolution": "bundler",
+ "allowImportingTsExtensions": true,
+ "isolatedModules": true,
+ "moduleDetection": "force",
+ "noEmit": true,
+ "jsx": "react-jsx",
+ "jsxImportSource": "preact",
+ /* Linting */
+ "strict": true,
+ "noUnusedLocals": true,
+ "noUnusedParameters": true,
+ "noFallthroughCasesInSwitch": true,
+ "noUncheckedSideEffectImports": true
+ },
+ "include": [
+ "src"
+ ]
+}
+
+
+
+{
+ "files": [],
+ "references": [
+ { "path": "./tsconfig.app.json" },
+ { "path": "./tsconfig.node.json" }
+ ]
+}
+
+
+
+{
+ "compilerOptions": {
+ "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo",
+ "target": "ES2022",
+ "lib": ["ES2023"],
+ "module": "ESNext",
+ "skipLibCheck": true,
+
+ /* Bundler mode */
+ "moduleResolution": "bundler",
+ "allowImportingTsExtensions": true,
+ "isolatedModules": true,
+ "moduleDetection": "force",
+ "noEmit": true,
+
+ /* Linting */
+ "strict": true,
+ "noUnusedLocals": true,
+ "noUnusedParameters": true,
+ "noFallthroughCasesInSwitch": true,
+ "noUncheckedSideEffectImports": true
+ },
+ "include": ["vite.config.ts"]
+}
+
+
+
+import preact from '@preact/preset-vite';
+import tailwindcss from '@tailwindcss/vite';
+import { defineConfig } from 'vite';
+import tsConfigPaths from 'vite-tsconfig-paths';
+
+// https://vite.dev/config/
+export default defineConfig({
+ plugins: [preact(), tailwindcss(), tsConfigPaths()],
+});
+
+
+
+@reference '../../index.scss';
+
+.button {
+ @apply rounded-2xl border-2 py-3 font-semibold text-white transition-colors hover:cursor-pointer;
+}
+
+
+
+import { FunctionComponent } from "preact";
+import { tv } from "tailwind-variants";
+import classes from "./Button.module.scss";
+const button = tv({
+ base: classes.button,
+ variants: {
+ color: {
+ primary: "bg-blue-400 hover:bg-blue-500",
+ secondary: "bg-red-400 hover:bg-red-500",
+ },
+ },
+});
+
+const Button: FunctionComponent<{ onClick: () => void }> = (props) => {
+ return (
+
+ {props.children}
+
+ );
+};
+
+export default Button;
+
+
+
+import { FunctionComponent } from "preact";
+import { tv } from "tailwind-variants";
+import classes from "./Input.module.scss";
+
+const input = tv({
+ base: classes.input_field,
+ variants: {
+ "text-align": {
+ center: "text-center",
+ left: "text-left",
+ },
+ },
+ defaultVariants: {
+ "text-align": "left",
+ },
+});
+
+interface InputProps {
+ isPassword?: boolean;
+ placeholder?: string;
+ textAlign?: "center" | "left";
+}
+
+const Input: FunctionComponent = ({ isPassword = false, placeholder = "", textAlign }: InputProps) => {
+ return (
+
+ );
+};
+
+export default Input;
+
+
+
+@reference "../index.scss";
+
+.menu_container {
+ @apply flex min-h-8 min-w-screen flex-col items-center gap-4 border-l border-l-gray-500 px-5 pt-5 md:min-h-screen md:min-w-[300px];
+}
+
+.menu_item {
+ @apply w-full cursor-pointer rounded-md px-6 py-2 text-center hover:bg-gray-200;
+}
+
+
+
+import { FunctionComponent } from "preact";
+import { useLocation } from "preact-iso";
+import { tv } from "tailwind-variants";
+import classes from "./menu.module.scss";
+
+interface MenuItemProps {
+ title: string;
+ link: string;
+}
+
+const MenuItem: FunctionComponent = ({ title, link }: MenuItemProps) => {
+ const location = useLocation();
+ const active = location.path === link;
+ const menuItemClasses = tv({
+ base: classes.menu_item,
+ variants: {
+ activity: {
+ active: "bg-gray-200",
+ inactive: "bg-gray-100",
+ },
+ },
+ defaultVariants: {
+ activity: "inactive",
+ },
+ });
+ return (
+
+ );
+};
+
+interface MenuItems {
+ title: string;
+ link: string;
+}
+
+const Menu: FunctionComponent = () => {
+ const menu_items: MenuItems[] = [
+ {
+ title: "Профиль",
+ link: "/profile",
+ },
+ {
+ title: "Задачи",
+ link: "/tasks",
+ },
+ {
+ title: "Календарь",
+ link: "/calendar",
+ },
+ ];
+ return (
+
+ );
+};
+
+export default Menu;
+
+
+
+@reference "../index.scss";
+
+.login_container {
+ @apply flex min-h-screen flex-col items-center justify-center;
+}
+
+.login_card {
+ @apply flex w-[95%] min-w-[300px] flex-col justify-center gap-2 rounded-md border-gray-400 p-5 shadow-md md:w-[350px];
+}
+
+
+
+import Button from "@/components/ui/Button";
+import Input from "@/components/ui/Input";
+import { useAppContext } from "@/providers/AuthProvider";
+import { FunctionComponent } from "preact";
+import { useLocation } from "preact-iso";
+import classes from "./login.module.scss";
+const LoginPage: FunctionComponent = () => {
+ const { isLoggedIn } = useAppContext();
+ const location = useLocation();
+ return (
+
+ );
+};
+
+export default LoginPage;
+
+
+
+@import "tailwindcss";
+@import url("https://fonts.googleapis.com/css2?family=Montserrat:ital,wght@0,100..900;1,100..900&display=swap");
+:root {
+ font-family: "Montserrat", sans-serif;
+}
+
+
+
+
+
+
+
+
+
+ Антихвост
+
+
+
+
+
+
+
+
+
+@reference "../../index.scss";
+
+.input_field {
+ @apply rounded-md border border-gray-300 p-2 placeholder:transition focus:outline-0 focus:placeholder:opacity-25;
+}
+
+
+
+import { FunctionComponent } from "preact";
+import { ErrorBoundary, lazy, LocationProvider, Route, Router, useLocation } from "preact-iso";
+import "preact/debug";
+import LoginPage from "./pages/login";
+import { AppProvider } from "./providers/AuthProvider";
+
+const HomePage: FunctionComponent = () => {
+ const location = useLocation();
+ location.route("/login");
+ return Redirecting to login...
;
+};
+
+export function App() {
+ return (
+
+
+
+
+
+
+ import("./pages/profile"))} />
+
+
+
+
+ );
+}
+
+
+
+{
+ "tabWidth": 2,
+ "printWidth": 120,
+ "arrowParens": "always",
+ "singleQuote": false,
+ "trailingComma": "es5",
+ "useTabs": false,
+ "semi": true,
+ "bracketSpacing": true,
+ "plugins": ["prettier-plugin-tailwindcss"],
+ "tailwindFunctions": ["tv"]
+}
+
+
+
+{
+ "name": "anti-hvost",
+ "private": true,
+ "version": "0.0.0",
+ "type": "module",
+ "scripts": {
+ "dev": "vite",
+ "build": "tsc -b && vite build",
+ "preview": "vite preview"
+ },
+ "dependencies": {
+ "@preact/signals": "^2.0.2",
+ "@tailwindcss/postcss": "^4.0.17",
+ "@tailwindcss/vite": "^4.0.17",
+ "clsx": "^2.1.1",
+ "postcss": "^8.5.3",
+ "preact": "^10.26.2",
+ "preact-iso": "^2.9.1",
+ "tailwind-merge": "^3.0.2",
+ "tailwind-variants": "^1.0.0",
+ "tailwindcss": "^4.0.17"
+ },
+ "devDependencies": {
+ "@eslint/js": "^9.23.0",
+ "@preact/preset-vite": "^2.10.1",
+ "@typescript-eslint/parser": "^8.28.0",
+ "eslint": "^9.23.0",
+ "eslint-config-prettier": "^10.1.1",
+ "prettier": "^3.5.3",
+ "prettier-eslint": "^16.3.0",
+ "prettier-plugin-tailwindcss": "^0.6.11",
+ "sass-embedded": "^1.86.0",
+ "typescript": "~5.7.2",
+ "typescript-eslint": "^8.28.0",
+ "vite": "^6.2.0",
+ "vite-tsconfig-paths": "^5.1.4"
+ }
+}
+
+
+
diff --git a/src/pages/profile_tasks.tsx b/src/pages/profile_tasks.tsx
index 109aa7a..da96cf0 100644
--- a/src/pages/profile_tasks.tsx
+++ b/src/pages/profile_tasks.tsx
@@ -3,6 +3,7 @@ import Task from "@/components/task";
import ModalCalendar from "@/components/ModalCalendar";
import ModalTags, { ITags } from "@/components/ModalTags";
import Button from "@/components/ui/Button";
+import Dialog from "@/components/ui/Dialog";
import ModalWindow from "@/components/ui/Modal";
import { withTitle } from "@/constructors/Component";
import { UrlsTitle } from "@/enums/urls";
@@ -26,7 +27,6 @@ import { SubmitHandler, useForm } from "react-hook-form";
import { v4 as uuid } from "uuid";
import { ITask, ITaskForm } from "./profile_tasks.dto";
import classes from "./profile_tasks.module.scss";
-import Dialog from "@/components/ui/Dialog";
const example_tags: { first: string[]; second: string[] } = {
first: ["Программирование", "Информатика", "Физика", "Математика"],
@@ -117,29 +117,27 @@ const ProfileTasks: FunctionComponent = () => {
const groupTasksByDate = useMemo(() => {
const today = new Date();
today.setHours(0, 0, 0, 0);
-
+
const tomorrow = new Date(today);
tomorrow.setDate(tomorrow.getDate() + 1);
-
+
const groupedTasks = {
today: [] as ITask[],
tomorrow: [] as ITask[],
future: [] as { date: Date; tasks: ITask[] }[],
};
- tasks.forEach(task => {
+ tasks.forEach((task) => {
const taskDate = new Date(task.date);
taskDate.setHours(0, 0, 0, 0);
-
+
if (taskDate.getTime() === today.getTime()) {
groupedTasks.today.push(task);
} else if (taskDate.getTime() === tomorrow.getTime()) {
groupedTasks.tomorrow.push(task);
} else if (taskDate > tomorrow) {
- const existingGroup = groupedTasks.future.find(group =>
- group.date.getTime() === taskDate.getTime()
- );
-
+ const existingGroup = groupedTasks.future.find((group) => group.date.getTime() === taskDate.getTime());
+
if (existingGroup) {
existingGroup.tasks.push(task);
} else {
@@ -152,7 +150,7 @@ const ProfileTasks: FunctionComponent = () => {
groupedTasks.today.sort((a, b) => a.date.getTime() - b.date.getTime());
groupedTasks.tomorrow.sort((a, b) => a.date.getTime() - b.date.getTime());
groupedTasks.future.sort((a, b) => a.date.getTime() - b.date.getTime());
- groupedTasks.future.forEach(group => {
+ groupedTasks.future.forEach((group) => {
group.tasks.sort((a, b) => a.date.getTime() - b.date.getTime());
});
@@ -163,7 +161,7 @@ const ProfileTasks: FunctionComponent = () => {
return new Intl.DateTimeFormat("ru-RU", {
day: "numeric",
month: "long",
- year: "numeric"
+ year: "numeric",
}).format(date);
};
@@ -483,7 +481,7 @@ const ProfileTasks: FunctionComponent = () => {
) : (
<>
Начни уже сегодня!
-