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
|
*.sln
|
||||||
*.sw?
|
*.sw?
|
||||||
*.pnpm-store
|
*.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
|
// Footer component
|
||||||
</script>
|
</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="container mx-auto max-w-6xl">
|
||||||
<div class="flex flex-col md:flex-row justify-between items-center">
|
<div
|
||||||
<div class="mb-4 md:mb-0">
|
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>
|
<div class="text-lg font-semibold text-blue-800">SecureWeb</div>
|
||||||
<p class="text-gray-600 text-sm mt-1">
|
<p class="text-gray-600 text-sm mt-1">
|
||||||
Secure and reliable web solutions
|
Secure and reliable web solutions
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</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
|
<a
|
||||||
href="/"
|
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
|
>Home</a
|
||||||
>
|
>
|
||||||
<a
|
<a
|
||||||
href="/about"
|
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
|
>About</a
|
||||||
>
|
>
|
||||||
<a
|
<a
|
||||||
href="/services"
|
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
|
>Services</a
|
||||||
>
|
>
|
||||||
<a
|
<a
|
||||||
href="/contact"
|
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
|
>Contact</a
|
||||||
>
|
>
|
||||||
</div>
|
</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
|
<a
|
||||||
href="/twitter"
|
href="/twitter"
|
||||||
aria-label="Twitter"
|
aria-label="Twitter"
|
||||||
@ -88,7 +97,7 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<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>
|
<p>
|
||||||
© {new Date().getFullYear()} SecureWeb. All rights reserved.
|
© {new Date().getFullYear()} SecureWeb. All rights reserved.
|
||||||
|
@ -8,34 +8,38 @@
|
|||||||
$: actualPath = contentPath || "introduction/introduction";
|
$: actualPath = contentPath || "introduction/introduction";
|
||||||
</script>
|
</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}
|
{#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} />
|
<MarkdownContent path={actualPath} />
|
||||||
</div>
|
</div>
|
||||||
{:else}
|
{:else}
|
||||||
<!-- Hero Section -->
|
<!-- 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: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
|
<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>
|
Welcome to <span class="text-blue-600">SecureWeb</span>
|
||||||
</h1>
|
</h1>
|
||||||
<p
|
<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
|
A comprehensive platform for secure and reliable web
|
||||||
solutions designed for modern businesses.
|
solutions designed for modern businesses.
|
||||||
</p>
|
</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
|
<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
|
>Get Started</button
|
||||||
>
|
>
|
||||||
<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
|
>Learn More</button
|
||||||
>
|
>
|
||||||
</div>
|
</div>
|
||||||
@ -45,70 +49,89 @@
|
|||||||
src="https://via.placeholder.com/600x400/f3f4f6/1e40af?text=SecureWeb"
|
src="https://via.placeholder.com/600x400/f3f4f6/1e40af?text=SecureWeb"
|
||||||
alt="SecureWeb Platform"
|
alt="SecureWeb Platform"
|
||||||
class="rounded-lg shadow-lg w-full"
|
class="rounded-lg shadow-lg w-full"
|
||||||
|
loading="lazy"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<!-- Features Section -->
|
<!-- Features Section -->
|
||||||
<section class="mb-20">
|
<section class="mb-12 sm:mb-16 md:mb-20">
|
||||||
<div class="text-center mb-12">
|
<div class="text-center mb-8 sm:mb-12">
|
||||||
<h2 class="text-3xl font-bold mb-4 text-gray-900">
|
<h2
|
||||||
|
class="text-2xl sm:text-3xl font-bold mb-3 sm:mb-4 text-gray-900"
|
||||||
|
>
|
||||||
Our Features
|
Our Features
|
||||||
</h2>
|
</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
|
Discover what makes SecureWeb the preferred choice for
|
||||||
security-conscious businesses.
|
security-conscious businesses.
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</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
|
<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
|
<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>
|
</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
|
Advanced Security
|
||||||
</h3>
|
</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
|
State-of-the-art encryption and security protocols to
|
||||||
keep your data protected from threats.
|
keep your data protected from threats.
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<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
|
<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>
|
</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
|
Lightning Performance
|
||||||
</h3>
|
</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
|
Optimized for speed and efficiency, ensuring a smooth
|
||||||
and responsive user experience.
|
and responsive user experience.
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<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
|
<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>
|
</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
|
Responsive Design
|
||||||
</h3>
|
</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
|
Fully responsive layouts that provide a seamless
|
||||||
experience across all devices and screen sizes.
|
experience across all devices and screen sizes.
|
||||||
</p>
|
</p>
|
||||||
@ -119,22 +142,24 @@
|
|||||||
<!-- CTA Section -->
|
<!-- CTA Section -->
|
||||||
<section>
|
<section>
|
||||||
<div
|
<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="md:flex md:items-center md:justify-between">
|
||||||
<div class="mb-8 md:mb-0 md:w-2/3">
|
<div class="mb-6 md:mb-0 md:w-2/3 md:pr-6">
|
||||||
<h2 class="text-3xl font-bold mb-4">
|
<h2 class="text-2xl sm:text-3xl font-bold mb-3 sm:mb-4">
|
||||||
Ready to Get Started?
|
Ready to Get Started?
|
||||||
</h2>
|
</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
|
Join thousands of satisfied users who trust
|
||||||
SecureWeb for their web security needs. Sign up
|
SecureWeb for their web security needs. Sign up
|
||||||
today and experience the difference.
|
today and experience the difference.
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div class="flex justify-center md:justify-end">
|
||||||
<button
|
<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
|
Sign Up Now
|
||||||
</button>
|
</button>
|
||||||
|
@ -12,19 +12,35 @@
|
|||||||
|
|
||||||
function toggleSidebar() {
|
function toggleSidebar() {
|
||||||
sidebarVisible = !sidebarVisible;
|
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) {
|
function handleNavItemClick(path: string) {
|
||||||
selectedContentPath = path;
|
selectedContentPath = path;
|
||||||
|
// Auto-close sidebar on mobile after navigation
|
||||||
|
if (isMobile) {
|
||||||
|
sidebarVisible = false;
|
||||||
|
document.body.classList.remove("overflow-hidden");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
onMount(() => {
|
onMount(() => {
|
||||||
const checkMobile = () => {
|
const checkMobile = () => {
|
||||||
|
const wasMobile = isMobile;
|
||||||
isMobile = window.innerWidth < 768;
|
isMobile = window.innerWidth < 768;
|
||||||
if (isMobile) {
|
|
||||||
sidebarVisible = false;
|
// Only change sidebar visibility when transitioning between mobile and desktop
|
||||||
} else {
|
if (wasMobile !== isMobile) {
|
||||||
sidebarVisible = true;
|
if (isMobile) {
|
||||||
|
sidebarVisible = false;
|
||||||
|
} else {
|
||||||
|
sidebarVisible = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -38,19 +54,34 @@
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="flex flex-col min-h-screen bg-gray-50">
|
<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>
|
<NavDataProvider let:navData>
|
||||||
{#if sidebarVisible}
|
<!-- Sidebar with improved mobile handling -->
|
||||||
<Sidebar {navData} onNavItemClick={handleNavItemClick} />
|
<Sidebar
|
||||||
{/if}
|
{navData}
|
||||||
|
onNavItemClick={handleNavItemClick}
|
||||||
|
visible={sidebarVisible}
|
||||||
|
{isMobile}
|
||||||
|
/>
|
||||||
|
|
||||||
<main
|
<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
|
<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}
|
{#if selectedContentPath}
|
||||||
<Home contentPath={selectedContentPath} />
|
<Home contentPath={selectedContentPath} />
|
||||||
|
@ -94,41 +94,57 @@
|
|||||||
|
|
||||||
<style>
|
<style>
|
||||||
.markdown-content {
|
.markdown-content {
|
||||||
padding: 1rem;
|
padding: 0.5rem;
|
||||||
max-width: 100%;
|
max-width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@media (min-width: 640px) {
|
||||||
|
.markdown-content {
|
||||||
|
padding: 1rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.loading,
|
.loading,
|
||||||
.error {
|
.error {
|
||||||
padding: 2rem;
|
padding: 1rem;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@media (min-width: 640px) {
|
||||||
|
.loading,
|
||||||
|
.error {
|
||||||
|
padding: 2rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.error {
|
.error {
|
||||||
color: #e53e3e;
|
color: #e53e3e;
|
||||||
}
|
}
|
||||||
|
|
||||||
.content :global(h1) {
|
.content :global(h1) {
|
||||||
font-size: 2.5rem;
|
font-size: 1.75rem;
|
||||||
font-weight: 700;
|
font-weight: 700;
|
||||||
margin-bottom: 1.5rem;
|
margin-bottom: 1rem;
|
||||||
color: #1e40af;
|
color: #1e40af;
|
||||||
|
word-break: break-word;
|
||||||
}
|
}
|
||||||
|
|
||||||
.content :global(h2) {
|
.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-size: 1.5rem;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
margin-top: 1.5rem;
|
margin-top: 1.5rem;
|
||||||
margin-bottom: 0.75rem;
|
margin-bottom: 0.75rem;
|
||||||
color: #1e3a8a;
|
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) {
|
.content :global(p) {
|
||||||
@ -139,7 +155,7 @@
|
|||||||
.content :global(ul),
|
.content :global(ul),
|
||||||
.content :global(ol) {
|
.content :global(ol) {
|
||||||
margin-bottom: 1rem;
|
margin-bottom: 1rem;
|
||||||
margin-left: 2rem;
|
margin-left: 1.5rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.content :global(li) {
|
.content :global(li) {
|
||||||
@ -149,6 +165,7 @@
|
|||||||
.content :global(a) {
|
.content :global(a) {
|
||||||
color: #2563eb;
|
color: #2563eb;
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
|
word-break: break-word;
|
||||||
}
|
}
|
||||||
|
|
||||||
.content :global(a:hover) {
|
.content :global(a:hover) {
|
||||||
@ -169,11 +186,14 @@
|
|||||||
padding: 0.2rem 0.4rem;
|
padding: 0.2rem 0.4rem;
|
||||||
border-radius: 0.25rem;
|
border-radius: 0.25rem;
|
||||||
font-family: monospace;
|
font-family: monospace;
|
||||||
|
font-size: 0.875em;
|
||||||
|
word-break: break-word;
|
||||||
|
white-space: pre-wrap;
|
||||||
}
|
}
|
||||||
|
|
||||||
.content :global(pre) {
|
.content :global(pre) {
|
||||||
background-color: #f3f4f6;
|
background-color: #f3f4f6;
|
||||||
padding: 1rem;
|
padding: 0.75rem;
|
||||||
border-radius: 0.5rem;
|
border-radius: 0.5rem;
|
||||||
overflow-x: auto;
|
overflow-x: auto;
|
||||||
margin-bottom: 1rem;
|
margin-bottom: 1rem;
|
||||||
@ -182,6 +202,8 @@
|
|||||||
.content :global(pre code) {
|
.content :global(pre code) {
|
||||||
background-color: transparent;
|
background-color: transparent;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
|
white-space: pre;
|
||||||
|
word-break: normal;
|
||||||
}
|
}
|
||||||
|
|
||||||
.content :global(img) {
|
.content :global(img) {
|
||||||
@ -189,27 +211,59 @@
|
|||||||
height: auto;
|
height: auto;
|
||||||
border-radius: 0.5rem;
|
border-radius: 0.5rem;
|
||||||
margin: 1rem 0;
|
margin: 1rem 0;
|
||||||
|
display: block;
|
||||||
}
|
}
|
||||||
|
|
||||||
.content :global(hr) {
|
.content :global(hr) {
|
||||||
border: 0;
|
border: 0;
|
||||||
border-top: 1px solid #e5e7eb;
|
border-top: 1px solid #e5e7eb;
|
||||||
margin: 2rem 0;
|
margin: 1.5rem 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.content :global(table) {
|
.content :global(table) {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
border-collapse: collapse;
|
border-collapse: collapse;
|
||||||
margin-bottom: 1rem;
|
margin-bottom: 1rem;
|
||||||
|
display: block;
|
||||||
|
overflow-x: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
.content :global(th),
|
.content :global(th),
|
||||||
.content :global(td) {
|
.content :global(td) {
|
||||||
border: 1px solid #e5e7eb;
|
border: 1px solid #e5e7eb;
|
||||||
padding: 0.5rem;
|
padding: 0.5rem;
|
||||||
|
min-width: 100px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.content :global(th) {
|
.content :global(th) {
|
||||||
background-color: #f9fafb;
|
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>
|
</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">
|
<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 toggleSidebar: () => void = () => {};
|
||||||
|
export let isMobile: boolean = false;
|
||||||
|
export let sidebarVisible: boolean = false;
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<header
|
<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">
|
<div class="flex items-center">
|
||||||
<button
|
<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}
|
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>
|
</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>
|
||||||
|
|
||||||
<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">
|
<div class="relative hidden md:block">
|
||||||
<Search
|
<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-gray-400"
|
||||||
@ -26,12 +40,12 @@
|
|||||||
<input
|
<input
|
||||||
type="text"
|
type="text"
|
||||||
placeholder="Search..."
|
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>
|
</div>
|
||||||
|
|
||||||
<button
|
<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" />
|
<Bell class="h-5 w-5" />
|
||||||
<span
|
<span
|
||||||
|
@ -1,11 +1,12 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import type { NavItem } from "../types/nav";
|
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[] = [];
|
export let navData: NavItem[] = [];
|
||||||
|
|
||||||
// Define a prop for the event handler
|
|
||||||
export let onNavItemClick: (path: string) => void = () => {};
|
export let onNavItemClick: (path: string) => void = () => {};
|
||||||
|
export let visible: boolean = true;
|
||||||
|
export let isMobile: boolean = false;
|
||||||
|
|
||||||
// Track which sections are expanded
|
// Track which sections are expanded
|
||||||
let expanded: Record<string, boolean> = {};
|
let expanded: Record<string, boolean> = {};
|
||||||
@ -13,6 +14,21 @@
|
|||||||
// Track active item
|
// Track active item
|
||||||
let activePath: string = "";
|
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) {
|
function toggleSection(label: string) {
|
||||||
expanded[label] = !expanded[label];
|
expanded[label] = !expanded[label];
|
||||||
}
|
}
|
||||||
@ -28,22 +44,32 @@
|
|||||||
// Call the event handler prop
|
// Call the event handler prop
|
||||||
onNavItemClick(docPath);
|
onNavItemClick(docPath);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Initialize with first section expanded
|
||||||
|
onMount(() => {
|
||||||
|
if (navData.length > 0) {
|
||||||
|
expanded[navData[0].label] = true;
|
||||||
|
}
|
||||||
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<aside
|
<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">
|
<nav class="w-full">
|
||||||
{#each navData as item}
|
{#each navData as item}
|
||||||
{#if item.children && item.children.length > 0}
|
{#if item.children && item.children.length > 0}
|
||||||
<div class="border-b border-gray-200">
|
<div class="border-b border-gray-200">
|
||||||
<button
|
<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)}
|
on:click={() => toggleSection(item.label)}
|
||||||
>
|
>
|
||||||
{item.label}
|
<span class="truncate">{item.label}</span>
|
||||||
<ChevronDown
|
<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
|
item.label
|
||||||
]
|
]
|
||||||
? 'rotate-180'
|
? 'rotate-180'
|
||||||
@ -56,7 +82,7 @@
|
|||||||
{#each item.children as child}
|
{#each item.children as child}
|
||||||
<a
|
<a
|
||||||
href={child.link}
|
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
|
child.link
|
||||||
? 'bg-blue-50 text-blue-700 font-medium'
|
? 'bg-blue-50 text-blue-700 font-medium'
|
||||||
: ''}"
|
: ''}"
|
||||||
@ -72,7 +98,7 @@
|
|||||||
{:else}
|
{:else}
|
||||||
<a
|
<a
|
||||||
href={item.link}
|
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
|
item.link
|
||||||
? 'bg-blue-50 text-blue-700 font-medium'
|
? 'bg-blue-50 text-blue-700 font-medium'
|
||||||
: ''}"
|
: ''}"
|
||||||
|
@ -4,6 +4,14 @@ export default {
|
|||||||
'./src/**/*.{html,js,svelte,ts}',
|
'./src/**/*.{html,js,svelte,ts}',
|
||||||
],
|
],
|
||||||
theme: {
|
theme: {
|
||||||
|
screens: {
|
||||||
|
'xs': '480px',
|
||||||
|
'sm': '640px',
|
||||||
|
'md': '768px',
|
||||||
|
'lg': '1024px',
|
||||||
|
'xl': '1280px',
|
||||||
|
'2xl': '1536px',
|
||||||
|
},
|
||||||
extend: {
|
extend: {
|
||||||
colors: {
|
colors: {
|
||||||
blue: {
|
blue: {
|
||||||
|
Loading…
Reference in New Issue
Block a user