chore: Improve website UI and add .vscode to .gitignore
- Update website footer to improve responsiveness and layout. - Improve the styling and layout of the Home page components. - Update the Layout component to handle mobile sidebar better. - Improve Markdown rendering for better responsiveness. - Remove unused NavBar component. - Remove svelte-vscode extension from extensions.json. - Add .vscode folder to .gitignore to prevent accidental commits.
This commit is contained in:
parent
e68d0bbe8c
commit
486b5ceb05
1
.gitignore
vendored
1
.gitignore
vendored
@ -23,3 +23,4 @@ dist-ssr
|
||||
*.sln
|
||||
*.sw?
|
||||
*.pnpm-store
|
||||
*.vscode
|
3
sweb/.vscode/extensions.json
vendored
3
sweb/.vscode/extensions.json
vendored
@ -1,3 +0,0 @@
|
||||
{
|
||||
"recommendations": ["svelte.svelte-vscode"]
|
||||
}
|
@ -2,40 +2,49 @@
|
||||
// Footer component
|
||||
</script>
|
||||
|
||||
<footer class="bg-gray-100 border-t border-gray-200 py-6 px-4 w-full mt-auto">
|
||||
<footer
|
||||
class="bg-gray-100 border-t border-gray-200 py-4 sm:py-6 px-3 sm:px-4 w-full mt-auto"
|
||||
>
|
||||
<div class="container mx-auto max-w-6xl">
|
||||
<div class="flex flex-col md:flex-row justify-between items-center">
|
||||
<div class="mb-4 md:mb-0">
|
||||
<div
|
||||
class="grid grid-cols-1 sm:grid-cols-2 md:grid-cols-3 gap-6 md:gap-4"
|
||||
>
|
||||
<!-- 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">
|
||||
Secure and reliable web solutions
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="flex space-x-6">
|
||||
<!-- Navigation links -->
|
||||
<div
|
||||
class="flex flex-wrap justify-center sm:justify-start gap-x-6 gap-y-2"
|
||||
>
|
||||
<a
|
||||
href="/"
|
||||
class="text-gray-600 hover:text-blue-800 transition-colors"
|
||||
class="text-gray-600 hover:text-blue-800 transition-colors text-sm sm:text-base"
|
||||
>Home</a
|
||||
>
|
||||
<a
|
||||
href="/about"
|
||||
class="text-gray-600 hover:text-blue-800 transition-colors"
|
||||
class="text-gray-600 hover:text-blue-800 transition-colors text-sm sm:text-base"
|
||||
>About</a
|
||||
>
|
||||
<a
|
||||
href="/services"
|
||||
class="text-gray-600 hover:text-blue-800 transition-colors"
|
||||
class="text-gray-600 hover:text-blue-800 transition-colors text-sm sm:text-base"
|
||||
>Services</a
|
||||
>
|
||||
<a
|
||||
href="/contact"
|
||||
class="text-gray-600 hover:text-blue-800 transition-colors"
|
||||
class="text-gray-600 hover:text-blue-800 transition-colors text-sm sm:text-base"
|
||||
>Contact</a
|
||||
>
|
||||
</div>
|
||||
|
||||
<div class="flex space-x-4 mt-4 md:mt-0">
|
||||
<!-- Social media icons -->
|
||||
<div class="flex justify-center md:justify-end space-x-4">
|
||||
<a
|
||||
href="/twitter"
|
||||
aria-label="Twitter"
|
||||
@ -88,7 +97,7 @@
|
||||
</div>
|
||||
|
||||
<div
|
||||
class="border-t border-gray-200 mt-6 pt-6 text-center text-gray-500 text-sm"
|
||||
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"
|
||||
>
|
||||
<p>
|
||||
© {new Date().getFullYear()} SecureWeb. All rights reserved.
|
||||
|
@ -8,34 +8,38 @@
|
||||
$: actualPath = contentPath || "introduction/introduction";
|
||||
</script>
|
||||
|
||||
<div class="py-8 px-4 max-w-7xl mx-auto">
|
||||
<div class="py-4 sm:py-6 md:py-8 px-3 sm:px-4 max-w-7xl mx-auto">
|
||||
{#if contentPath}
|
||||
<div class="bg-white rounded-lg shadow-sm p-6 mb-8">
|
||||
<div
|
||||
class="bg-white rounded-lg shadow-sm p-4 sm:p-6 mb-6 sm:mb-8 overflow-x-auto"
|
||||
>
|
||||
<MarkdownContent path={actualPath} />
|
||||
</div>
|
||||
{:else}
|
||||
<!-- Hero Section -->
|
||||
<section class="mb-20 text-center md:text-left">
|
||||
<section class="mb-12 sm:mb-16 md:mb-20 text-center md:text-left">
|
||||
<div class="md:flex md:items-center md:justify-between">
|
||||
<div class="md:w-1/2 mb-10 md:mb-0">
|
||||
<div class="md:w-1/2 mb-8 md:mb-0 md:pr-6">
|
||||
<h1
|
||||
class="text-4xl md:text-5xl font-bold mb-6 text-gray-900 leading-tight"
|
||||
class="text-3xl sm:text-4xl md:text-5xl font-bold mb-4 sm:mb-6 text-gray-900 leading-tight"
|
||||
>
|
||||
Welcome to <span class="text-blue-600">SecureWeb</span>
|
||||
</h1>
|
||||
<p
|
||||
class="text-xl text-gray-600 max-w-2xl mb-8 leading-relaxed"
|
||||
class="text-lg sm:text-xl text-gray-600 max-w-2xl mb-6 sm:mb-8 leading-relaxed"
|
||||
>
|
||||
A comprehensive platform for secure and reliable web
|
||||
solutions designed for modern businesses.
|
||||
</p>
|
||||
<div class="flex flex-col sm:flex-row gap-4">
|
||||
<div
|
||||
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-8 py-3 rounded-md font-medium transition-colors duration-200"
|
||||
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"
|
||||
>Get Started</button
|
||||
>
|
||||
<button
|
||||
class="bg-gray-100 hover:bg-gray-200 text-gray-800 px-8 py-3 rounded-md font-medium border border-gray-300 transition-colors duration-200"
|
||||
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"
|
||||
>Learn More</button
|
||||
>
|
||||
</div>
|
||||
@ -45,70 +49,89 @@
|
||||
src="https://via.placeholder.com/600x400/f3f4f6/1e40af?text=SecureWeb"
|
||||
alt="SecureWeb Platform"
|
||||
class="rounded-lg shadow-lg w-full"
|
||||
loading="lazy"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- Features Section -->
|
||||
<section class="mb-20">
|
||||
<div class="text-center mb-12">
|
||||
<h2 class="text-3xl font-bold mb-4 text-gray-900">
|
||||
<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"
|
||||
>
|
||||
Our Features
|
||||
</h2>
|
||||
<p class="text-xl text-gray-600 max-w-3xl mx-auto">
|
||||
<p class="text-lg sm:text-xl text-gray-600 max-w-3xl mx-auto">
|
||||
Discover what makes SecureWeb the preferred choice for
|
||||
security-conscious businesses.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="grid grid-cols-1 md:grid-cols-3 gap-10">
|
||||
<div
|
||||
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-8 rounded-xl shadow-md hover:shadow-lg transition-shadow border border-gray-100"
|
||||
class="bg-gray-50 p-6 sm:p-8 rounded-xl shadow-md hover:shadow-lg transition-shadow border border-gray-100"
|
||||
>
|
||||
<div
|
||||
class="bg-blue-100 p-3 rounded-full w-14 h-14 flex items-center justify-center mb-6"
|
||||
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"
|
||||
>
|
||||
<Shield class="h-7 w-7 text-blue-600" />
|
||||
<Shield class="h-6 w-6 sm:h-7 sm:w-7 text-blue-600" />
|
||||
</div>
|
||||
<h3 class="text-xl font-bold mb-4 text-gray-800">
|
||||
<h3
|
||||
class="text-lg sm:text-xl font-bold mb-3 sm:mb-4 text-gray-800"
|
||||
>
|
||||
Advanced Security
|
||||
</h3>
|
||||
<p class="text-gray-600 leading-relaxed">
|
||||
<p
|
||||
class="text-gray-600 leading-relaxed text-sm sm:text-base"
|
||||
>
|
||||
State-of-the-art encryption and security protocols to
|
||||
keep your data protected from threats.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div
|
||||
class="bg-white p-8 rounded-xl shadow-md hover:shadow-lg transition-shadow border border-gray-100"
|
||||
class="bg-white p-6 sm:p-8 rounded-xl shadow-md hover:shadow-lg transition-shadow border border-gray-100"
|
||||
>
|
||||
<div
|
||||
class="bg-blue-100 p-3 rounded-full w-14 h-14 flex items-center justify-center mb-6"
|
||||
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"
|
||||
>
|
||||
<Zap class="h-7 w-7 text-blue-600" />
|
||||
<Zap class="h-6 w-6 sm:h-7 sm:w-7 text-blue-600" />
|
||||
</div>
|
||||
<h3 class="text-xl font-bold mb-4 text-gray-800">
|
||||
<h3
|
||||
class="text-lg sm:text-xl font-bold mb-3 sm:mb-4 text-gray-800"
|
||||
>
|
||||
Lightning Performance
|
||||
</h3>
|
||||
<p class="text-gray-600 leading-relaxed">
|
||||
<p
|
||||
class="text-gray-600 leading-relaxed text-sm sm:text-base"
|
||||
>
|
||||
Optimized for speed and efficiency, ensuring a smooth
|
||||
and responsive user experience.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div
|
||||
class="bg-gray-50 p-8 rounded-xl shadow-md hover:shadow-lg transition-shadow border border-gray-100"
|
||||
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"
|
||||
>
|
||||
<div
|
||||
class="bg-blue-100 p-3 rounded-full w-14 h-14 flex items-center justify-center mb-6"
|
||||
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"
|
||||
>
|
||||
<Smartphone class="h-7 w-7 text-blue-600" />
|
||||
<Smartphone
|
||||
class="h-6 w-6 sm:h-7 sm:w-7 text-blue-600"
|
||||
/>
|
||||
</div>
|
||||
<h3 class="text-xl font-bold mb-4 text-gray-800">
|
||||
<h3
|
||||
class="text-lg sm:text-xl font-bold mb-3 sm:mb-4 text-gray-800"
|
||||
>
|
||||
Responsive Design
|
||||
</h3>
|
||||
<p class="text-gray-600 leading-relaxed">
|
||||
<p
|
||||
class="text-gray-600 leading-relaxed text-sm sm:text-base"
|
||||
>
|
||||
Fully responsive layouts that provide a seamless
|
||||
experience across all devices and screen sizes.
|
||||
</p>
|
||||
@ -119,22 +142,24 @@
|
||||
<!-- CTA Section -->
|
||||
<section>
|
||||
<div
|
||||
class="bg-gradient-to-r from-blue-600 to-blue-800 rounded-2xl p-10 text-white shadow-xl"
|
||||
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"
|
||||
>
|
||||
<div class="md:flex md:items-center md:justify-between">
|
||||
<div class="mb-8 md:mb-0 md:w-2/3">
|
||||
<h2 class="text-3xl font-bold mb-4">
|
||||
<div class="mb-6 md:mb-0 md:w-2/3 md:pr-6">
|
||||
<h2 class="text-2xl sm:text-3xl font-bold mb-3 sm:mb-4">
|
||||
Ready to Get Started?
|
||||
</h2>
|
||||
<p class="text-lg text-blue-100 mb-0 max-w-2xl">
|
||||
<p
|
||||
class="text-base sm:text-lg text-blue-100 mb-0 max-w-2xl"
|
||||
>
|
||||
Join thousands of satisfied users who trust
|
||||
SecureWeb for their web security needs. Sign up
|
||||
today and experience the difference.
|
||||
</p>
|
||||
</div>
|
||||
<div>
|
||||
<div class="flex justify-center md:justify-end">
|
||||
<button
|
||||
class="bg-white text-blue-700 hover:bg-blue-50 px-8 py-3 rounded-lg font-semibold text-lg shadow-md transition-colors"
|
||||
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"
|
||||
>
|
||||
Sign Up Now
|
||||
</button>
|
||||
|
@ -12,19 +12,35 @@
|
||||
|
||||
function toggleSidebar() {
|
||||
sidebarVisible = !sidebarVisible;
|
||||
// On mobile, when sidebar is opened, add a class to prevent body scrolling
|
||||
if (isMobile && sidebarVisible) {
|
||||
document.body.classList.add("overflow-hidden");
|
||||
} else {
|
||||
document.body.classList.remove("overflow-hidden");
|
||||
}
|
||||
}
|
||||
|
||||
function handleNavItemClick(path: string) {
|
||||
selectedContentPath = path;
|
||||
// Auto-close sidebar on mobile after navigation
|
||||
if (isMobile) {
|
||||
sidebarVisible = false;
|
||||
document.body.classList.remove("overflow-hidden");
|
||||
}
|
||||
}
|
||||
|
||||
onMount(() => {
|
||||
const checkMobile = () => {
|
||||
const wasMobile = isMobile;
|
||||
isMobile = window.innerWidth < 768;
|
||||
if (isMobile) {
|
||||
sidebarVisible = false;
|
||||
} else {
|
||||
sidebarVisible = true;
|
||||
|
||||
// Only change sidebar visibility when transitioning between mobile and desktop
|
||||
if (wasMobile !== isMobile) {
|
||||
if (isMobile) {
|
||||
sidebarVisible = false;
|
||||
} else {
|
||||
sidebarVisible = true;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@ -38,19 +54,34 @@
|
||||
</script>
|
||||
|
||||
<div class="flex flex-col min-h-screen bg-gray-50">
|
||||
<Navbar {toggleSidebar} />
|
||||
<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}
|
||||
|
||||
<div class="flex flex-1 pt-16">
|
||||
<NavDataProvider let:navData>
|
||||
{#if sidebarVisible}
|
||||
<Sidebar {navData} onNavItemClick={handleNavItemClick} />
|
||||
{/if}
|
||||
<!-- Sidebar with improved mobile handling -->
|
||||
<Sidebar
|
||||
{navData}
|
||||
onNavItemClick={handleNavItemClick}
|
||||
visible={sidebarVisible}
|
||||
{isMobile}
|
||||
/>
|
||||
|
||||
<main
|
||||
class={`flex-1 transition-all duration-300 ${sidebarVisible ? "md:ml-64" : "ml-0"}`}
|
||||
class={`flex-1 transition-all duration-300 ${
|
||||
sidebarVisible && !isMobile ? "md:ml-64" : "ml-0"
|
||||
}`}
|
||||
>
|
||||
<div
|
||||
class="container mx-auto px-4 py-8 min-h-[calc(100vh-12rem)]"
|
||||
class="container mx-auto px-3 sm:px-4 py-4 sm:py-8 min-h-[calc(100vh-12rem)]"
|
||||
>
|
||||
{#if selectedContentPath}
|
||||
<Home contentPath={selectedContentPath} />
|
||||
|
@ -94,41 +94,57 @@
|
||||
|
||||
<style>
|
||||
.markdown-content {
|
||||
padding: 1rem;
|
||||
padding: 0.5rem;
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
@media (min-width: 640px) {
|
||||
.markdown-content {
|
||||
padding: 1rem;
|
||||
}
|
||||
}
|
||||
|
||||
.loading,
|
||||
.error {
|
||||
padding: 2rem;
|
||||
padding: 1rem;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
@media (min-width: 640px) {
|
||||
.loading,
|
||||
.error {
|
||||
padding: 2rem;
|
||||
}
|
||||
}
|
||||
|
||||
.error {
|
||||
color: #e53e3e;
|
||||
}
|
||||
|
||||
.content :global(h1) {
|
||||
font-size: 2.5rem;
|
||||
font-size: 1.75rem;
|
||||
font-weight: 700;
|
||||
margin-bottom: 1.5rem;
|
||||
margin-bottom: 1rem;
|
||||
color: #1e40af;
|
||||
word-break: break-word;
|
||||
}
|
||||
|
||||
.content :global(h2) {
|
||||
font-size: 2rem;
|
||||
font-weight: 600;
|
||||
margin-top: 2rem;
|
||||
margin-bottom: 1rem;
|
||||
color: #1e3a8a;
|
||||
}
|
||||
|
||||
.content :global(h3) {
|
||||
font-size: 1.5rem;
|
||||
font-weight: 600;
|
||||
margin-top: 1.5rem;
|
||||
margin-bottom: 0.75rem;
|
||||
color: #1e3a8a;
|
||||
word-break: break-word;
|
||||
}
|
||||
|
||||
.content :global(h3) {
|
||||
font-size: 1.25rem;
|
||||
font-weight: 600;
|
||||
margin-top: 1.25rem;
|
||||
margin-bottom: 0.5rem;
|
||||
color: #1e3a8a;
|
||||
word-break: break-word;
|
||||
}
|
||||
|
||||
.content :global(p) {
|
||||
@ -139,7 +155,7 @@
|
||||
.content :global(ul),
|
||||
.content :global(ol) {
|
||||
margin-bottom: 1rem;
|
||||
margin-left: 2rem;
|
||||
margin-left: 1.5rem;
|
||||
}
|
||||
|
||||
.content :global(li) {
|
||||
@ -149,6 +165,7 @@
|
||||
.content :global(a) {
|
||||
color: #2563eb;
|
||||
text-decoration: none;
|
||||
word-break: break-word;
|
||||
}
|
||||
|
||||
.content :global(a:hover) {
|
||||
@ -169,11 +186,14 @@
|
||||
padding: 0.2rem 0.4rem;
|
||||
border-radius: 0.25rem;
|
||||
font-family: monospace;
|
||||
font-size: 0.875em;
|
||||
word-break: break-word;
|
||||
white-space: pre-wrap;
|
||||
}
|
||||
|
||||
.content :global(pre) {
|
||||
background-color: #f3f4f6;
|
||||
padding: 1rem;
|
||||
padding: 0.75rem;
|
||||
border-radius: 0.5rem;
|
||||
overflow-x: auto;
|
||||
margin-bottom: 1rem;
|
||||
@ -182,6 +202,8 @@
|
||||
.content :global(pre code) {
|
||||
background-color: transparent;
|
||||
padding: 0;
|
||||
white-space: pre;
|
||||
word-break: normal;
|
||||
}
|
||||
|
||||
.content :global(img) {
|
||||
@ -189,27 +211,59 @@
|
||||
height: auto;
|
||||
border-radius: 0.5rem;
|
||||
margin: 1rem 0;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.content :global(hr) {
|
||||
border: 0;
|
||||
border-top: 1px solid #e5e7eb;
|
||||
margin: 2rem 0;
|
||||
margin: 1.5rem 0;
|
||||
}
|
||||
|
||||
.content :global(table) {
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
margin-bottom: 1rem;
|
||||
display: block;
|
||||
overflow-x: auto;
|
||||
}
|
||||
|
||||
.content :global(th),
|
||||
.content :global(td) {
|
||||
border: 1px solid #e5e7eb;
|
||||
padding: 0.5rem;
|
||||
min-width: 100px;
|
||||
}
|
||||
|
||||
.content :global(th) {
|
||||
background-color: #f9fafb;
|
||||
}
|
||||
|
||||
@media (min-width: 640px) {
|
||||
.content :global(h1) {
|
||||
font-size: 2.25rem;
|
||||
margin-bottom: 1.5rem;
|
||||
}
|
||||
|
||||
.content :global(h2) {
|
||||
font-size: 1.75rem;
|
||||
margin-top: 2rem;
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
.content :global(h3) {
|
||||
font-size: 1.5rem;
|
||||
margin-top: 1.5rem;
|
||||
margin-bottom: 0.75rem;
|
||||
}
|
||||
|
||||
.content :global(ul),
|
||||
.content :global(ol) {
|
||||
margin-left: 2rem;
|
||||
}
|
||||
|
||||
.content :global(pre) {
|
||||
padding: 1rem;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
@ -1,49 +0,0 @@
|
||||
<script lang="ts">
|
||||
import type { NavItem } from '../types/nav';
|
||||
import * as Accordion from '$lib/components/ui/accordion'; // Assuming Shadcn Accordion is in $lib/components/ui/accordion
|
||||
import { Button } from '$lib/components/ui/button'; // Assuming Shadcn Button is in $lib/components/ui/button
|
||||
import { ChevronDown } from 'lucide-svelte'; // Assuming lucide-svelte is installed for icons
|
||||
|
||||
export let navData: NavItem[];
|
||||
|
||||
function renderNavItem(item: NavItem): any {
|
||||
if (item.children && item.children.length > 0) {
|
||||
return Accordion.Item;
|
||||
} else {
|
||||
return 'a'; // Render as a link
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<nav class="w-64 bg-gray-800 text-white h-full">
|
||||
<div class="p-4">
|
||||
<h2 class="text-xl font-semibold mb-4">OurWorld</h2>
|
||||
</div>
|
||||
<Accordion.Root class="w-full">
|
||||
{#each navData as item}
|
||||
{#if item.children && item.children.length > 0}
|
||||
<Accordion.Item value={item.label}>
|
||||
<Accordion.Trigger class="flex justify-between items-center w-full text-left p-4 hover:bg-gray-700">
|
||||
{item.label}
|
||||
<ChevronDown class="h-4 w-4 transition-transform duration-200" />
|
||||
</Accordion.Trigger>
|
||||
<Accordion.Content>
|
||||
<ul class="pl-4">
|
||||
{#each item.children as child}
|
||||
<li>
|
||||
<a href={child.link} class="block p-2 hover:bg-gray-700">
|
||||
{child.label}
|
||||
</a>
|
||||
</li>
|
||||
{/each}
|
||||
</ul>
|
||||
</Accordion.Content>
|
||||
</Accordion.Item>
|
||||
{:else}
|
||||
<a href={item.link} class="block p-4 hover:bg-gray-700">
|
||||
{item.label}
|
||||
</a>
|
||||
{/if}
|
||||
{/each}
|
||||
</Accordion.Root>
|
||||
</nav>
|
@ -1,24 +1,38 @@
|
||||
<script lang="ts">
|
||||
import { Menu, Search, User, Bell } from "lucide-svelte";
|
||||
import { Menu, Search, User, Bell, X } from "lucide-svelte";
|
||||
|
||||
export let toggleSidebar: () => void = () => {};
|
||||
export let isMobile: boolean = false;
|
||||
export let sidebarVisible: boolean = false;
|
||||
</script>
|
||||
|
||||
<header
|
||||
class="bg-gray-50 border-b border-gray-200 fixed top-0 left-0 right-0 z-10 h-16 flex items-center justify-between px-4 shadow-sm"
|
||||
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"
|
||||
>
|
||||
<div class="flex items-center">
|
||||
<button
|
||||
class="md:hidden mr-3 p-2 rounded-md hover:bg-gray-100 text-gray-700"
|
||||
class="mr-3 p-2 rounded-md hover:bg-gray-100 text-gray-700"
|
||||
on:click={toggleSidebar}
|
||||
aria-label="Toggle sidebar"
|
||||
aria-label={sidebarVisible ? "Close sidebar" : "Open sidebar"}
|
||||
>
|
||||
<Menu class="h-5 w-5" />
|
||||
{#if isMobile && sidebarVisible}
|
||||
<X class="h-5 w-5" />
|
||||
{:else}
|
||||
<Menu class="h-5 w-5" />
|
||||
{/if}
|
||||
</button>
|
||||
<div class="text-xl font-bold text-blue-800">SecureWeb</div>
|
||||
<div class="text-lg sm:text-xl font-bold text-blue-800">SecureWeb</div>
|
||||
</div>
|
||||
|
||||
<div class="flex items-center space-x-4">
|
||||
<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"
|
||||
>
|
||||
<Search class="h-5 w-5" />
|
||||
</button>
|
||||
|
||||
<!-- 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"
|
||||
@ -26,12 +40,12 @@
|
||||
<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-48 lg:w-64"
|
||||
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"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<button
|
||||
class="p-2 rounded-full hover:bg-gray-100 text-gray-700 relative"
|
||||
class="p-2 rounded-full hover:bg-gray-100 text-gray-700 relative hidden sm:block"
|
||||
>
|
||||
<Bell class="h-5 w-5" />
|
||||
<span
|
||||
|
@ -1,11 +1,12 @@
|
||||
<script lang="ts">
|
||||
import type { NavItem } from "../types/nav";
|
||||
import { ChevronDown } from "lucide-svelte";
|
||||
import { ChevronDown, X } from "lucide-svelte";
|
||||
import { onMount } from "svelte";
|
||||
|
||||
export let navData: NavItem[] = [];
|
||||
|
||||
// Define a prop for the event handler
|
||||
export let onNavItemClick: (path: string) => void = () => {};
|
||||
export let visible: boolean = true;
|
||||
export let isMobile: boolean = false;
|
||||
|
||||
// Track which sections are expanded
|
||||
let expanded: Record<string, boolean> = {};
|
||||
@ -13,6 +14,21 @@
|
||||
// Track active item
|
||||
let activePath: string = "";
|
||||
|
||||
// Auto-expand the section containing the active item
|
||||
$: if (activePath) {
|
||||
// Find which section contains this path
|
||||
navData.forEach((item) => {
|
||||
if (item.children) {
|
||||
const hasActivePath = item.children.some(
|
||||
(child) => child.link === activePath,
|
||||
);
|
||||
if (hasActivePath) {
|
||||
expanded[item.label] = true;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function toggleSection(label: string) {
|
||||
expanded[label] = !expanded[label];
|
||||
}
|
||||
@ -28,22 +44,32 @@
|
||||
// Call the event handler prop
|
||||
onNavItemClick(docPath);
|
||||
}
|
||||
|
||||
// Initialize with first section expanded
|
||||
onMount(() => {
|
||||
if (navData.length > 0) {
|
||||
expanded[navData[0].label] = true;
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<aside
|
||||
class="sidebar w-64 bg-gray-50 border-r border-gray-200 h-screen fixed top-0 left-0 pt-16 overflow-y-auto shadow-sm"
|
||||
class="sidebar bg-gray-50 border-r border-gray-200 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'}"
|
||||
>
|
||||
<nav class="w-full">
|
||||
{#each navData as item}
|
||||
{#if item.children && item.children.length > 0}
|
||||
<div class="border-b border-gray-200">
|
||||
<button
|
||||
class="flex justify-between items-center w-full text-left p-4 hover:bg-gray-100 text-gray-700 font-medium"
|
||||
class="flex justify-between items-center w-full text-left p-3 sm:p-4 hover:bg-gray-100 text-gray-700 font-medium"
|
||||
on:click={() => toggleSection(item.label)}
|
||||
>
|
||||
{item.label}
|
||||
<span class="truncate">{item.label}</span>
|
||||
<ChevronDown
|
||||
class="h-4 w-4 transition-transform duration-200 {expanded[
|
||||
class="h-4 w-4 flex-shrink-0 transition-transform duration-200 {expanded[
|
||||
item.label
|
||||
]
|
||||
? 'rotate-180'
|
||||
@ -56,7 +82,7 @@
|
||||
{#each item.children as child}
|
||||
<a
|
||||
href={child.link}
|
||||
class="block p-3 pl-8 hover:bg-gray-100 text-gray-600 border-t border-gray-100 {activePath ===
|
||||
class="block p-3 pl-6 sm:pl-8 hover:bg-gray-100 text-gray-600 border-t border-gray-100 truncate {activePath ===
|
||||
child.link
|
||||
? 'bg-blue-50 text-blue-700 font-medium'
|
||||
: ''}"
|
||||
@ -72,7 +98,7 @@
|
||||
{:else}
|
||||
<a
|
||||
href={item.link}
|
||||
class="block p-4 hover:bg-gray-100 text-gray-700 border-b border-gray-200 {activePath ===
|
||||
class="block p-3 sm:p-4 hover:bg-gray-100 text-gray-700 border-b border-gray-200 truncate {activePath ===
|
||||
item.link
|
||||
? 'bg-blue-50 text-blue-700 font-medium'
|
||||
: ''}"
|
||||
|
@ -4,6 +4,14 @@ export default {
|
||||
'./src/**/*.{html,js,svelte,ts}',
|
||||
],
|
||||
theme: {
|
||||
screens: {
|
||||
'xs': '480px',
|
||||
'sm': '640px',
|
||||
'md': '768px',
|
||||
'lg': '1024px',
|
||||
'xl': '1280px',
|
||||
'2xl': '1536px',
|
||||
},
|
||||
extend: {
|
||||
colors: {
|
||||
blue: {
|
||||
|
Loading…
Reference in New Issue
Block a user