chore: Update Tailwind CSS and dependencies
- Downgraded Tailwind CSS to version 3.4.17 for compatibility. - Updated various dependencies to resolve version conflicts and ensure smooth operation. - Added missing types for Node.js to enhance type safety. - Improved the theming system using CSS custom properties (variables) for better customization and dark mode support. - Refactored styles in `app.css` to improve maintainability and readability. Updated the color palette to enhance the user experience. - Updated the PostCSS configuration to use the new Tailwind CSS version. - Updated component styles to utilize the new theming system.
This commit is contained in:
parent
da0ced9b4a
commit
f22e9faae2
@ -21,7 +21,7 @@
|
||||
"postcss": "^8.5.3",
|
||||
"svelte": "^5.28.1",
|
||||
"svelte-check": "^4.1.6",
|
||||
"tailwindcss": "^4.1.6",
|
||||
"tailwindcss": "^3.4.17",
|
||||
"typescript": "~5.8.3",
|
||||
"vite": "^6.3.5"
|
||||
},
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,6 +1,6 @@
|
||||
export default {
|
||||
plugins: {
|
||||
'@tailwindcss/postcss': {},
|
||||
tailwindcss: {},
|
||||
autoprefixer: {},
|
||||
},
|
||||
}
|
||||
|
108
sweb/src/app.css
108
sweb/src/app.css
@ -1,11 +1,115 @@
|
||||
@import "tailwindcss";
|
||||
@tailwind base;
|
||||
@tailwind components;
|
||||
@tailwind utilities;
|
||||
|
||||
|
||||
@layer base {
|
||||
:root {
|
||||
/* Primary color (blue) */
|
||||
--color-primary-50: 239 246 255;
|
||||
/* blue-50 */
|
||||
--color-primary-100: 219 234 254;
|
||||
/* blue-100 */
|
||||
--color-primary-200: 191 219 254;
|
||||
/* blue-200 */
|
||||
--color-primary-300: 147 197 253;
|
||||
/* blue-300 */
|
||||
--color-primary-400: 96 165 250;
|
||||
/* blue-400 */
|
||||
--color-primary-500: 59 130 246;
|
||||
/* blue-500 */
|
||||
--color-primary-600: 37 99 235;
|
||||
/* blue-600 */
|
||||
--color-primary-700: 29 78 216;
|
||||
/* blue-700 */
|
||||
--color-primary-800: 30 64 175;
|
||||
/* blue-800 */
|
||||
--color-primary-900: 30 58 138;
|
||||
/* blue-900 */
|
||||
|
||||
/* Background colors */
|
||||
--color-background: 249 250 251;
|
||||
/* gray-50 */
|
||||
--color-background-secondary: 255 255 255;
|
||||
/* white */
|
||||
|
||||
/* Text colors */
|
||||
--color-text: 17 24 39;
|
||||
/* gray-900 */
|
||||
--color-text-secondary: 55 65 81;
|
||||
/* gray-700 */
|
||||
--color-text-muted: 107 114 128;
|
||||
/* gray-500 */
|
||||
|
||||
/* Border colors */
|
||||
--color-border: 229 231 235;
|
||||
/* gray-200 */
|
||||
--color-border-secondary: 209 213 219;
|
||||
/* gray-300 */
|
||||
}
|
||||
|
||||
.dark {
|
||||
/* Primary color (blue) - slightly adjusted for dark mode */
|
||||
--color-primary-50: 30 58 138;
|
||||
/* blue-900 */
|
||||
--color-primary-100: 30 64 175;
|
||||
/* blue-800 */
|
||||
--color-primary-200: 29 78 216;
|
||||
/* blue-700 */
|
||||
--color-primary-300: 37 99 235;
|
||||
/* blue-600 */
|
||||
--color-primary-400: 59 130 246;
|
||||
/* blue-500 */
|
||||
--color-primary-500: 96 165 250;
|
||||
/* blue-400 */
|
||||
--color-primary-600: 147 197 253;
|
||||
/* blue-300 */
|
||||
--color-primary-700: 191 219 254;
|
||||
/* blue-200 */
|
||||
--color-primary-800: 219 234 254;
|
||||
/* blue-100 */
|
||||
--color-primary-900: 239 246 255;
|
||||
/* blue-50 */
|
||||
|
||||
/* Background colors */
|
||||
--color-background: 17 24 39;
|
||||
/* gray-900 */
|
||||
--color-background-secondary: 31 41 55;
|
||||
/* gray-800 */
|
||||
|
||||
/* Text colors */
|
||||
--color-text: 249 250 251;
|
||||
/* gray-50 */
|
||||
--color-text-secondary: 229 231 235;
|
||||
/* gray-200 */
|
||||
--color-text-muted: 156 163 175;
|
||||
/* gray-400 */
|
||||
|
||||
/* Border colors */
|
||||
--color-border: 55 65 81;
|
||||
/* gray-700 */
|
||||
--color-border-secondary: 75 85 99;
|
||||
/* gray-600 */
|
||||
}
|
||||
|
||||
body {
|
||||
font-family: system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif;
|
||||
@apply bg-background text-text;
|
||||
}
|
||||
|
||||
/* Add utility classes for components */
|
||||
.btn {
|
||||
@apply inline-flex items-center justify-center rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary-500 focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50;
|
||||
}
|
||||
|
||||
.btn-primary {
|
||||
@apply bg-primary-600 text-white hover:bg-primary-700;
|
||||
}
|
||||
|
||||
.btn-secondary {
|
||||
@apply bg-background-secondary text-text border border-border hover:bg-background hover:text-text-secondary;
|
||||
}
|
||||
|
||||
.btn-ghost {
|
||||
@apply hover:bg-background-secondary hover:text-text-secondary;
|
||||
}
|
||||
}
|
@ -3,7 +3,7 @@
|
||||
</script>
|
||||
|
||||
<footer
|
||||
class="bg-gray-100 border-t border-gray-200 py-4 sm:py-6 px-3 sm:px-4 w-full mt-auto"
|
||||
class="bg-background-secondary border-t border-border py-4 sm:py-6 px-3 sm:px-4 w-full mt-auto"
|
||||
>
|
||||
<div class="container mx-auto max-w-6xl">
|
||||
<div
|
||||
@ -11,8 +11,10 @@
|
||||
>
|
||||
<!-- Logo and tagline -->
|
||||
<div class="text-center sm:text-left">
|
||||
<div class="text-lg font-semibold text-blue-800">SecureWeb</div>
|
||||
<p class="text-gray-600 text-sm mt-1">
|
||||
<div class="text-lg font-semibold text-primary-600">
|
||||
SecureWeb
|
||||
</div>
|
||||
<p class="text-text-secondary text-sm mt-1">
|
||||
Secure and reliable web solutions
|
||||
</p>
|
||||
</div>
|
||||
@ -23,22 +25,22 @@
|
||||
>
|
||||
<a
|
||||
href="/"
|
||||
class="text-gray-600 hover:text-blue-800 transition-colors text-sm sm:text-base"
|
||||
class="text-text-secondary hover:text-primary-600 transition-colors text-sm sm:text-base"
|
||||
>Home</a
|
||||
>
|
||||
<a
|
||||
href="/about"
|
||||
class="text-gray-600 hover:text-blue-800 transition-colors text-sm sm:text-base"
|
||||
class="text-text-secondary hover:text-primary-600 transition-colors text-sm sm:text-base"
|
||||
>About</a
|
||||
>
|
||||
<a
|
||||
href="/services"
|
||||
class="text-gray-600 hover:text-blue-800 transition-colors text-sm sm:text-base"
|
||||
class="text-text-secondary hover:text-primary-600 transition-colors text-sm sm:text-base"
|
||||
>Services</a
|
||||
>
|
||||
<a
|
||||
href="/contact"
|
||||
class="text-gray-600 hover:text-blue-800 transition-colors text-sm sm:text-base"
|
||||
class="text-text-secondary hover:text-primary-600 transition-colors text-sm sm:text-base"
|
||||
>Contact</a
|
||||
>
|
||||
</div>
|
||||
@ -48,7 +50,7 @@
|
||||
<a
|
||||
href="/twitter"
|
||||
aria-label="Twitter"
|
||||
class="text-gray-500 hover:text-blue-800"
|
||||
class="text-text-muted hover:text-primary-600"
|
||||
>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
@ -64,7 +66,7 @@
|
||||
<a
|
||||
href="/github"
|
||||
aria-label="GitHub"
|
||||
class="text-gray-500 hover:text-blue-800"
|
||||
class="text-text-muted hover:text-primary-600"
|
||||
>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
@ -80,7 +82,7 @@
|
||||
<a
|
||||
href="/linkedin"
|
||||
aria-label="LinkedIn"
|
||||
class="text-gray-500 hover:text-blue-800"
|
||||
class="text-text-muted hover:text-primary-600"
|
||||
>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
@ -97,7 +99,7 @@
|
||||
</div>
|
||||
|
||||
<div
|
||||
class="border-t border-gray-200 mt-4 sm:mt-6 pt-4 sm:pt-6 text-center text-gray-500 text-xs sm:text-sm"
|
||||
class="border-t border-border mt-4 sm:mt-6 pt-4 sm:pt-6 text-center text-text-muted text-xs sm:text-sm"
|
||||
>
|
||||
<p>
|
||||
© {new Date().getFullYear()} SecureWeb. All rights reserved.
|
||||
|
@ -8,10 +8,10 @@
|
||||
$: actualPath = contentPath || "introduction/introduction";
|
||||
</script>
|
||||
|
||||
<div class="py-4 sm:py-6 md:py-8 px-3 sm:px-4 max-w-7xl mx-auto">
|
||||
<div class="">
|
||||
{#if contentPath}
|
||||
<div
|
||||
class="bg-white rounded-lg shadow-sm p-4 sm:p-6 mb-6 sm:mb-8 overflow-x-auto"
|
||||
class="bg-background-secondary shadow-sm p-4 sm:p-6 overflow-x-auto"
|
||||
>
|
||||
<MarkdownContent path={actualPath} />
|
||||
</div>
|
||||
@ -21,12 +21,14 @@
|
||||
<div class="md:flex md:items-center md:justify-between">
|
||||
<div class="md:w-1/2 mb-8 md:mb-0 md:pr-6">
|
||||
<h1
|
||||
class="text-3xl sm:text-4xl md:text-5xl font-bold mb-4 sm:mb-6 text-gray-900 leading-tight"
|
||||
class="text-3xl sm:text-4xl md:text-5xl font-bold mb-4 sm:mb-6 text-text leading-tight"
|
||||
>
|
||||
Welcome to <span class="text-blue-600">SecureWeb</span>
|
||||
Welcome to <span class="text-primary-600"
|
||||
>SecureWeb</span
|
||||
>
|
||||
</h1>
|
||||
<p
|
||||
class="text-lg sm:text-xl text-gray-600 max-w-2xl mb-6 sm:mb-8 leading-relaxed"
|
||||
class="text-lg sm:text-xl text-text-secondary max-w-2xl mb-6 sm:mb-8 leading-relaxed"
|
||||
>
|
||||
A comprehensive platform for secure and reliable web
|
||||
solutions designed for modern businesses.
|
||||
@ -35,11 +37,11 @@
|
||||
class="flex flex-col xs:flex-row justify-center md:justify-start gap-3 sm:gap-4"
|
||||
>
|
||||
<button
|
||||
class="bg-blue-600 hover:bg-blue-700 text-white px-6 sm:px-8 py-2.5 sm:py-3 rounded-md font-medium transition-colors duration-200 w-full xs:w-auto"
|
||||
class="bg-primary-600 hover:bg-primary-700 text-white px-6 sm:px-8 py-2.5 sm:py-3 rounded-md font-medium transition-colors duration-200 w-full xs:w-auto"
|
||||
>Get Started</button
|
||||
>
|
||||
<button
|
||||
class="bg-gray-100 hover:bg-gray-200 text-gray-800 px-6 sm:px-8 py-2.5 sm:py-3 rounded-md font-medium border border-gray-300 transition-colors duration-200 w-full xs:w-auto"
|
||||
class="bg-background-secondary hover:bg-background text-text px-6 sm:px-8 py-2.5 sm:py-3 rounded-md font-medium border border-border transition-colors duration-200 w-full xs:w-auto"
|
||||
>Learn More</button
|
||||
>
|
||||
</div>
|
||||
@ -59,11 +61,13 @@
|
||||
<section class="mb-12 sm:mb-16 md:mb-20">
|
||||
<div class="text-center mb-8 sm:mb-12">
|
||||
<h2
|
||||
class="text-2xl sm:text-3xl font-bold mb-3 sm:mb-4 text-gray-900"
|
||||
class="text-2xl sm:text-3xl font-bold mb-3 sm:mb-4 text-text"
|
||||
>
|
||||
Our Features
|
||||
</h2>
|
||||
<p class="text-lg sm:text-xl text-gray-600 max-w-3xl mx-auto">
|
||||
<p
|
||||
class="text-lg sm:text-xl text-text-secondary max-w-3xl mx-auto"
|
||||
>
|
||||
Discover what makes SecureWeb the preferred choice for
|
||||
security-conscious businesses.
|
||||
</p>
|
||||
@ -73,20 +77,22 @@
|
||||
class="grid grid-cols-1 sm:grid-cols-2 md:grid-cols-3 gap-6 sm:gap-8 md:gap-10"
|
||||
>
|
||||
<div
|
||||
class="bg-gray-50 p-6 sm:p-8 rounded-xl shadow-md hover:shadow-lg transition-shadow border border-gray-100"
|
||||
class="bg-background p-6 sm:p-8 rounded-xl shadow-md hover:shadow-lg transition-shadow border border-border"
|
||||
>
|
||||
<div
|
||||
class="bg-blue-100 p-3 rounded-full w-12 h-12 sm:w-14 sm:h-14 flex items-center justify-center mb-4 sm:mb-6"
|
||||
class="bg-primary-100 p-3 rounded-full w-12 h-12 sm:w-14 sm:h-14 flex items-center justify-center mb-4 sm:mb-6"
|
||||
>
|
||||
<Shield class="h-6 w-6 sm:h-7 sm:w-7 text-blue-600" />
|
||||
<Shield
|
||||
class="h-6 w-6 sm:h-7 sm:w-7 text-primary-600"
|
||||
/>
|
||||
</div>
|
||||
<h3
|
||||
class="text-lg sm:text-xl font-bold mb-3 sm:mb-4 text-gray-800"
|
||||
class="text-lg sm:text-xl font-bold mb-3 sm:mb-4 text-text"
|
||||
>
|
||||
Advanced Security
|
||||
</h3>
|
||||
<p
|
||||
class="text-gray-600 leading-relaxed text-sm sm:text-base"
|
||||
class="text-text-secondary leading-relaxed text-sm sm:text-base"
|
||||
>
|
||||
State-of-the-art encryption and security protocols to
|
||||
keep your data protected from threats.
|
||||
@ -94,20 +100,20 @@
|
||||
</div>
|
||||
|
||||
<div
|
||||
class="bg-white p-6 sm:p-8 rounded-xl shadow-md hover:shadow-lg transition-shadow border border-gray-100"
|
||||
class="bg-background-secondary p-6 sm:p-8 rounded-xl shadow-md hover:shadow-lg transition-shadow border border-border"
|
||||
>
|
||||
<div
|
||||
class="bg-blue-100 p-3 rounded-full w-12 h-12 sm:w-14 sm:h-14 flex items-center justify-center mb-4 sm:mb-6"
|
||||
class="bg-primary-100 p-3 rounded-full w-12 h-12 sm:w-14 sm:h-14 flex items-center justify-center mb-4 sm:mb-6"
|
||||
>
|
||||
<Zap class="h-6 w-6 sm:h-7 sm:w-7 text-blue-600" />
|
||||
<Zap class="h-6 w-6 sm:h-7 sm:w-7 text-primary-600" />
|
||||
</div>
|
||||
<h3
|
||||
class="text-lg sm:text-xl font-bold mb-3 sm:mb-4 text-gray-800"
|
||||
class="text-lg sm:text-xl font-bold mb-3 sm:mb-4 text-text"
|
||||
>
|
||||
Lightning Performance
|
||||
</h3>
|
||||
<p
|
||||
class="text-gray-600 leading-relaxed text-sm sm:text-base"
|
||||
class="text-text-secondary leading-relaxed text-sm sm:text-base"
|
||||
>
|
||||
Optimized for speed and efficiency, ensuring a smooth
|
||||
and responsive user experience.
|
||||
@ -115,22 +121,22 @@
|
||||
</div>
|
||||
|
||||
<div
|
||||
class="bg-gray-50 p-6 sm:p-8 rounded-xl shadow-md hover:shadow-lg transition-shadow border border-gray-100 sm:col-span-2 md:col-span-1"
|
||||
class="bg-background p-6 sm:p-8 rounded-xl shadow-md hover:shadow-lg transition-shadow border border-border sm:col-span-2 md:col-span-1"
|
||||
>
|
||||
<div
|
||||
class="bg-blue-100 p-3 rounded-full w-12 h-12 sm:w-14 sm:h-14 flex items-center justify-center mb-4 sm:mb-6"
|
||||
class="bg-primary-100 p-3 rounded-full w-12 h-12 sm:w-14 sm:h-14 flex items-center justify-center mb-4 sm:mb-6"
|
||||
>
|
||||
<Smartphone
|
||||
class="h-6 w-6 sm:h-7 sm:w-7 text-blue-600"
|
||||
class="h-6 w-6 sm:h-7 sm:w-7 text-primary-600"
|
||||
/>
|
||||
</div>
|
||||
<h3
|
||||
class="text-lg sm:text-xl font-bold mb-3 sm:mb-4 text-gray-800"
|
||||
class="text-lg sm:text-xl font-bold mb-3 sm:mb-4 text-text"
|
||||
>
|
||||
Responsive Design
|
||||
</h3>
|
||||
<p
|
||||
class="text-gray-600 leading-relaxed text-sm sm:text-base"
|
||||
class="text-text-secondary leading-relaxed text-sm sm:text-base"
|
||||
>
|
||||
Fully responsive layouts that provide a seamless
|
||||
experience across all devices and screen sizes.
|
||||
@ -142,7 +148,7 @@
|
||||
<!-- CTA Section -->
|
||||
<section>
|
||||
<div
|
||||
class="bg-gradient-to-r from-blue-600 to-blue-800 rounded-xl sm:rounded-2xl p-6 sm:p-8 md:p-10 text-white shadow-lg sm:shadow-xl"
|
||||
class="bg-gradient-to-r from-primary-600 to-primary-800 rounded-xl sm:rounded-2xl p-6 sm:p-8 md:p-10 text-white shadow-lg sm:shadow-xl"
|
||||
>
|
||||
<div class="md:flex md:items-center md:justify-between">
|
||||
<div class="mb-6 md:mb-0 md:w-2/3 md:pr-6">
|
||||
@ -150,7 +156,7 @@
|
||||
Ready to Get Started?
|
||||
</h2>
|
||||
<p
|
||||
class="text-base sm:text-lg text-blue-100 mb-0 max-w-2xl"
|
||||
class="text-base sm:text-lg text-primary-100 mb-0 max-w-2xl"
|
||||
>
|
||||
Join thousands of satisfied users who trust
|
||||
SecureWeb for their web security needs. Sign up
|
||||
@ -159,7 +165,7 @@
|
||||
</div>
|
||||
<div class="flex justify-center md:justify-end">
|
||||
<button
|
||||
class="bg-white text-blue-700 hover:bg-blue-50 px-6 sm:px-8 py-2.5 sm:py-3 rounded-lg font-semibold text-base sm:text-lg shadow-md transition-colors w-full xs:w-auto"
|
||||
class="bg-background-secondary text-primary-700 hover:bg-primary-50 px-6 sm:px-8 py-2.5 sm:py-3 rounded-lg font-semibold text-base sm:text-lg shadow-md transition-colors w-full xs:w-auto"
|
||||
>
|
||||
Sign Up Now
|
||||
</button>
|
||||
|
@ -5,6 +5,7 @@
|
||||
import NavDataProvider from "./NavDataProvider.svelte";
|
||||
import Home from "./Home.svelte";
|
||||
import { onMount } from "svelte";
|
||||
import ThemeProvider from "../lib/theme/ThemeProvider.svelte";
|
||||
|
||||
let sidebarVisible = true;
|
||||
let isMobile = false;
|
||||
@ -53,46 +54,43 @@
|
||||
});
|
||||
</script>
|
||||
|
||||
<div class="flex flex-col min-h-screen bg-gray-50">
|
||||
<Navbar {toggleSidebar} {isMobile} {sidebarVisible} />
|
||||
<ThemeProvider>
|
||||
<div class="flex flex-col min-h-screen bg-background">
|
||||
<Navbar {toggleSidebar} {isMobile} {sidebarVisible} />
|
||||
|
||||
<div class="flex flex-1 pt-16 relative">
|
||||
<!-- Overlay for mobile sidebar -->
|
||||
{#if sidebarVisible && isMobile}
|
||||
<div
|
||||
class="fixed inset-0 bg-gray-900 bg-opacity-50 z-20 transition-opacity duration-300"
|
||||
on:click={toggleSidebar}
|
||||
aria-hidden="true"
|
||||
></div>
|
||||
{/if}
|
||||
|
||||
<NavDataProvider let:navData>
|
||||
<!-- Sidebar with improved mobile handling -->
|
||||
<Sidebar
|
||||
{navData}
|
||||
onNavItemClick={handleNavItemClick}
|
||||
visible={sidebarVisible}
|
||||
{isMobile}
|
||||
/>
|
||||
|
||||
<main
|
||||
class={`flex-1 transition-all duration-300 ${
|
||||
sidebarVisible && !isMobile ? "md:ml-64" : "ml-0"
|
||||
}`}
|
||||
>
|
||||
<div class="flex flex-1 pt-16 relative">
|
||||
<!-- Overlay for mobile sidebar -->
|
||||
{#if sidebarVisible && isMobile}
|
||||
<div
|
||||
class="container mx-auto px-3 sm:px-4 py-4 sm:py-8 min-h-[calc(100vh-12rem)]"
|
||||
class="fixed inset-0 bg-text bg-opacity-50 z-20 transition-opacity duration-300"
|
||||
on:click={toggleSidebar}
|
||||
aria-hidden="true"
|
||||
></div>
|
||||
{/if}
|
||||
|
||||
<NavDataProvider let:navData>
|
||||
<!-- Sidebar with improved mobile handling -->
|
||||
<Sidebar
|
||||
{navData}
|
||||
onNavItemClick={handleNavItemClick}
|
||||
visible={sidebarVisible}
|
||||
{isMobile}
|
||||
/>
|
||||
|
||||
<main
|
||||
class={`flex-1 transition-all duration-300 ${
|
||||
sidebarVisible && !isMobile ? "md:ml-64" : "ml-0"
|
||||
}`}
|
||||
>
|
||||
{#if selectedContentPath}
|
||||
<Home contentPath={selectedContentPath} />
|
||||
{:else}
|
||||
<slot />
|
||||
{/if}
|
||||
</div>
|
||||
</main>
|
||||
</NavDataProvider>
|
||||
</div>
|
||||
</main>
|
||||
</NavDataProvider>
|
||||
</div>
|
||||
|
||||
<!-- Footer is now outside the main content area -->
|
||||
<Footer />
|
||||
</div>
|
||||
<Footer />
|
||||
</div>
|
||||
</ThemeProvider>
|
||||
|
@ -94,13 +94,13 @@
|
||||
|
||||
<style>
|
||||
.markdown-content {
|
||||
padding: 0.5rem;
|
||||
/* padding: 0.5rem; */
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
@media (min-width: 640px) {
|
||||
.markdown-content {
|
||||
padding: 1rem;
|
||||
/* padding: 1rem; */
|
||||
}
|
||||
}
|
||||
|
||||
@ -118,14 +118,14 @@
|
||||
}
|
||||
|
||||
.error {
|
||||
color: #e53e3e;
|
||||
color: rgb(229 62 62);
|
||||
}
|
||||
|
||||
.content :global(h1) {
|
||||
font-size: 1.75rem;
|
||||
font-weight: 700;
|
||||
margin-bottom: 1rem;
|
||||
color: #1e40af;
|
||||
color: rgb(var(--color-primary-700));
|
||||
word-break: break-word;
|
||||
}
|
||||
|
||||
@ -134,7 +134,7 @@
|
||||
font-weight: 600;
|
||||
margin-top: 1.5rem;
|
||||
margin-bottom: 0.75rem;
|
||||
color: #1e3a8a;
|
||||
color: rgb(var(--color-primary-800));
|
||||
word-break: break-word;
|
||||
}
|
||||
|
||||
@ -143,7 +143,7 @@
|
||||
font-weight: 600;
|
||||
margin-top: 1.25rem;
|
||||
margin-bottom: 0.5rem;
|
||||
color: #1e3a8a;
|
||||
color: rgb(var(--color-primary-800));
|
||||
word-break: break-word;
|
||||
}
|
||||
|
||||
@ -163,7 +163,7 @@
|
||||
}
|
||||
|
||||
.content :global(a) {
|
||||
color: #2563eb;
|
||||
color: rgb(var(--color-primary-600));
|
||||
text-decoration: none;
|
||||
word-break: break-word;
|
||||
}
|
||||
@ -173,16 +173,16 @@
|
||||
}
|
||||
|
||||
.content :global(blockquote) {
|
||||
border-left: 4px solid #e5e7eb;
|
||||
border-left: 4px solid rgb(var(--color-border));
|
||||
padding-left: 1rem;
|
||||
margin-left: 0;
|
||||
margin-right: 0;
|
||||
font-style: italic;
|
||||
color: #4b5563;
|
||||
color: rgb(var(--color-text-secondary));
|
||||
}
|
||||
|
||||
.content :global(code) {
|
||||
background-color: #f3f4f6;
|
||||
background-color: rgb(var(--color-background-secondary));
|
||||
padding: 0.2rem 0.4rem;
|
||||
border-radius: 0.25rem;
|
||||
font-family: monospace;
|
||||
@ -192,7 +192,7 @@
|
||||
}
|
||||
|
||||
.content :global(pre) {
|
||||
background-color: #f3f4f6;
|
||||
background-color: rgb(var(--color-background-secondary));
|
||||
padding: 0.75rem;
|
||||
border-radius: 0.5rem;
|
||||
overflow-x: auto;
|
||||
@ -216,7 +216,7 @@
|
||||
|
||||
.content :global(hr) {
|
||||
border: 0;
|
||||
border-top: 1px solid #e5e7eb;
|
||||
border-top: 1px solid rgb(var(--color-border));
|
||||
margin: 1.5rem 0;
|
||||
}
|
||||
|
||||
@ -230,13 +230,13 @@
|
||||
|
||||
.content :global(th),
|
||||
.content :global(td) {
|
||||
border: 1px solid #e5e7eb;
|
||||
border: 1px solid rgb(var(--color-border));
|
||||
padding: 0.5rem;
|
||||
min-width: 100px;
|
||||
}
|
||||
|
||||
.content :global(th) {
|
||||
background-color: #f9fafb;
|
||||
background-color: rgb(var(--color-background-secondary));
|
||||
}
|
||||
|
||||
@media (min-width: 640px) {
|
||||
|
@ -41,15 +41,9 @@
|
||||
>
|
||||
<div class="tree-line" style="width: {indentation}px;"></div>
|
||||
<div class="icon-container">
|
||||
{#if isExpanded}
|
||||
<ChevronDown
|
||||
class="chevron-icon {isExpanded ? 'expanded' : ''}"
|
||||
/>
|
||||
{:else}
|
||||
<ChevronRight
|
||||
class="chevron-icon {isExpanded ? 'expanded' : ''}"
|
||||
/>
|
||||
{/if}
|
||||
<ChevronRight
|
||||
class="chevron-icon {isExpanded ? 'expanded' : ''}"
|
||||
/>
|
||||
</div>
|
||||
<span class="label">{item.label}</span>
|
||||
</button>
|
||||
@ -101,7 +95,7 @@
|
||||
position: relative;
|
||||
border: none;
|
||||
background: transparent;
|
||||
color: #4b5563;
|
||||
color: var(--color-text-secondary);
|
||||
font-size: 0.9rem;
|
||||
cursor: pointer;
|
||||
transition:
|
||||
@ -110,12 +104,12 @@
|
||||
}
|
||||
|
||||
.nav-button:hover {
|
||||
background-color: rgba(0, 0, 0, 0.05);
|
||||
background-color: rgba(var(--color-background), 0.5);
|
||||
}
|
||||
|
||||
.nav-button.active {
|
||||
background-color: rgba(59, 130, 246, 0.1);
|
||||
color: #3b82f6;
|
||||
background-color: rgba(var(--color-primary-500), 0.1);
|
||||
color: rgb(var(--color-primary-600));
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
@ -134,7 +128,7 @@
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
width: 1px;
|
||||
background-color: #e5e7eb;
|
||||
background-color: rgb(var(--color-border));
|
||||
}
|
||||
|
||||
.icon-container {
|
||||
@ -143,13 +137,13 @@
|
||||
margin-right: 8px;
|
||||
}
|
||||
|
||||
.chevron-icon {
|
||||
:global(.chevron-icon) {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
transition: transform 0.2s;
|
||||
}
|
||||
|
||||
.chevron-icon.expanded {
|
||||
:global(.chevron-icon.expanded) {
|
||||
transform: rotate(90deg);
|
||||
}
|
||||
|
||||
|
@ -1,5 +1,6 @@
|
||||
<script lang="ts">
|
||||
import { Menu, Search, User, Bell, X } from "lucide-svelte";
|
||||
import { Menu, Search, X } from "lucide-svelte";
|
||||
import ThemeToggle from "../lib/theme/ThemeToggle.svelte";
|
||||
|
||||
export let toggleSidebar: () => void = () => {};
|
||||
export let isMobile: boolean = false;
|
||||
@ -7,11 +8,11 @@
|
||||
</script>
|
||||
|
||||
<header
|
||||
class="bg-gray-50 border-b border-gray-200 fixed top-0 left-0 right-0 z-30 h-16 flex items-center justify-between px-3 sm:px-4 shadow-sm"
|
||||
class="bg-background border-b border-border fixed top-0 left-0 right-0 z-30 h-16 flex items-center justify-between px-3 sm:px-4 shadow-sm"
|
||||
>
|
||||
<div class="flex items-center">
|
||||
<button
|
||||
class="mr-3 p-2 rounded-md hover:bg-gray-100 text-gray-700"
|
||||
class="mr-3 p-2 rounded-md hover:bg-background-secondary text-text"
|
||||
on:click={toggleSidebar}
|
||||
aria-label={sidebarVisible ? "Close sidebar" : "Open sidebar"}
|
||||
>
|
||||
@ -21,13 +22,15 @@
|
||||
<Menu class="h-5 w-5" />
|
||||
{/if}
|
||||
</button>
|
||||
<div class="text-lg sm:text-xl font-bold text-blue-800">SecureWeb</div>
|
||||
<div class="text-lg sm:text-xl font-bold text-primary-600">
|
||||
SecureWeb
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="flex items-center space-x-2 sm:space-x-4">
|
||||
<!-- Search button for mobile -->
|
||||
<button
|
||||
class="md:hidden p-2 rounded-md hover:bg-gray-100 text-gray-700"
|
||||
class="md:hidden p-2 rounded-md hover:bg-background-secondary text-text"
|
||||
>
|
||||
<Search class="h-5 w-5" />
|
||||
</button>
|
||||
@ -35,26 +38,16 @@
|
||||
<!-- Search bar for desktop -->
|
||||
<div class="relative hidden md:block">
|
||||
<Search
|
||||
class="h-4 w-4 absolute left-3 top-1/2 transform -translate-y-1/2 text-gray-400"
|
||||
class="h-4 w-4 absolute left-3 top-1/2 transform -translate-y-1/2 text-text-muted"
|
||||
/>
|
||||
<input
|
||||
type="text"
|
||||
placeholder="Search..."
|
||||
class="pl-9 pr-4 py-1.5 text-sm rounded-md border border-gray-300 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent w-40 lg:w-64"
|
||||
class="pl-9 pr-4 py-1.5 text-sm rounded-md border border-border bg-background text-text focus:outline-none focus:ring-2 focus:ring-primary-500 focus:border-transparent w-40 lg:w-64"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<button
|
||||
class="p-2 rounded-full hover:bg-gray-100 text-gray-700 relative hidden sm:block"
|
||||
>
|
||||
<Bell class="h-5 w-5" />
|
||||
<span
|
||||
class="absolute top-1 right-1 w-2 h-2 bg-blue-500 rounded-full"
|
||||
></span>
|
||||
</button>
|
||||
|
||||
<button class="p-1.5 rounded-full hover:bg-gray-100 text-gray-700">
|
||||
<User class="h-5 w-5" />
|
||||
</button>
|
||||
<!-- Theme toggle -->
|
||||
<ThemeToggle class="hover:bg-background-secondary" />
|
||||
</div>
|
||||
</header>
|
||||
|
@ -75,25 +75,11 @@
|
||||
</script>
|
||||
|
||||
<aside
|
||||
class="sidebar bg-white border-gray-200 h-screen fixed top-0 left-0 pt-16 overflow-y-auto shadow-sm z-20
|
||||
class="sidebar bg-background-secondary border-border h-screen fixed top-0 left-0 pt-16 overflow-y-auto shadow-sm z-20
|
||||
{isMobile ? 'w-[85%] max-w-xs' : 'w-64'}
|
||||
transition-transform duration-300 ease-in-out
|
||||
{visible ? 'translate-x-0' : '-translate-x-full'}"
|
||||
>
|
||||
<div
|
||||
class="sidebar-header border-gray-200 p-3 flex justify-between items-center"
|
||||
>
|
||||
{#if isMobile}
|
||||
<button
|
||||
class="p-1 rounded-md hover:bg-gray-100"
|
||||
on:click={toggleSidebar}
|
||||
aria-label="Close sidebar"
|
||||
>
|
||||
<X class="w-5 h-5 text-gray-500" />
|
||||
</button>
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
<nav class="w-full py-2">
|
||||
{#each navData as item}
|
||||
<NavItemComponent
|
||||
@ -110,11 +96,11 @@
|
||||
|
||||
{#if isMobile && !visible}
|
||||
<button
|
||||
class="fixed top-4 left-4 z-10 p-2 bg-white rounded-md shadow-md hover:bg-gray-100"
|
||||
class="fixed top-4 left-4 z-10 p-2 bg-background-secondary rounded-md shadow-md hover:bg-background"
|
||||
on:click={toggleSidebar}
|
||||
aria-label="Open sidebar"
|
||||
>
|
||||
<Menu class="w-5 h-5 text-gray-700" />
|
||||
<Menu class="w-5 h-5 text-text" />
|
||||
</button>
|
||||
{/if}
|
||||
|
||||
@ -122,6 +108,7 @@
|
||||
.sidebar {
|
||||
scrollbar-width: thin;
|
||||
scrollbar-color: rgba(156, 163, 175, 0.5) transparent;
|
||||
border-right: 1px solid rgb(var(--color-border));
|
||||
}
|
||||
|
||||
.sidebar::-webkit-scrollbar {
|
||||
|
@ -1,10 +0,0 @@
|
||||
<script lang="ts">
|
||||
let count: number = $state(0)
|
||||
const increment = () => {
|
||||
count += 1
|
||||
}
|
||||
</script>
|
||||
|
||||
<button onclick={increment}>
|
||||
count is {count}
|
||||
</button>
|
104
sweb/src/lib/theme/ThemeProvider.svelte
Normal file
104
sweb/src/lib/theme/ThemeProvider.svelte
Normal file
@ -0,0 +1,104 @@
|
||||
<script lang="ts" module>
|
||||
import { createContext } from "../create-context";
|
||||
|
||||
// Define theme types
|
||||
export type Theme = "light" | "dark" | "system";
|
||||
|
||||
// Create theme context
|
||||
export const { get: getThemeContext, set: setThemeContext } =
|
||||
createContext<{
|
||||
theme: Theme;
|
||||
setTheme: (theme: Theme) => void;
|
||||
subscribe?: (callback: (theme: Theme) => void) => () => void;
|
||||
}>();
|
||||
</script>
|
||||
|
||||
<script lang="ts">
|
||||
import { onMount } from "svelte";
|
||||
|
||||
// Props
|
||||
export let initialTheme: Theme = "system";
|
||||
|
||||
// State with reactivity
|
||||
let theme = initialTheme;
|
||||
let mounted = false;
|
||||
|
||||
// Create a custom store for the theme
|
||||
const themeStore = {
|
||||
subscribe: (callback: (theme: Theme) => void) => {
|
||||
// Initial call
|
||||
callback(theme);
|
||||
|
||||
// Setup a MutationObserver to watch for class changes on documentElement
|
||||
const observer = new MutationObserver(() => {
|
||||
callback(theme);
|
||||
});
|
||||
|
||||
observer.observe(document.documentElement, {
|
||||
attributes: true,
|
||||
attributeFilter: ["class"],
|
||||
});
|
||||
|
||||
// Return unsubscribe function
|
||||
return () => observer.disconnect();
|
||||
},
|
||||
};
|
||||
|
||||
// Set the theme in localStorage and update the DOM
|
||||
function setTheme(newTheme: Theme) {
|
||||
theme = newTheme;
|
||||
|
||||
if (mounted) {
|
||||
updateTheme(theme);
|
||||
localStorage.setItem("theme", theme);
|
||||
}
|
||||
}
|
||||
|
||||
// Update the DOM based on the current theme
|
||||
function updateTheme(currentTheme: Theme) {
|
||||
const isDark =
|
||||
currentTheme === "dark" ||
|
||||
(currentTheme === "system" &&
|
||||
window.matchMedia("(prefers-color-scheme: dark)").matches);
|
||||
|
||||
document.documentElement.classList.toggle("dark", isDark);
|
||||
}
|
||||
|
||||
// Initialize theme on mount
|
||||
onMount(() => {
|
||||
// Get stored theme or use system preference
|
||||
const storedTheme = localStorage.getItem("theme") as Theme | null;
|
||||
if (storedTheme) {
|
||||
theme = storedTheme;
|
||||
}
|
||||
|
||||
// Set up system theme change listener
|
||||
const mediaQuery = window.matchMedia("(prefers-color-scheme: dark)");
|
||||
const handleChange = () => {
|
||||
if (theme === "system") {
|
||||
updateTheme("system");
|
||||
}
|
||||
};
|
||||
|
||||
mediaQuery.addEventListener("change", handleChange);
|
||||
|
||||
// Apply initial theme
|
||||
updateTheme(theme);
|
||||
mounted = true;
|
||||
|
||||
return () => {
|
||||
mediaQuery.removeEventListener("change", handleChange);
|
||||
};
|
||||
});
|
||||
|
||||
// Set the context with the store
|
||||
setThemeContext({
|
||||
get theme() {
|
||||
return theme;
|
||||
},
|
||||
setTheme,
|
||||
subscribe: themeStore.subscribe,
|
||||
});
|
||||
</script>
|
||||
|
||||
<slot />
|
78
sweb/src/lib/theme/ThemeToggle.svelte
Normal file
78
sweb/src/lib/theme/ThemeToggle.svelte
Normal file
@ -0,0 +1,78 @@
|
||||
<script lang="ts">
|
||||
import { Sun, Moon } from "lucide-svelte";
|
||||
import { getThemeContext, type Theme } from "./ThemeProvider.svelte";
|
||||
import { cn } from "../utils";
|
||||
import { onMount } from "svelte";
|
||||
|
||||
export let size: "sm" | "md" | "lg" = "md";
|
||||
|
||||
let className: string | undefined | null = undefined;
|
||||
export { className as class };
|
||||
|
||||
const themeContext = getThemeContext();
|
||||
|
||||
// Create a reactive variable to track the current theme
|
||||
let currentTheme: Theme = themeContext.theme;
|
||||
|
||||
// Subscribe to theme changes if the subscribe method is available
|
||||
onMount(() => {
|
||||
// Set initial theme
|
||||
currentTheme = themeContext.theme;
|
||||
|
||||
// If subscribe is available, use it to update the theme
|
||||
if (themeContext.subscribe) {
|
||||
const unsubscribe = themeContext.subscribe((newTheme) => {
|
||||
currentTheme = newTheme;
|
||||
});
|
||||
|
||||
return unsubscribe;
|
||||
}
|
||||
});
|
||||
|
||||
// Size classes for the button
|
||||
const sizeClasses = {
|
||||
sm: "h-8 w-8",
|
||||
md: "h-9 w-9",
|
||||
lg: "h-10 w-10",
|
||||
};
|
||||
|
||||
// Size classes for the icons
|
||||
const iconSizeClasses = {
|
||||
sm: "h-4 w-4",
|
||||
md: "h-5 w-5",
|
||||
lg: "h-6 w-6",
|
||||
};
|
||||
|
||||
// Toggle between light and dark modes only
|
||||
function toggleTheme() {
|
||||
let newTheme: Theme;
|
||||
|
||||
// Just toggle between light and dark
|
||||
if (currentTheme === "light") {
|
||||
newTheme = "dark";
|
||||
} else {
|
||||
newTheme = "light";
|
||||
}
|
||||
|
||||
themeContext.setTheme(newTheme);
|
||||
// Update our local state immediately
|
||||
currentTheme = newTheme;
|
||||
}
|
||||
</script>
|
||||
|
||||
<button
|
||||
type="button"
|
||||
aria-label="Toggle theme"
|
||||
class={cn(
|
||||
"rounded-md p-2 transition-colors hover:bg-background-secondary",
|
||||
sizeClasses[size],
|
||||
className,
|
||||
)}
|
||||
on:click={toggleTheme}
|
||||
>
|
||||
{#if currentTheme === "dark"}
|
||||
<Sun class={cn("text-text", iconSizeClasses[size])} />
|
||||
{:else}
|
||||
<Moon class={cn("text-text", iconSizeClasses[size])} />
|
||||
{/if}
|
||||
</button>
|
@ -3,6 +3,7 @@ export default {
|
||||
content: [
|
||||
'./src/**/*.{html,js,svelte,ts}',
|
||||
],
|
||||
darkMode: 'class',
|
||||
theme: {
|
||||
screens: {
|
||||
'xs': '480px',
|
||||
@ -14,6 +15,32 @@ export default {
|
||||
},
|
||||
extend: {
|
||||
colors: {
|
||||
primary: {
|
||||
50: 'rgb(var(--color-primary-50) / <alpha-value>)',
|
||||
100: 'rgb(var(--color-primary-100) / <alpha-value>)',
|
||||
200: 'rgb(var(--color-primary-200) / <alpha-value>)',
|
||||
300: 'rgb(var(--color-primary-300) / <alpha-value>)',
|
||||
400: 'rgb(var(--color-primary-400) / <alpha-value>)',
|
||||
500: 'rgb(var(--color-primary-500) / <alpha-value>)',
|
||||
600: 'rgb(var(--color-primary-600) / <alpha-value>)',
|
||||
700: 'rgb(var(--color-primary-700) / <alpha-value>)',
|
||||
800: 'rgb(var(--color-primary-800) / <alpha-value>)',
|
||||
900: 'rgb(var(--color-primary-900) / <alpha-value>)',
|
||||
},
|
||||
background: {
|
||||
DEFAULT: 'rgb(var(--color-background) / <alpha-value>)',
|
||||
secondary: 'rgb(var(--color-background-secondary) / <alpha-value>)',
|
||||
},
|
||||
text: {
|
||||
DEFAULT: 'rgb(var(--color-text) / <alpha-value>)',
|
||||
secondary: 'rgb(var(--color-text-secondary) / <alpha-value>)',
|
||||
muted: 'rgb(var(--color-text-muted) / <alpha-value>)',
|
||||
},
|
||||
border: {
|
||||
DEFAULT: 'rgb(var(--color-border) / <alpha-value>)',
|
||||
secondary: 'rgb(var(--color-border-secondary) / <alpha-value>)',
|
||||
},
|
||||
// Keep original colors for backward compatibility
|
||||
blue: {
|
||||
600: '#2563eb',
|
||||
700: '#1d4ed8',
|
||||
|
Loading…
Reference in New Issue
Block a user