diff --git a/.idea/caches/deviceStreaming.xml b/.idea/caches/deviceStreaming.xml index 9aaec77..64702e5 100644 --- a/.idea/caches/deviceStreaming.xml +++ b/.idea/caches/deviceStreaming.xml @@ -75,6 +75,19 @@ diff --git a/.idea/copilot.data.migration.agent.xml b/.idea/copilot.data.migration.agent.xml new file mode 100644 index 0000000..4ea72a9 --- /dev/null +++ b/.idea/copilot.data.migration.agent.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/.idea/copilot.data.migration.ask2agent.xml b/.idea/copilot.data.migration.ask2agent.xml new file mode 100644 index 0000000..1f2ea11 --- /dev/null +++ b/.idea/copilot.data.migration.ask2agent.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/.idea/copilot.data.migration.edit.xml b/.idea/copilot.data.migration.edit.xml new file mode 100644 index 0000000..8648f94 --- /dev/null +++ b/.idea/copilot.data.migration.edit.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/index.html b/index.html new file mode 100644 index 0000000..37b02be --- /dev/null +++ b/index.html @@ -0,0 +1,1239 @@ + + + + + + + + + TaskNexus - Modern Task Management + + + + + + + + + + + + +
+
+
+
+

+ TaskNexus +

+

+ Your Central Hub for Task Management Excellence +

+

+ A modern, cross-platform task management application built with + React Native, Expo, and TypeScript. Manage your daily tasks + efficiently with real-time synchronization, beautiful charts, and + intuitive UI. +

+
+
+ Cross-Platform + iOS, Android & Web +
+
+ Real-time + Cloud Sync +
+
+ 100% + TypeScript +
+
+ +
+
+
+ + +
+
+

Overview

+
+

+ TaskNexus is a comprehensive task management solution designed for + modern users who need reliable, efficient, and beautiful task + tracking across all their devices. Built with cutting-edge + technologies and best practices, it offers a seamless experience + whether you're on iOS, Android, or the web. +

+
+ +
+
+
๐ŸŽฏ
+

Purpose-Built

+

+ Designed specifically for efficient task management with an + intuitive interface that gets out of your way. +

+
+
+
โšก
+

Lightning Fast

+

+ Optimized performance with real-time updates and smooth animations + throughout the app. +

+
+
+
๐Ÿ”’
+

Secure & Private

+

+ Your data is protected with Supabase authentication and row-level + security policies. +

+
+
+
๐Ÿ“Š
+

Visual Analytics

+

+ Beautiful charts and statistics to help you understand your + productivity patterns. +

+
+
+ +
+

Why TaskNexus?

+

+ The name "TaskNexus" reflects the app's core purpose โ€“ serving as a + central hub (nexus) for all your tasks. It conveys a sense of + connectivity and organization, bringing together tasks from + different aspects of your life into one unified, powerful platform. +

+
+
+
+ + +
+
+

Key Features

+ +
+
+
๐Ÿ“
+

Task Management

+
    +
  • Add, update, and delete tasks effortlessly
  • +
  • Drag-and-drop reordering with smooth animations
  • +
  • Mark tasks as complete/incomplete with a tap
  • +
  • Color-coded tasks for easy categorization
  • +
  • Due date and time tracking
  • +
+
+ +
+
โ˜๏ธ
+

Cloud Synchronization

+
    +
  • Real-time sync across all devices
  • +
  • Supabase-powered backend
  • +
  • WebSocket-based live updates
  • +
  • Automatic conflict resolution
  • +
  • Manual refresh capability
  • +
+
+ +
+
๐Ÿ“Š
+

Statistics & Charts

+
    +
  • Pie chart for completion ratios
  • +
  • Bar chart for overdue vs. upcoming tasks
  • +
  • Line chart for tasks over time
  • +
  • Theme-adaptive transparent charts
  • +
  • Real-time chart updates
  • +
+
+ +
+
๐ŸŽจ
+

Theming & UI

+
    +
  • Dark and light mode support
  • +
  • Smooth theme transitions (200ms)
  • +
  • System theme auto-detection
  • +
  • Material Design components
  • +
  • Custom bottom tab bar
  • +
+
+ +
+
๐Ÿ”
+

Authentication

+
    +
  • Secure user registration and login
  • +
  • Supabase authentication integration
  • +
  • Row-level security policies
  • +
  • Session management
  • +
  • Password encryption
  • +
+
+ +
+
๐Ÿš€
+

Performance

+
    +
  • Optimized React Native components
  • +
  • Efficient state management with Context API
  • +
  • Smooth 60 FPS animations
  • +
  • Lazy loading and code splitting
  • +
  • Minimal bundle size
  • +
+
+
+
+
+ + +
+
+

System Architecture

+ +
+

+ TaskNexus follows a modern, scalable architecture pattern with clear + separation of concerns. The application is built using React Native + with Expo, leveraging TypeScript for type safety and Supabase for + backend services. +

+
+ +
+
+graph TB + subgraph "Client Layer" + A[Mobile App - iOS/Android] + B[Web App] + C[React Native Components] + end + subgraph "Application Layer" + D[Expo Router] + E[Context API State Management] + F[Task Context] + G[Theme Context] + end + subgraph "UI Components" + H[Home Screen] + I[Stats Screen] + J[Auth Screens] + K[Custom Tab Bar] + L[Chart Components] + end + subgraph "Backend Services" + M[Supabase Client] + N[Authentication Service] + O[Real-time Subscriptions] + P[PostgreSQL Database] + end + subgraph "Data Layer" + Q[Tasks Table] + R[Users Table] + S[Row Level Security] + end + A --> C + B --> C + C --> D + D --> E + E --> F + E --> G + F --> H + F --> I + G --> K + H --> M + I --> M + J --> N + M --> O + M --> N + N --> P + O --> P + P --> Q + P --> R + P --> S + style A fill:#4CAF50 + style B fill:#4CAF50 + style M fill:#3ECF8E + style P fill:#336791 + style E fill:#61DAFB +
+
+ +
+
+

Component Architecture

+
+graph LR + A[App Root] --> B[Layout] + B --> C[Theme Provider] + B --> D[Task Provider] + C --> E[Navigation] + D --> E + E --> F[Tab Screens] + F --> G[Home] + F --> H[Stats] + F --> I[Auth] + style A fill:#FF6B6B + style B fill:#4ECDC4 + style C fill:#45B7D1 + style D fill:#FFA07A + style E fill:#98D8C8 +
+
+ +
+

Data Flow

+
+sequenceDiagram + participant U as User + participant C as Component + participant Ctx as Context + participant S as Supabase + participant DB as Database + U->>C: Interact (Add Task) + C->>Ctx: Update State + Ctx->>S: API Call + S->>DB: Insert Data + DB->>S: Confirm + S->>Ctx: Real-time Update + Ctx->>C: Re-render + C->>U: UI Update +
+
+
+ +
+

Project Structure

+
Task-Manager-ReactNative/
+โ”œโ”€โ”€ ๐Ÿ“ฑ app/                    # Expo Router screens
+โ”‚   โ”œโ”€โ”€ _layout.tsx           # Root layout with providers
+โ”‚   โ”œโ”€โ”€ index.tsx             # Flash/Splash screen
+โ”‚   โ””โ”€โ”€ (tabs)/               # Tab-based navigation
+โ”‚       โ”œโ”€โ”€ home.tsx          # Task management screen
+โ”‚       โ”œโ”€โ”€ stats.tsx         # Analytics screen
+โ”‚       โ”œโ”€โ”€ login.tsx         # Authentication screen
+โ”‚       โ””โ”€โ”€ register.tsx      # Registration screen
+โ”œโ”€โ”€ ๐ŸŽจ components/            # Reusable components
+โ”‚   โ”œโ”€โ”€ Chart.tsx            # Chart visualizations
+โ”‚   โ”œโ”€โ”€ CustomTabBar.tsx     # Custom tab bar with theme toggle
+โ”‚   โ”œโ”€โ”€ TaskAddModal.tsx     # Task creation modal
+โ”‚   โ””โ”€โ”€ TaskItem.tsx         # Individual task component
+โ”œโ”€โ”€ ๐ŸŽฏ contexts/              # Global state management
+โ”‚   โ”œโ”€โ”€ TaskContext.tsx      # Task state & operations
+โ”‚   โ””โ”€โ”€ ThemeOverrideContext.tsx  # Theme management
+โ”œโ”€โ”€ ๐Ÿ”ง lib/                   # Utilities & configuration
+โ”‚   โ””โ”€โ”€ supabaseClient.ts    # Supabase initialization
+โ”œโ”€โ”€ ๐Ÿ’… styles/                # Component styles
+โ”‚   โ”œโ”€โ”€ HomeScreenStyles.ts
+โ”‚   โ”œโ”€โ”€ StatsScreenStyles.ts
+โ”‚   โ””โ”€โ”€ ...
+โ”œโ”€โ”€ ๐ŸŽญ constants/             # App constants
+โ”‚   โ””โ”€โ”€ Colors.ts            # Theme colors
+โ”œโ”€โ”€ ๐Ÿช hooks/                 # Custom React hooks
+โ”‚   โ””โ”€โ”€ usePrevious.ts       # Previous state hook
+โ”œโ”€โ”€ ๐Ÿ“ฆ types/                 # TypeScript definitions
+โ”‚   โ””โ”€โ”€ types.ts             # Shared types
+โ”œโ”€โ”€ ๐Ÿ—„๏ธ supabase/              # Database schema
+โ”‚   โ””โ”€โ”€ db.sql               # PostgreSQL schema
+โ”œโ”€โ”€ ๐Ÿงช __tests__/             # Test files
+โ”œโ”€โ”€ ๐Ÿณ Dockerfile             # Container configuration
+โ””โ”€โ”€ ๐Ÿ“ README.md              # Documentation
+
+
+
+ + +
+
+

App Gallery

+ +
+

+ ๐Ÿ“ฑ iOS Platform +

+
+
+ iOS Flash Screen +

Flash Screen

+
+
+ iOS Home Light +

Home - Light Mode

+
+
+ iOS Stats Light +

Stats - Light Mode

+
+
+ iOS Home Dark +

Home - Dark Mode

+
+
+ iOS Stats Dark +

Stats - Dark Mode

+
+
+
+ +
+

+ ๐Ÿค– Android Platform +

+
+
+ Android Flash Screen +

Flash Screen

+
+
+ Android Home Light +

Home - Light Mode

+
+
+ Android Stats Light +

Stats - Light Mode

+
+
+ Android Home Dark +

Home - Dark Mode

+
+
+ Android Stats Dark +

Stats - Dark Mode

+
+
+
+ +
+

+ ๐ŸŒ Web Platform +

+
+
+ Web Home Light +

Home - Light Mode

+
+
+ Web Stats Light +

Stats - Light Mode

+
+
+ Web Home Dark +

Home - Dark Mode

+
+
+ Web Stats Dark +

Stats - Dark Mode

+
+
+
+ +
+

+ โœจ Interactive Demos +

+
+
+ iOS Demo +

iOS User Experience

+
+
+ Android Demo +

Android User Experience

+
+
+
+ Real-time Sync Demo +

+ Real-time Synchronization Across Devices +

+
+
+ + +
+
+ + +
+
+

Technology Stack

+ +
+

Core Technologies

+
+
+ React Native +
+
+ Expo +
+
+ TypeScript +
+
+ Node.js +
+
+
+ +
+

Backend & Database

+
+
+ Supabase +
+
+ PostgreSQL +
+
+ WebSockets +
+
+ Ruby on Rails +
+
+
+ +
+

UI & Charts

+
+
+ React Native Paper +
+
+ Chart Kit +
+
+ Vector Icons +
+
+
+ +
+

DevOps & Deployment

+
+
+ Docker +
+
+ GitHub Actions +
+
+ AWS +
+
+ Vercel +
+
+
+ +
+

Testing & Quality

+
+
+ Jest +
+
+ Testing Library +
+
+ ESLint +
+
+ Prettier +
+
+
+ +
+
+

State Management

+

+ React Context API for global state management with TaskContext and + ThemeContext providers +

+
+
+

Navigation

+

+ Expo Router for file-based routing with nested layouts and tab + navigation +

+
+
+

Animations

+

+ React Native Reanimated for smooth 60 FPS animations and gesture + handling +

+
+
+

Real-time Updates

+

+ Supabase real-time subscriptions for instant synchronization + across devices +

+
+
+
+
+ + +
+
+

Installation & Setup

+ +
+
+
1
+
+

Prerequisites

+
    +
  • Node.js version 14 or above
  • +
  • + npm or Yarn package manager +
  • +
  • Expo CLI (install globally)
  • +
  • Android/iOS Emulator or Physical Device
  • +
  • Supabase Account for cloud sync
  • +
+
+
# Install Expo CLI globally
+npm install -g expo-cli
+
+
+
+ +
+
2
+
+

Clone the Repository

+
+
git clone https://github.com/hoangsonww/Task-Manager-ReactNative.git
+cd Task-Manager-ReactNative
+
+
+
+ +
+
3
+
+

Install Dependencies

+
+
# Using npm
+npm install
+
+# Or using Yarn
+yarn install
+
+
+
+ +
+
4
+
+

Configure Environment

+

+ Create a .env file in the root directory with your + Supabase credentials: +

+
+
EXPO_PUBLIC_SUPABASE_URL=your_supabase_url
+EXPO_PUBLIC_SUPABASE_ANON_KEY=your_supabase_anon_key
+
+
+
+ +
+
5
+
+

Set Up Database

+

+ Run the SQL schema from supabase/db.sql in your + Supabase project: +

+
+
-- Creates tasks table with row-level security
+-- Run this in your Supabase SQL editor
+
+
+
+ +
+
6
+
+

Run the App

+
+
# Start the Expo development server
+npm start
+
+# Or use Expo CLI directly
+npx expo start
+
+# Clear cache if needed
+npx expo start -c
+
+

+ Press a for Android, i for iOS, or + w for Web +

+
+
+
+ +
+
+

๐Ÿ’ก Pro Tip

+

+ Use the shell scripts in the shell/ directory for + common tasks: +

+
    +
  • ./shell/start.sh - Start the app
  • +
  • ./shell/format.sh - Format code
  • +
  • ./shell/reset.sh - Reset project state
  • +
+
+
+

โš ๏ธ Important

+

+ The web version may not display correctly on larger screens and + some features like drag-and-drop may have limited functionality on + web. +

+
+
+
+
+ + +
+
+

Documentation

+ +
+
+

๐Ÿ“š Usage Guide

+
    +
  • + Authentication: Register or login to access + your tasks +
  • +
  • + Add Tasks: Tap the "Add Task" button to create + new tasks +
  • +
  • + Reorder: Drag and drop tasks to adjust their + order +
  • +
  • + Complete: Tap the checkbox to mark tasks as + done +
  • +
  • Statistics: View charts in the Stats tab
  • +
  • + Theme: Toggle dark/light mode from the tab bar +
  • +
+
+ +
+

๐Ÿงช Testing

+
+
# Run all tests
+npm test
+
+# Watch mode
+npm run test:watch
+
+# Coverage report
+npm run test:coverage
+
+

+ Tests are located in the __tests__/ directory using + Jest and React Testing Library. +

+
+ +
+

๐Ÿณ Docker Support

+
+
# Build and run with Docker Compose
+docker-compose up --build
+
+# Stop containers
+docker-compose down
+
+

+ Note: Docker setup is optimized for the web version of the app. +

+
+ +
+

๐Ÿ“Š Database Schema

+
+

Tasks Table

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
ColumnTypeDescription
idUUIDPrimary key
user_idUUIDForeign key to auth.users
textTextTask description
colorTextTask color
due_dateTimestampDue date and time
completedBooleanCompletion status
+
+
+
+ +
+

Available Scripts

+
+
+ npm start +

Start the Expo development server

+
+
+ npm run android +

Start on Android emulator

+
+
+ npm run ios +

Start on iOS simulator

+
+
+ npm run web +

Start on web browser

+
+
+ npm run format +

Format code with Prettier

+
+
+ npm test +

Run test suite

+
+
+
+
+
+ + +
+
+

Contact & Support

+ +
+
+
๐Ÿ‘จโ€๐Ÿ’ป
+

Developer

+

Son Nguyen

+ sonnguyenhoang.com +
+ +
+
๐Ÿ“ง
+

Email

+ hoangson091104@gmail.com +
+ +
+
+ + + +
+

GitHub

+ @hoangsonww +
+ +
+
+ + + +
+

LinkedIn

+ Son Nguyen +
+
+ +
+

๐Ÿค Contribute

+

+ TaskNexus is open source and welcomes contributions! Feel free to: +

+
    +
  • + Report bugs or request features via + GitHub Issues +
  • +
  • Submit pull requests to improve the codebase
  • +
  • Share feedback and suggestions
  • +
  • Star the repository if you find it useful!
  • +
+
+ +
+

๐Ÿ“„ License

+

+ This project is licensed under the MIT License. See + the + LICENSE + file for details. +

+

+ Note: This project is for educational purposes. + Please credit the original author when using any part of this code. +

+
+
+
+ + + + + + + + + + diff --git a/packages/script.js b/packages/script.js new file mode 100644 index 0000000..c09fa0a --- /dev/null +++ b/packages/script.js @@ -0,0 +1,740 @@ +// ======================================== +// TaskNexus Wiki - Interactive Features +// ======================================== + +(function () { + "use strict"; + + // ======================================== + // Theme Management + // ======================================== + const themeToggle = document.getElementById("themeToggle"); + const themeIcon = document.querySelector(".theme-icon"); + const html = document.documentElement; + + // Initialize theme from localStorage or system preference + function initTheme() { + const savedTheme = localStorage.getItem("theme"); + const systemPrefersDark = window.matchMedia( + "(prefers-color-scheme: dark)", + ).matches; + const initialTheme = savedTheme || (systemPrefersDark ? "dark" : "light"); + + setTheme(initialTheme, false); + } + + // Set theme and update UI + function setTheme(theme, animate = true) { + html.setAttribute("data-theme", theme); + localStorage.setItem("theme", theme); + + // Update icon + themeIcon.textContent = theme === "dark" ? "โ˜€๏ธ" : "๐ŸŒ™"; + + // Add animation class + if (animate) { + document.body.style.transition = + "background-color 0.3s ease, color 0.3s ease"; + setTimeout(() => { + document.body.style.transition = ""; + }, 300); + } + } + + // Toggle theme + function toggleTheme() { + const currentTheme = html.getAttribute("data-theme"); + const newTheme = currentTheme === "dark" ? "light" : "dark"; + setTheme(newTheme); + + // Add rotation animation to icon + themeIcon.style.transform = "rotate(360deg)"; + setTimeout(() => { + themeIcon.style.transform = ""; + }, 300); + + // Re-render mermaid diagrams with new theme + setTimeout(() => { + reRenderMermaid(); + }, 350); + } + + // Event listener for theme toggle + if (themeToggle) { + themeToggle.addEventListener("click", toggleTheme); + } + + // Listen for system theme changes + window + .matchMedia("(prefers-color-scheme: dark)") + .addEventListener("change", (e) => { + if (!localStorage.getItem("theme")) { + setTheme(e.matches ? "dark" : "light"); + } + }); + + // ======================================== + // Mobile Menu Toggle + // ======================================== + const hamburgerMenu = document.getElementById("hamburgerMenu"); + const navCenter = document.querySelector(".nav-center"); + const navLinks = document.getElementById("navLinks"); + + if (hamburgerMenu && navCenter && navLinks) { + hamburgerMenu.addEventListener("click", function (e) { + e.stopPropagation(); + hamburgerMenu.classList.toggle("active"); + navCenter.classList.toggle("active"); + }); + + // Close menu when clicking on a link + navLinks.querySelectorAll("a").forEach((link) => { + link.addEventListener("click", function () { + hamburgerMenu.classList.remove("active"); + navCenter.classList.remove("active"); + }); + }); + + // Close menu when clicking outside + document.addEventListener("click", function (e) { + if ( + !hamburgerMenu.contains(e.target) && + !navCenter.contains(e.target) + ) { + hamburgerMenu.classList.remove("active"); + navCenter.classList.remove("active"); + } + }); + } + + // ======================================== + // Smooth Scrolling + // ======================================== + function initSmoothScroll() { + document.querySelectorAll('a[href^="#"]').forEach((anchor) => { + anchor.addEventListener("click", function (e) { + const href = this.getAttribute("href"); + + // Skip if it's just "#" + if (href === "#") return; + + e.preventDefault(); + const targetId = href.substring(1); + const target = document.getElementById(targetId); + + if (target) { + const navHeight = + document.querySelector(".navbar")?.offsetHeight || 0; + const targetPosition = target.offsetTop - navHeight - 20; + + window.scrollTo({ + top: targetPosition, + behavior: "smooth", + }); + } + }); + }); + } + + // ======================================== + // Back to Top Button + // ======================================== + const backToTopButton = document.getElementById("backToTop"); + + function handleScroll() { + if (window.pageYOffset > 300) { + backToTopButton.classList.add("visible"); + } else { + backToTopButton.classList.remove("visible"); + } + } + + function scrollToTop() { + window.scrollTo({ + top: 0, + behavior: "smooth", + }); + } + + if (backToTopButton) { + window.addEventListener("scroll", handleScroll); + backToTopButton.addEventListener("click", scrollToTop); + } + + // ======================================== + // Enhanced Navbar Scroll Effect + // ======================================== + const navbar = document.querySelector(".navbar"); + let lastScrollTop = 0; + let ticking = false; + + function handleNavbarScroll() { + const scrollTop = window.pageYOffset || document.documentElement.scrollTop; + + if (!ticking) { + window.requestAnimationFrame(() => { + // Add scrolled class for enhanced shadow + if (scrollTop > 20) { + navbar.classList.add("scrolled"); + } else { + navbar.classList.remove("scrolled"); + } + + lastScrollTop = scrollTop; + ticking = false; + }); + + ticking = true; + } + } + + if (navbar) { + window.addEventListener("scroll", handleNavbarScroll); + + // Initial check + handleNavbarScroll(); + } + + // ======================================== + // Responsive Layout Handler + // ======================================== + function handleResize() { + const hamburgerMenu = document.getElementById("hamburgerMenu"); + const navCenter = document.querySelector(".nav-center"); + + if (window.innerWidth > 768) { + // Desktop view - close mobile menu + if (hamburgerMenu) { + hamburgerMenu.classList.remove("active"); + } + if (navCenter) { + navCenter.classList.remove("active"); + } + } + } + + window.addEventListener("resize", handleResize); + handleResize(); // Initial check + + // ======================================== + // Lazy Loading Images + // ======================================== + function initLazyLoading() { + const images = document.querySelectorAll('img[loading="lazy"]'); + + if ("IntersectionObserver" in window) { + const imageObserver = new IntersectionObserver( + (entries, observer) => { + entries.forEach((entry) => { + if (entry.isIntersecting) { + const img = entry.target; + img.src = img.src; // Trigger load + img.classList.add("fade-in"); + observer.unobserve(img); + } + }); + }, + { + rootMargin: "50px", + }, + ); + + images.forEach((img) => imageObserver.observe(img)); + } + } + + // ======================================== + // Scroll Animations + // ======================================== + function initScrollAnimations() { + const elements = document.querySelectorAll( + ".overview-card, .feature-card, .screenshot-item, .tech-detail-card", + ); + + if ("IntersectionObserver" in window) { + const observer = new IntersectionObserver( + (entries) => { + entries.forEach((entry) => { + if (entry.isIntersecting) { + entry.target.classList.add("fade-in"); + observer.unobserve(entry.target); + } + }); + }, + { + threshold: 0.1, + rootMargin: "0px 0px -50px 0px", + }, + ); + + elements.forEach((el) => observer.observe(el)); + } + } + + // ======================================== + // Code Block Copy Functionality + // ======================================== + function initCodeCopy() { + document.querySelectorAll(".code-block").forEach((block) => { + // Create copy button + const copyButton = document.createElement("button"); + copyButton.className = "copy-button"; + copyButton.innerHTML = "๐Ÿ“‹ Copy"; + copyButton.setAttribute("aria-label", "Copy code to clipboard"); + + // Style the button + copyButton.style.cssText = ` + position: absolute; + top: 10px; + right: 10px; + padding: 0.5rem 1rem; + background-color: var(--primary-color); + color: var(--text-inverse); + border: none; + border-radius: 6px; + cursor: pointer; + font-size: 0.85rem; + font-weight: 600; + transition: all 0.2s ease; + opacity: 0; + `; + + // Make code block relative for positioning + block.style.position = "relative"; + + // Show button on hover + block.addEventListener("mouseenter", () => { + copyButton.style.opacity = "1"; + }); + + block.addEventListener("mouseleave", () => { + if (!copyButton.classList.contains("copied")) { + copyButton.style.opacity = "0"; + } + }); + + // Copy functionality + copyButton.addEventListener("click", async () => { + const code = block.querySelector("code").textContent; + + try { + await navigator.clipboard.writeText(code); + copyButton.innerHTML = "โœ“ Copied!"; + copyButton.classList.add("copied"); + + setTimeout(() => { + copyButton.innerHTML = "๐Ÿ“‹ Copy"; + copyButton.classList.remove("copied"); + }, 2000); + } catch (err) { + console.error("Failed to copy code:", err); + copyButton.innerHTML = "โœ— Failed"; + setTimeout(() => { + copyButton.innerHTML = "๐Ÿ“‹ Copy"; + }, 2000); + } + }); + + block.appendChild(copyButton); + }); + } + + // ======================================== + // Initialize Mermaid Diagrams + // ======================================== + let mermaidInitialized = false; + + function initMermaid() { + if (typeof mermaid !== "undefined") { + const theme = html.getAttribute("data-theme") || "light"; + + mermaid.initialize({ + startOnLoad: false, + theme: theme === "dark" ? "dark" : "default", + themeVariables: { + primaryColor: "#4CAF50", + primaryTextColor: "#fff", + primaryBorderColor: "#388E3C", + lineColor: "#2196F3", + secondaryColor: "#2196F3", + tertiaryColor: "#FF6B6B", + fontSize: "14px", + fontFamily: + '-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif', + }, + flowchart: { + useMaxWidth: true, + htmlLabels: true, + curve: "basis", + }, + sequence: { + useMaxWidth: true, + mirrorActors: true, + }, + }); + + renderMermaidDiagrams(); + mermaidInitialized = true; + } + } + + function renderMermaidDiagrams() { + if (typeof mermaid === "undefined") return; + + const mermaidElements = document.querySelectorAll('.mermaid'); + mermaidElements.forEach((element, index) => { + // Store original content + if (!element.dataset.originalContent) { + element.dataset.originalContent = element.textContent.trim(); + } + + // Clear previous rendering + element.innerHTML = element.dataset.originalContent; + element.removeAttribute('data-processed'); + + // Set unique ID for each diagram + element.id = `mermaid-diagram-${index}`; + }); + + // Render all diagrams + mermaid.run({ + querySelector: '.mermaid', + }).catch(err => { + console.error('Mermaid rendering error:', err); + }); + } + + function reRenderMermaid() { + if (mermaidInitialized && typeof mermaid !== "undefined") { + const theme = html.getAttribute("data-theme") || "light"; + + // Re-initialize with new theme + mermaid.initialize({ + startOnLoad: false, + theme: theme === "dark" ? "dark" : "default", + themeVariables: { + primaryColor: "#4CAF50", + primaryTextColor: "#fff", + primaryBorderColor: "#388E3C", + lineColor: "#2196F3", + secondaryColor: "#2196F3", + tertiaryColor: "#FF6B6B", + fontSize: "14px", + fontFamily: + '-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif', + }, + flowchart: { + useMaxWidth: true, + htmlLabels: true, + curve: "basis", + }, + sequence: { + useMaxWidth: true, + mirrorActors: true, + }, + }); + + // Re-render all diagrams + renderMermaidDiagrams(); + } + } + + + + // ======================================== + // Performance Monitoring + // ======================================== + function logPerformance() { + if (window.performance && window.performance.timing) { + const perfData = window.performance.timing; + const pageLoadTime = perfData.loadEventEnd - perfData.navigationStart; + console.log(`๐Ÿ“Š Page Load Time: ${pageLoadTime}ms`); + } + } + + // ======================================== + // Keyboard Navigation + // ======================================== + function initKeyboardNav() { + document.addEventListener("keydown", (e) => { + // Alt + T: Toggle theme + if (e.altKey && e.key === "t") { + e.preventDefault(); + toggleTheme(); + } + + // Alt + Arrow Up: Scroll to top + if (e.altKey && e.key === "ArrowUp") { + e.preventDefault(); + scrollToTop(); + } + + // Escape: Close mobile menu if open + if (e.key === "Escape") { + const hamburgerMenu = document.getElementById("hamburgerMenu"); + const navCenter = document.querySelector(".nav-center"); + if (navCenter && navCenter.classList.contains("active")) { + navCenter.classList.remove("active"); + if (hamburgerMenu) hamburgerMenu.classList.remove("active"); + } + } + }); + } + + // ======================================== + // Screenshot Modal (Image Viewer) + // ======================================== + function initImageModal() { + const images = document.querySelectorAll( + ".screenshot-item img, .demo-item img, .demo-item-full img", + ); + + // Create modal + const modal = document.createElement("div"); + modal.className = "image-modal"; + modal.style.cssText = ` + display: none; + position: fixed; + top: 0; + left: 0; + right: 0; + bottom: 0; + background-color: rgba(0, 0, 0, 0.9); + z-index: 9999; + justify-content: center; + align-items: center; + cursor: zoom-out; + `; + + const modalImg = document.createElement("img"); + modalImg.style.cssText = ` + max-width: 90%; + max-height: 90%; + object-fit: contain; + `; + + modal.appendChild(modalImg); + document.body.appendChild(modal); + + // Click to open modal + images.forEach((img) => { + img.style.cursor = "zoom-in"; + img.addEventListener("click", (e) => { + e.stopPropagation(); + modalImg.src = img.src; + modal.style.display = "flex"; + document.body.style.overflow = "hidden"; + }); + }); + + // Click to close modal + modal.addEventListener("click", () => { + modal.style.display = "none"; + document.body.style.overflow = ""; + }); + + // ESC to close modal + document.addEventListener("keydown", (e) => { + if (e.key === "Escape" && modal.style.display === "flex") { + modal.style.display = "none"; + document.body.style.overflow = ""; + } + }); + } + + // ======================================== + // Smooth Scroll Progress Indicator + // ======================================== + function initProgressIndicator() { + const progressBar = document.createElement("div"); + progressBar.className = "scroll-progress"; + progressBar.id = "scrollProgress"; + document.body.appendChild(progressBar); + + let ticking = false; + + function updateProgress() { + const windowHeight = + document.documentElement.scrollHeight - + document.documentElement.clientHeight; + const scrolled = (window.pageYOffset / windowHeight) * 100; + progressBar.style.width = Math.min(scrolled, 100) + "%"; + ticking = false; + } + + window.addEventListener("scroll", () => { + if (!ticking) { + window.requestAnimationFrame(updateProgress); + ticking = true; + } + }); + + // Initial update + updateProgress(); + } + + // ======================================== + // Active Navigation Link Highlighting + // ======================================== + function initActiveNavigation() { + const sections = document.querySelectorAll("section[id]"); + const navLinks = document.querySelectorAll('.nav-links a[href^="#"]'); + + if (sections.length === 0 || navLinks.length === 0) return; + + let ticking = false; + + function updateActiveLink() { + const scrollPosition = window.pageYOffset + 100; // Offset for navbar height + + let currentSection = ""; + + sections.forEach((section) => { + const sectionTop = section.offsetTop; + const sectionHeight = section.offsetHeight; + + if ( + scrollPosition >= sectionTop && + scrollPosition < sectionTop + sectionHeight + ) { + currentSection = section.getAttribute("id"); + } + }); + + navLinks.forEach((link) => { + link.classList.remove("active"); + const href = link.getAttribute("href"); + if (href === `#${currentSection}`) { + link.classList.add("active"); + } + }); + + ticking = false; + } + + window.addEventListener("scroll", () => { + if (!ticking) { + window.requestAnimationFrame(updateActiveLink); + ticking = true; + } + }); + + // Initial update + updateActiveLink(); + } + + // ======================================== + // Easter Egg: Konami Code + // ======================================== + function initKonamiCode() { + const konamiCode = [ + "ArrowUp", + "ArrowUp", + "ArrowDown", + "ArrowDown", + "ArrowLeft", + "ArrowRight", + "ArrowLeft", + "ArrowRight", + "b", + "a", + ]; + let konamiIndex = 0; + + document.addEventListener("keydown", (e) => { + if (e.key === konamiCode[konamiIndex]) { + konamiIndex++; + if (konamiIndex === konamiCode.length) { + activateEasterEgg(); + konamiIndex = 0; + } + } else { + konamiIndex = 0; + } + }); + } + + function activateEasterEgg() { + // Create confetti effect + const colors = ["#4CAF50", "#2196F3", "#FF6B6B", "#FFC107", "#9C27B0"]; + + for (let i = 0; i < 100; i++) { + const confetti = document.createElement("div"); + confetti.style.cssText = ` + position: fixed; + width: 10px; + height: 10px; + background-color: ${colors[Math.floor(Math.random() * colors.length)]}; + top: -10px; + left: ${Math.random() * 100}%; + animation: fall ${2 + Math.random() * 2}s linear forwards; + z-index: 9999; + border-radius: 50%; + `; + + document.body.appendChild(confetti); + + setTimeout(() => confetti.remove(), 4000); + } + + // Add animation keyframes + if (!document.getElementById("confetti-animation")) { + const style = document.createElement("style"); + style.id = "confetti-animation"; + style.textContent = ` + @keyframes fall { + to { + transform: translateY(100vh) rotate(360deg); + opacity: 0; + } + } + `; + document.head.appendChild(style); + } + + alert( + "๐ŸŽ‰ Congratulations! You found the secret! ๐ŸŽ‰\n\nYou're now a TaskNexus power user!", + ); + } + + // ======================================== + // Initialize All Features + // ======================================== + function init() { + console.log("๐Ÿš€ TaskNexus Wiki Initializing..."); + + initTheme(); + initSmoothScroll(); + initLazyLoading(); + initScrollAnimations(); + initCodeCopy(); + initMermaid(); + initKeyboardNav(); + initImageModal(); + initProgressIndicator(); + initActiveNavigation(); + initKonamiCode(); + + // Log performance after page load + window.addEventListener("load", () => { + logPerformance(); + console.log("โœ… TaskNexus Wiki Ready!"); + }); + } + + // Run initialization when DOM is ready + if (document.readyState === "loading") { + document.addEventListener("DOMContentLoaded", init); + } else { + init(); + } + + // ======================================== + // Expose useful functions globally + // ======================================== + window.TaskNexusWiki = { + toggleTheme, + scrollToTop, + version: "1.0.0", + }; +})(); diff --git a/packages/styles.css b/packages/styles.css new file mode 100644 index 0000000..b24ccdd --- /dev/null +++ b/packages/styles.css @@ -0,0 +1,1722 @@ +/* ======================================== + CSS Variables & Root Styles + ======================================== */ +:root { + /* Light Theme Colors */ + --primary-color: #4caf50; + --primary-dark: #388e3c; + --primary-light: #81c784; + --secondary-color: #2196f3; + --secondary-dark: #1976d2; + --accent-color: #ff6b6b; + --accent-dark: #e74c3c; + + /* Background Colors */ + --bg-primary: #ffffff; + --bg-secondary: #f5f7fa; + --bg-tertiary: #e8edf2; + --bg-card: #ffffff; + --bg-code: #f8f9fa; + + /* Text Colors */ + --text-primary: #2c3e50; + --text-secondary: #546e7a; + --text-tertiary: #78909c; + --text-inverse: #ffffff; + + /* Border Colors */ + --border-color: #e0e0e0; + --border-light: #f0f0f0; + + /* Shadow */ + --shadow-sm: 0 2px 4px rgba(0, 0, 0, 0.05); + --shadow-md: 0 4px 8px rgba(0, 0, 0, 0.1); + --shadow-lg: 0 8px 16px rgba(0, 0, 0, 0.15); + --shadow-xl: 0 12px 24px rgba(0, 0, 0, 0.2); + + /* Typography */ + --font-primary: + -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen", "Ubuntu", + "Cantarell", sans-serif; + --font-mono: + "SF Mono", Monaco, "Cascadia Code", "Roboto Mono", Consolas, monospace; + + /* Spacing */ + --spacing-xs: 0.5rem; + --spacing-sm: 1rem; + --spacing-md: 1.5rem; + --spacing-lg: 2rem; + --spacing-xl: 3rem; + + /* Border Radius */ + --radius-sm: 4px; + --radius-md: 8px; + --radius-lg: 12px; + --radius-xl: 16px; + --radius-full: 9999px; + + /* Transitions */ + --transition-fast: 150ms ease-in-out; + --transition-normal: 250ms ease-in-out; + --transition-slow: 400ms ease-in-out; +} + +/* Dark Theme */ +[data-theme="dark"] { + --primary-color: #66bb6a; + --primary-dark: #4caf50; + --primary-light: #81c784; + --secondary-color: #42a5f5; + --secondary-dark: #2196f3; + --accent-color: #ff7979; + --accent-dark: #ff6b6b; + + --bg-primary: #121212; + --bg-secondary: #1e1e1e; + --bg-tertiary: #2a2a2a; + --bg-card: #1e1e1e; + --bg-code: #0d1117; + + --text-primary: #e0e0e0; + --text-secondary: #b0b0b0; + --text-tertiary: #808080; + --text-inverse: #121212; + + --border-color: #333333; + --border-light: #2a2a2a; + + --shadow-sm: 0 2px 4px rgba(0, 0, 0, 0.3); + --shadow-md: 0 4px 8px rgba(0, 0, 0, 0.4); + --shadow-lg: 0 8px 16px rgba(0, 0, 0, 0.5); + --shadow-xl: 0 12px 24px rgba(0, 0, 0, 0.6); +} + +/* ======================================== + Base Styles + ======================================== */ +* { + margin: 0; + padding: 0; + box-sizing: border-box; +} + +html { + scroll-behavior: smooth; + font-size: 16px; +} + +body { + font-family: var(--font-primary); + background-color: var(--bg-primary); + color: var(--text-primary); + line-height: 1.6; + transition: + background-color var(--transition-normal), + color var(--transition-normal); + overflow-x: hidden; +} + +.container { + max-width: 1200px; + margin: 0 auto; + padding: 0 var(--spacing-md); +} + +a { + color: var(--secondary-color); + text-decoration: none; + transition: color var(--transition-fast); +} + +a:hover { + color: var(--secondary-dark); +} + +img { + max-width: 100%; + height: auto; + display: block; +} + +code { + font-family: var(--font-mono); + background-color: var(--bg-code); + padding: 0.2em 0.4em; + border-radius: var(--radius-sm); + font-size: 0.9em; +} + +kbd { + background-color: var(--bg-tertiary); + padding: 0.2em 0.5em; + border-radius: var(--radius-sm); + border: 1px solid var(--border-color); + font-family: var(--font-mono); + font-size: 0.85em; +} + +/* ======================================== + Navigation Bar - Enhanced + ======================================== */ +.navbar { + position: fixed; + top: 0; + left: 0; + right: 0; + background: rgba(255, 255, 255, 0.98); + backdrop-filter: blur(20px) saturate(180%); + -webkit-backdrop-filter: blur(20px) saturate(180%); + border-bottom: 1px solid rgba(0, 0, 0, 0.05); + z-index: 1000; + transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1); +} + +[data-theme="dark"] .navbar { + background: rgba(18, 18, 18, 0.98); + border-bottom: 1px solid rgba(255, 255, 255, 0.1); +} + +.navbar.scrolled { + box-shadow: 0 4px 20px rgba(0, 0, 0, 0.08); +} + +[data-theme="dark"] .navbar.scrolled { + box-shadow: 0 4px 20px rgba(0, 0, 0, 0.4); +} + +.navbar .container { + display: flex; + justify-content: space-between; + align-items: center; + padding: 0.75rem var(--spacing-md); + max-width: 1400px; + gap: 1rem; +} + +.nav-center { + display: flex; + justify-content: center; + flex: 1; +} + +.nav-brand { + display: flex; + align-items: center; + cursor: pointer; + transition: transform 0.2s ease; +} + +.nav-brand:hover { + transform: scale(1.02); +} + +.brand-name { + font-size: 1.35rem; + font-weight: 800; + letter-spacing: -0.5px; + background: linear-gradient( + 135deg, + var(--primary-color) 0%, + var(--secondary-color) 50%, + var(--accent-color) 100% + ); + -webkit-background-clip: text; + -webkit-text-fill-color: transparent; + background-clip: text; + background-size: 200% 200%; + animation: gradient-flow 3s ease infinite; +} + +@keyframes gradient-flow { + 0%, + 100% { + background-position: 0% 50%; + } + 50% { + background-position: 100% 50%; + } +} + +.nav-links { + display: flex; + list-style: none; + gap: 0.25rem; + align-items: center; + padding: 0; + margin: 0; +} + +.nav-links li { + margin: 0; +} + +.nav-links a { + position: relative; + color: var(--text-secondary); + font-weight: 600; + font-size: 0.875rem; + padding: 0.5rem 1rem; + border-radius: 8px; + transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1); + display: inline-flex; + align-items: center; + text-decoration: none; + overflow: hidden; +} + +.nav-links a::before { + content: ""; + position: absolute; + top: 0; + left: 0; + right: 0; + bottom: 0; + background: linear-gradient( + 135deg, + var(--primary-color), + var(--secondary-color) + ); + opacity: 0; + transition: opacity 0.2s ease; + border-radius: 8px; +} + +.nav-links a:hover { + color: var(--text-inverse); + transform: translateY(-1px); +} + +.nav-links a:hover::before { + opacity: 1; +} + +.nav-links a span { + position: relative; + z-index: 1; +} + +.nav-links a.active { + color: var(--text-inverse); + background: linear-gradient( + 135deg, + var(--primary-color), + var(--secondary-color) + ); + box-shadow: 0 2px 8px rgba(76, 175, 80, 0.3); +} + +.nav-links a.active::after { + content: ""; + position: absolute; + bottom: 4px; + left: 50%; + transform: translateX(-50%); + width: 4px; + height: 4px; + background: var(--text-inverse); + border-radius: 50%; + box-shadow: 0 0 8px rgba(255, 255, 255, 0.8); +} + +.theme-toggle { + position: relative; + background: transparent; + border: 2px solid var(--border-color); + padding: 0.5rem; + border-radius: 12px; + cursor: pointer; + font-size: 1.1rem; + transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1); + display: flex; + align-items: center; + justify-content: center; + width: 44px; + height: 44px; + margin-left: auto; + overflow: hidden; +} + +.theme-toggle::before { + content: ""; + position: absolute; + top: 50%; + left: 50%; + width: 0; + height: 0; + border-radius: 50%; + background: linear-gradient( + 135deg, + var(--primary-color), + var(--secondary-color) + ); + transform: translate(-50%, -50%); + transition: all 0.4s cubic-bezier(0.4, 0, 0.2, 1); +} + +.theme-toggle:hover::before { + width: 100%; + height: 100%; +} + +.theme-toggle:hover { + border-color: var(--primary-color); + transform: scale(1.05); +} + +.theme-toggle:active { + transform: scale(0.95); +} + +.theme-icon { + position: relative; + z-index: 1; + display: inline-block; + transition: transform 0.4s cubic-bezier(0.4, 0, 0.2, 1); +} + +.hamburger-menu { + display: none; + background: transparent; + border: 2px solid var(--border-color); + padding: 0.5rem; + border-radius: 12px; + cursor: pointer; + font-size: 1.1rem; + transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1); + align-items: center; + justify-content: center; + width: 50px; + height: 50px; + flex-direction: column; + gap: 5px; +} + +.hamburger-menu span { + width: 20px; + height: 2px; + background: var(--text-primary); + border-radius: 2px; + transition: all 0.3s ease; +} + +.hamburger-menu.active span:nth-child(1) { + transform: rotate(45deg) translate(5px, 5px); +} + +.hamburger-menu.active span:nth-child(2) { + opacity: 0; +} + +.hamburger-menu.active span:nth-child(3) { + transform: rotate(-45deg) translate(5px, -5px); +} + +.hamburger-menu:hover { + border-color: var(--primary-color); + transform: scale(1.05); +} + +.theme-toggle:hover .theme-icon { + transform: rotate(20deg) scale(1.1); +} + +/* ======================================== + Scroll Progress Bar + ======================================== */ +.scroll-progress { + position: fixed; + top: 0; + left: 0; + width: 0%; + height: 4px; + background: linear-gradient( + 90deg, + var(--primary-color), + var(--secondary-color), + var(--accent-color) + ); + z-index: 9999; + transition: width 0.1s ease-out; + box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2); + will-change: width; +} + +[data-theme="dark"] .scroll-progress { + box-shadow: 0 2px 8px rgba(76, 175, 80, 0.3); +} + +/* ======================================== + Hero Section + ======================================== */ +.hero { + position: relative; + min-height: 100vh; + display: flex; + align-items: center; + justify-content: center; + padding-top: 60px; + overflow: hidden; + background: linear-gradient( + 135deg, + var(--bg-primary) 0%, + var(--bg-secondary) 100% + ); +} + +.hero-particles { + position: absolute; + top: 0; + left: 0; + right: 0; + bottom: 0; + background-image: + radial-gradient( + circle at 20% 30%, + var(--primary-color) 1px, + transparent 1px + ), + radial-gradient( + circle at 80% 70%, + var(--secondary-color) 1px, + transparent 1px + ), + radial-gradient(circle at 40% 80%, var(--accent-color) 1px, transparent 1px); + background-size: + 50px 50px, + 80px 80px, + 60px 60px; + opacity: 0.1; + animation: float 20s ease-in-out infinite; +} + +@keyframes float { + 0%, + 100% { + transform: translateY(0px); + } + 50% { + transform: translateY(-20px); + } +} + +.hero-content { + position: relative; + z-index: 1; + text-align: center; + max-width: 900px; +} + +.hero-title { + font-size: clamp(2.5rem, 8vw, 5rem); + font-weight: 800; + margin-bottom: var(--spacing-md); + line-height: 1.1; +} + +.gradient-text { + background: linear-gradient( + 135deg, + var(--primary-color), + var(--secondary-color), + var(--accent-color) + ); + -webkit-background-clip: text; + -webkit-text-fill-color: transparent; + background-clip: text; + animation: gradient-shift 3s ease infinite; + background-size: 200% 200%; +} + +@keyframes gradient-shift { + 0%, + 100% { + background-position: 0% 50%; + } + 50% { + background-position: 100% 50%; + } +} + +.hero-subtitle { + font-size: clamp(1.2rem, 3vw, 1.8rem); + color: var(--text-secondary); + margin-bottom: var(--spacing-md); + font-weight: 600; +} + +.hero-description { + font-size: clamp(1rem, 2vw, 1.2rem); + color: var(--text-secondary); + margin-bottom: var(--spacing-xl); + max-width: 700px; + margin-left: auto; + margin-right: auto; +} + +.hero-stats { + display: flex; + justify-content: center; + gap: var(--spacing-xl); + margin-bottom: var(--spacing-xl); + flex-wrap: wrap; +} + +.stat-item { + display: flex; + flex-direction: column; + align-items: center; +} + +.stat-number { + font-size: 1.5rem; + font-weight: 700; + color: var(--primary-color); +} + +.stat-label { + font-size: 0.9rem; + color: var(--text-tertiary); +} + +.hero-buttons { + display: flex; + gap: var(--spacing-md); + justify-content: center; + flex-wrap: wrap; +} + +.btn { + display: inline-flex; + align-items: center; + gap: var(--spacing-xs); + padding: var(--spacing-sm) var(--spacing-lg); + border-radius: var(--radius-full); + font-weight: 600; + font-size: 1rem; + transition: all var(--transition-normal); + cursor: pointer; + border: 2px solid transparent; +} + +.btn-primary { + background-color: var(--primary-color); + color: var(--text-inverse); +} + +.btn-primary:hover { + background-color: var(--primary-dark); + transform: translateY(-2px); + box-shadow: var(--shadow-lg); +} + +.btn-secondary { + background-color: transparent; + color: var(--text-primary); + border-color: var(--border-color); +} + +.btn-secondary:hover { + background-color: var(--bg-secondary); + border-color: var(--primary-color); + color: var(--primary-color); + transform: translateY(-2px); +} + +.github-icon { + width: 20px; + height: 20px; +} + +/* ======================================== + Section Styles + ======================================== */ +.section { + padding: calc(var(--spacing-xl) + 20px) 0 var(--spacing-xl); + margin-top: 0; + scroll-margin-top: 60px; +} + +.section-alt { + background-color: var(--bg-secondary); +} + +.section-title { + font-size: clamp(2rem, 5vw, 3rem); + font-weight: 700; + text-align: center; + margin-bottom: var(--spacing-xl); + color: var(--text-primary); +} + +.subsection-title { + font-size: clamp(1.5rem, 3vw, 2rem); + font-weight: 600; + margin: var(--spacing-lg) 0 var(--spacing-md); + color: var(--text-primary); +} + +.section-intro { + max-width: 800px; + margin: 0 auto var(--spacing-xl); + text-align: center; + font-size: 1.1rem; + color: var(--text-secondary); + line-height: 1.8; +} + +/* ======================================== + Overview Section + ======================================== */ +.overview-grid { + display: grid; + grid-template-columns: repeat(auto-fit, minmax(250px, 1fr)); + gap: var(--spacing-lg); + margin-bottom: var(--spacing-xl); +} + +.overview-card { + background-color: var(--bg-card); + padding: var(--spacing-lg); + border-radius: var(--radius-lg); + box-shadow: var(--shadow-md); + transition: all var(--transition-normal); + border: 1px solid var(--border-light); +} + +.overview-card:hover { + transform: translateY(-5px); + box-shadow: var(--shadow-lg); +} + +.card-icon { + font-size: 3rem; + margin-bottom: var(--spacing-sm); +} + +.overview-card h3 { + font-size: 1.5rem; + margin-bottom: var(--spacing-sm); + color: var(--text-primary); +} + +.overview-card p { + color: var(--text-secondary); + line-height: 1.6; +} + +.branding-section { + background-color: var(--bg-card); + padding: var(--spacing-lg); + border-radius: var(--radius-lg); + border-left: 4px solid var(--primary-color); + box-shadow: var(--shadow-sm); +} + +.branding-section p { + color: var(--text-secondary); + line-height: 1.8; +} + +/* ======================================== + Features Section + ======================================== */ +.features-grid { + display: grid; + grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); + gap: var(--spacing-lg); +} + +.feature-card { + background-color: var(--bg-card); + padding: var(--spacing-lg); + border-radius: var(--radius-lg); + box-shadow: var(--shadow-md); + transition: all var(--transition-normal); + border: 1px solid var(--border-light); +} + +.feature-card:hover { + transform: translateY(-5px); + box-shadow: var(--shadow-lg); + border-color: var(--primary-color); +} + +.feature-icon { + font-size: 2.5rem; + margin-bottom: var(--spacing-sm); +} + +.feature-card h3 { + font-size: 1.5rem; + margin-bottom: var(--spacing-md); + color: var(--text-primary); +} + +.feature-list { + list-style: none; + padding: 0; +} + +.feature-list li { + padding: var(--spacing-xs) 0; + color: var(--text-secondary); + position: relative; + padding-left: var(--spacing-md); +} + +.feature-list li::before { + content: "โœ“"; + position: absolute; + left: 0; + color: var(--primary-color); + font-weight: bold; +} + +/* ======================================== + Architecture Section + ======================================== */ +.architecture-intro { + max-width: 800px; + margin: 0 auto var(--spacing-xl); + text-align: center; + color: var(--text-secondary); + font-size: 1.1rem; + line-height: 1.8; +} + +.mermaid-container { + background-color: var(--bg-card); + padding: var(--spacing-lg); + border-radius: var(--radius-lg); + box-shadow: var(--shadow-md); + margin-bottom: var(--spacing-xl); + overflow-x: auto; +} + +.mermaid { + display: flex; + justify-content: center; + min-height: 400px; +} + +.architecture-details { + display: grid; + grid-template-columns: repeat(auto-fit, minmax(400px, 1fr)); + gap: var(--spacing-lg); + margin-bottom: var(--spacing-xl); +} + +.arch-card { + background-color: var(--bg-card); + padding: var(--spacing-lg); + border-radius: var(--radius-lg); + box-shadow: var(--shadow-md); +} + +.arch-card h3 { + font-size: 1.5rem; + margin-bottom: var(--spacing-md); + color: var(--text-primary); +} + +.file-structure { + background-color: var(--bg-card); + padding: var(--spacing-lg); + border-radius: var(--radius-lg); + box-shadow: var(--shadow-md); + overflow-x: auto; +} + +.file-structure pre { + margin-top: var(--spacing-md); + background-color: var(--bg-code); + padding: var(--spacing-md); + border-radius: var(--radius-md); + overflow-x: auto; +} + +.file-structure code { + color: var(--text-secondary); + line-height: 1.8; + font-size: 0.9rem; +} + +/* ======================================== + Screenshots Gallery + ======================================== */ +.platform-section { + margin-bottom: var(--spacing-xl); +} + +.platform-icon { + font-size: 1.5rem; + margin-right: var(--spacing-xs); +} + +.screenshot-grid { + display: grid; + grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)); + gap: var(--spacing-md); + margin-top: var(--spacing-md); +} + +.web-grid { + grid-template-columns: repeat(auto-fill, minmax(300px, 1fr)); +} + +.screenshot-item { + background-color: var(--bg-card); + border-radius: var(--radius-lg); + overflow: hidden; + box-shadow: var(--shadow-md); + transition: all var(--transition-normal); +} + +.screenshot-item:hover { + transform: translateY(-5px); + box-shadow: var(--shadow-lg); +} + +.screenshot-item img { + width: 100%; + height: auto; + display: block; +} + +.screenshot-caption { + padding: var(--spacing-sm); + text-align: center; + font-size: 0.9rem; + color: var(--text-secondary); + font-weight: 500; +} + +.demo-grid { + display: grid; + grid-template-columns: repeat(auto-fit, minmax(400px, 1fr)); + gap: var(--spacing-lg); + margin-top: var(--spacing-md); +} + +.demo-item { + background-color: var(--bg-card); + border-radius: var(--radius-lg); + overflow: hidden; + box-shadow: var(--shadow-md); +} + +.demo-item-full { + background-color: var(--bg-card); + border-radius: var(--radius-lg); + overflow: hidden; + box-shadow: var(--shadow-md); + margin-top: var(--spacing-lg); +} + +.demo-item img, +.demo-item-full img { + width: 100%; + height: auto; + display: block; +} + +.gallery-note { + background-color: var(--bg-card); + padding: var(--spacing-md); + border-radius: var(--radius-md); + border-left: 4px solid var(--accent-color); + margin-top: var(--spacing-xl); +} + +.gallery-note p { + color: var(--text-secondary); + line-height: 1.6; +} + +/* ======================================== + Tech Stack Section + ======================================== */ +.tech-category { + margin-bottom: var(--spacing-xl); +} + +.tech-category-title { + font-size: 1.5rem; + margin-bottom: var(--spacing-md); + color: var(--text-primary); + font-weight: 600; +} + +.tech-grid { + display: grid; + grid-template-columns: repeat(auto-fill, minmax(250px, 1fr)); + gap: var(--spacing-md); +} + +.tech-badge { + display: flex; + justify-content: center; + align-items: center; + padding: 0.5rem; + min-height: 50px; +} + +.tech-badge img { + width: auto; + height: 28px; + max-width: 140px; + object-fit: contain; + transition: transform 0.2s ease; +} + +.tech-badge:hover img { + transform: scale(1.05); +} + +.tech-details { + display: grid; + grid-template-columns: repeat(auto-fit, minmax(250px, 1fr)); + gap: var(--spacing-md); + margin-top: var(--spacing-xl); +} + +.tech-detail-card { + background-color: var(--bg-card); + padding: var(--spacing-md); + border-radius: var(--radius-lg); + box-shadow: var(--shadow-sm); + border: 1px solid var(--border-light); +} + +.tech-detail-card h4 { + font-size: 1.2rem; + margin-bottom: var(--spacing-sm); + color: var(--primary-color); +} + +.tech-detail-card p { + color: var(--text-secondary); + line-height: 1.6; +} + +/* ======================================== + Installation Section + ======================================== */ +.install-steps { + max-width: 900px; + margin: 0 auto; +} + +.install-step { + display: flex; + gap: var(--spacing-md); + margin-bottom: var(--spacing-xl); + background-color: var(--bg-card); + padding: var(--spacing-lg); + border-radius: var(--radius-lg); + box-shadow: var(--shadow-md); +} + +.step-number { + flex-shrink: 0; + width: 50px; + height: 50px; + background: linear-gradient( + 135deg, + var(--primary-color), + var(--secondary-color) + ); + color: var(--text-inverse); + border-radius: var(--radius-full); + display: flex; + align-items: center; + justify-content: center; + font-size: 1.5rem; + font-weight: 700; +} + +.step-content { + flex: 1; +} + +.step-content h3 { + font-size: 1.5rem; + margin-bottom: var(--spacing-sm); + color: var(--text-primary); +} + +.step-content ul { + margin: var(--spacing-sm) 0; + padding-left: var(--spacing-md); + color: var(--text-secondary); +} + +.step-content li { + margin-bottom: var(--spacing-xs); +} + +.code-block { + background-color: var(--bg-code); + border-radius: var(--radius-md); + overflow: hidden; + margin: var(--spacing-md) 0; +} + +.code-block pre { + margin: 0; + padding: var(--spacing-md); + overflow-x: auto; +} + +.code-block code { + background-color: transparent; + padding: 0; + color: var(--text-secondary); + font-size: 0.9rem; + line-height: 1.6; +} + +.step-note { + margin-top: var(--spacing-sm); + padding: var(--spacing-sm); + background-color: var(--bg-secondary); + border-radius: var(--radius-md); + font-size: 0.9rem; + color: var(--text-secondary); +} + +.install-notes { + display: grid; + grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); + gap: var(--spacing-md); + margin-top: var(--spacing-xl); +} + +.note-card { + padding: var(--spacing-md); + border-radius: var(--radius-lg); + box-shadow: var(--shadow-sm); +} + +.note-card h4 { + font-size: 1.2rem; + margin-bottom: var(--spacing-sm); +} + +.note-tip { + background-color: var(--bg-card); + border-left: 4px solid var(--primary-color); +} + +.note-warning { + background-color: var(--bg-card); + border-left: 4px solid var(--accent-color); +} + +.note-card ul { + margin-top: var(--spacing-sm); + padding-left: var(--spacing-md); + color: var(--text-secondary); +} + +/* ======================================== + Documentation Section + ======================================== */ +.doc-grid { + display: grid; + grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); + gap: var(--spacing-lg); + margin-bottom: var(--spacing-xl); +} + +.doc-card { + background-color: var(--bg-card); + padding: var(--spacing-lg); + border-radius: var(--radius-lg); + box-shadow: var(--shadow-md); + border: 1px solid var(--border-light); +} + +.doc-card h3 { + font-size: 1.5rem; + margin-bottom: var(--spacing-md); + color: var(--text-primary); +} + +.doc-card ul { + list-style: none; + padding: 0; +} + +.doc-card li { + padding: var(--spacing-xs) 0; + color: var(--text-secondary); + line-height: 1.6; +} + +.doc-card p { + color: var(--text-secondary); + line-height: 1.6; + margin-top: var(--spacing-sm); +} + +.schema-table { + margin-top: var(--spacing-md); +} + +.schema-table h4 { + font-size: 1.2rem; + margin-bottom: var(--spacing-sm); + color: var(--primary-color); +} + +.schema-table table { + width: 100%; + border-collapse: collapse; + margin-top: var(--spacing-sm); +} + +.schema-table th, +.schema-table td { + padding: var(--spacing-xs) var(--spacing-sm); + text-align: left; + border-bottom: 1px solid var(--border-color); +} + +.schema-table th { + background-color: var(--bg-secondary); + font-weight: 600; + color: var(--text-primary); +} + +.schema-table td { + color: var(--text-secondary); +} + +.api-section { + margin-top: var(--spacing-xl); +} + +.scripts-grid { + display: grid; + grid-template-columns: repeat(auto-fill, minmax(250px, 1fr)); + gap: var(--spacing-md); + margin-top: var(--spacing-md); +} + +.script-item { + background-color: var(--bg-card); + padding: var(--spacing-md); + border-radius: var(--radius-md); + box-shadow: var(--shadow-sm); + border: 1px solid var(--border-light); + transition: all var(--transition-fast); +} + +.script-item:hover { + border-color: var(--primary-color); + box-shadow: var(--shadow-md); +} + +.script-item code { + display: block; + margin-bottom: var(--spacing-xs); + font-size: 1rem; + color: var(--primary-color); +} + +.script-item p { + color: var(--text-secondary); + font-size: 0.9rem; + margin: 0; +} + +/* ======================================== + Contact Section + ======================================== */ +.contact-grid { + display: grid; + grid-template-columns: repeat(auto-fit, minmax(250px, 1fr)); + gap: var(--spacing-lg); + margin-bottom: var(--spacing-xl); +} + +.contact-card { + background-color: var(--bg-card); + padding: var(--spacing-lg); + border-radius: var(--radius-lg); + box-shadow: var(--shadow-md); + text-align: center; + transition: all var(--transition-normal); +} + +.contact-card:hover { + transform: translateY(-5px); + box-shadow: var(--shadow-lg); +} + +.contact-icon { + font-size: 3rem; + margin-bottom: var(--spacing-sm); + color: var(--primary-color); +} + +.contact-card h3 { + font-size: 1.3rem; + margin-bottom: var(--spacing-sm); + color: var(--text-primary); +} + +.contact-name { + font-weight: 600; + color: var(--text-primary); + margin-bottom: var(--spacing-xs); +} + +.contact-link { + color: var(--secondary-color); + font-weight: 500; +} + +.contact-link:hover { + color: var(--secondary-dark); + text-decoration: underline; +} + +.contribute-section { + background-color: var(--bg-card); + padding: var(--spacing-lg); + border-radius: var(--radius-lg); + box-shadow: var(--shadow-md); + margin-bottom: var(--spacing-xl); +} + +.contribute-section h3 { + font-size: 1.8rem; + margin-bottom: var(--spacing-md); + color: var(--text-primary); +} + +.contribute-section p { + color: var(--text-secondary); + line-height: 1.8; + margin-bottom: var(--spacing-sm); +} + +.contribute-section ul { + padding-left: var(--spacing-lg); + color: var(--text-secondary); +} + +.contribute-section li { + margin-bottom: var(--spacing-xs); + line-height: 1.6; +} + +.license-section { + background-color: var(--bg-card); + padding: var(--spacing-lg); + border-radius: var(--radius-lg); + box-shadow: var(--shadow-md); + border-left: 4px solid var(--primary-color); +} + +.license-section h3 { + font-size: 1.5rem; + margin-bottom: var(--spacing-md); + color: var(--text-primary); +} + +.license-section p { + color: var(--text-secondary); + line-height: 1.8; + margin-bottom: var(--spacing-sm); +} + +.license-notice { + margin-top: var(--spacing-md); + padding: var(--spacing-sm); + background-color: var(--bg-secondary); + border-radius: var(--radius-md); + font-size: 0.9rem; +} + +/* ======================================== + Footer + ======================================== */ +.footer { + background-color: var(--bg-card); + border-top: 1px solid var(--border-color); + padding: var(--spacing-xl) 0 var(--spacing-md); + margin-top: var(--spacing-xl); +} + +.footer-content { + display: grid; + grid-template-columns: 1fr 2fr; + gap: var(--spacing-xl); + margin-bottom: var(--spacing-lg); +} + +.footer-brand { + display: flex; + flex-direction: column; + gap: var(--spacing-sm); +} + +.footer-logo { + width: 60px; + height: 60px; + border-radius: var(--radius-md); +} + +.footer-brand-name { + font-size: 2rem; + font-weight: 800; + margin: 0; + letter-spacing: -0.5px; + line-height: 1.2; +} + +.footer-tagline { + color: var(--text-secondary); + font-size: 0.9rem; +} + +.footer-links { + display: grid; + grid-template-columns: repeat(3, 1fr); + gap: var(--spacing-lg); +} + +.footer-column h4 { + font-size: 1.1rem; + margin-bottom: var(--spacing-sm); + color: var(--text-primary); +} + +.footer-column ul { + list-style: none; + padding: 0; +} + +.footer-column li { + margin-bottom: var(--spacing-xs); +} + +.footer-column a { + color: var(--text-secondary); + font-size: 0.9rem; +} + +.footer-column a:hover { + color: var(--primary-color); +} + +.footer-bottom { + text-align: center; + padding-top: var(--spacing-md); + border-top: 1px solid var(--border-light); +} + +.footer-bottom p { + color: var(--text-tertiary); + font-size: 0.9rem; + margin-bottom: var(--spacing-xs); +} + +.footer-note { + font-style: italic; +} + +/* ======================================== + Back to Top Button + ======================================== */ +.back-to-top { + position: fixed; + bottom: 30px; + right: 30px; + width: 50px; + height: 50px; + background-color: var(--primary-color); + color: var(--text-inverse); + border: none; + border-radius: var(--radius-full); + cursor: pointer; + display: none; + align-items: center; + justify-content: center; + box-shadow: var(--shadow-lg); + transition: all var(--transition-normal); + z-index: 999; +} + +.back-to-top:hover { + background-color: var(--primary-dark); + transform: translateY(-5px); +} + +.back-to-top.visible { + display: flex; +} + +.back-to-top svg { + width: 24px; + height: 24px; +} + +/* ======================================== + Responsive Design + ======================================== */ +@media (max-width: 1024px) { + .navbar .container { + padding: 0.6rem var(--spacing-md); + } + + .nav-links { + gap: 0.15rem; + } + + .nav-links a { + padding: 0.4rem 0.7rem; + font-size: 0.8rem; + } + + .brand-name { + font-size: 1.1rem; + } + + .footer-content { + grid-template-columns: 1fr; + } + + .footer-links { + grid-template-columns: repeat(2, 1fr); + } +} + +@media (max-width: 768px) { + html { + font-size: 14px; + } + + .navbar .container { + flex-wrap: nowrap; + padding: 0.5rem var(--spacing-sm); + position: relative; + } + + .nav-brand { + flex: 0 0 auto; + } + + .brand-name { + font-size: 1.5rem; + } + + .nav-center { + position: fixed; + top: 58px; + left: 0; + right: 0; + background: var(--bg-primary); + box-shadow: var(--shadow-lg); + border-top: 1px solid var(--border-color); + max-height: 0; + overflow: hidden; + transition: max-height 0.3s ease-in-out; + z-index: 998; + } + + .nav-center.active { + max-height: 500px; + } + + .nav-links { + flex-direction: column; + gap: 0; + width: 100%; + padding: 0; + } + + .nav-links li { + width: 100%; + border-bottom: 1px solid var(--border-light); + } + + .nav-links li:last-child { + border-bottom: none; + } + + .nav-links a { + font-size: 0.95rem; + padding: 1rem 1.25rem; + width: 100%; + text-align: left; + border-radius: 0; + display: block; + } + + .hamburger-menu { + display: flex; + margin-left: auto; + flex-shrink: 0; + } + + .theme-toggle { + width: 50px; + height: 50px; + font-size: 1.2rem; + margin-left: 0.5rem; + flex-shrink: 0; + } + + .hero { + min-height: auto; + padding: calc(var(--spacing-xl) + 80px) 0 var(--spacing-xl); + } + + .hero-stats { + flex-direction: column; + gap: var(--spacing-md); + } + + .hero-buttons { + flex-direction: column; + width: 100%; + max-width: 300px; + margin: 0 auto; + } + + .btn { + width: 100%; + justify-content: center; + } + + .overview-grid, + .features-grid, + .tech-grid { + grid-template-columns: 1fr; + } + + .screenshot-grid { + grid-template-columns: repeat(2, 1fr); + } + + .demo-grid { + grid-template-columns: 1fr; + } + + .architecture-details { + grid-template-columns: 1fr; + } + + .install-step { + flex-direction: column; + } + + .footer-links { + grid-template-columns: 1fr; + } + + .back-to-top { + bottom: 20px; + right: 20px; + width: 40px; + height: 40px; + } +} + +@media (max-width: 480px) { + .container { + padding: 0 var(--spacing-sm); + } + + .nav-links { + font-size: 0.8rem; + } + + .screenshot-grid { + grid-template-columns: 1fr; + } + + .tech-grid { + grid-template-columns: 1fr; + } + + .section { + padding: var(--spacing-lg) 0; + } +} + +/* ======================================== + Utility Classes + ======================================== */ +.text-center { + text-align: center; +} + +.mt-1 { + margin-top: var(--spacing-xs); +} +.mt-2 { + margin-top: var(--spacing-sm); +} +.mt-3 { + margin-top: var(--spacing-md); +} +.mt-4 { + margin-top: var(--spacing-lg); +} + +.mb-1 { + margin-bottom: var(--spacing-xs); +} +.mb-2 { + margin-bottom: var(--spacing-sm); +} +.mb-3 { + margin-bottom: var(--spacing-md); +} +.mb-4 { + margin-bottom: var(--spacing-lg); +} + +/* ======================================== + Animations + ======================================== */ +@keyframes fadeIn { + from { + opacity: 0; + transform: translateY(20px); + } + to { + opacity: 1; + transform: translateY(0); + } +} + +.fade-in { + animation: fadeIn 0.6s ease-out; +} + +/* ======================================== + Print Styles + ======================================== */ +@media print { + .navbar, + .theme-toggle, + .back-to-top, + .hero-buttons { + display: none; + } + + body { + background: white; + color: black; + } + + .section { + page-break-inside: avoid; + } +} diff --git a/serve-wiki.sh b/serve-wiki.sh new file mode 100755 index 0000000..4d360b0 --- /dev/null +++ b/serve-wiki.sh @@ -0,0 +1,49 @@ +#!/bin/bash + +# ======================================== +# TaskNexus Wiki Server Script +# ======================================== + +echo "๐Ÿš€ Starting TaskNexus Wiki Server..." +echo "" + +# Check if Python 3 is available +if command -v python3 &> /dev/null; then + echo "โœ… Python 3 detected" + echo "๐Ÿ“ก Starting HTTP server on http://localhost:8000" + echo "" + echo "๐Ÿ‘‰ Press Ctrl+C to stop the server" + echo "๐Ÿ‘‰ Open http://localhost:8000 in your browser" + echo "" + + # Start Python HTTP server + python3 -m http.server 8000 + +elif command -v python &> /dev/null; then + echo "โœ… Python detected" + echo "๐Ÿ“ก Starting HTTP server on http://localhost:8000" + echo "" + echo "๐Ÿ‘‰ Press Ctrl+C to stop the server" + echo "๐Ÿ‘‰ Open http://localhost:8000 in your browser" + echo "" + + # Start Python 2 HTTP server (fallback) + python -m SimpleHTTPServer 8000 + +else + echo "โŒ Python is not installed!" + echo "" + echo "Please install Python 3 or use an alternative:" + echo "" + echo "Option 1 - Install Python:" + echo " brew install python3" + echo "" + echo "Option 2 - Use Node.js http-server:" + echo " npm install -g http-server" + echo " http-server -p 8000" + echo "" + echo "Option 3 - Open directly in browser:" + echo " open index.html" + echo "" + exit 1 +fi