-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathLayout.astro
More file actions
176 lines (160 loc) · 12.2 KB
/
Layout.astro
File metadata and controls
176 lines (160 loc) · 12.2 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
---
import '../styles/global.css';
interface Props {
title: string;
description?: string;
image?: string;
}
const { title, description = 'Dev Proxy - Simulate API behaviors for testing and development', image } = Astro.props;
const canonicalURL = new URL(Astro.url.pathname, Astro.site ?? 'https://devproxy.net');
const ogImage = image ? new URL(image, Astro.site ?? 'https://devproxy.net').href : undefined;
---
<!doctype html>
<html lang="en" class="dark">
<head>
<meta charset="utf-8" />
<link rel="icon" type="image/svg+xml" href={`${import.meta.env.BASE_URL}favicon.svg`} />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="description" content={description} />
<meta name="generator" content={Astro.generator} />
<title>{title} | Dev Proxy</title>
<link rel="alternate" type="application/rss+xml" title="Dev Proxy Blog" href={`${import.meta.env.BASE_URL}rss.xml`} />
<!-- Open Graph -->
<meta property="og:type" content="website" />
<meta property="og:title" content={`${title} | Dev Proxy`} />
<meta property="og:description" content={description} />
<meta property="og:url" content={canonicalURL.href} />
{ogImage && <meta property="og:image" content={ogImage} />}
<!-- Twitter / X -->
<meta name="twitter:card" content={ogImage ? 'summary_large_image' : 'summary'} />
<meta name="twitter:title" content={`${title} | Dev Proxy`} />
<meta name="twitter:description" content={description} />
{ogImage && <meta name="twitter:image" content={ogImage} />}
<script is:inline>
(function() {
const theme = localStorage.getItem('theme');
if (theme === 'dark' || (!theme && window.matchMedia('(prefers-color-scheme: dark)').matches)) {
document.documentElement.classList.add('dark');
} else {
document.documentElement.classList.remove('dark');
}
})();
</script>
</head>
<body class="min-h-screen flex flex-col">
<nav class="border-b sticky top-0 z-50 backdrop-blur-sm" style="border-color: var(--border-primary); background: var(--bg-nav);">
<div class="max-w-6xl mx-auto px-4 h-16 flex items-center justify-between">
<a href={`${import.meta.env.BASE_URL}`} class="flex items-center gap-2 text-xl font-bold hover:text-purple-400 transition-colors">
<img src={`${import.meta.env.BASE_URL}icon.svg`} alt="Dev Proxy" class="w-6 h-6" />
Dev Proxy
</a>
<!-- Desktop nav -->
<div class="hidden md:flex items-center gap-6">
<a href={`${import.meta.env.BASE_URL}`} class="hover:text-purple-400 transition-colors" style="color: var(--text-muted);">Home</a>
<a href={`${import.meta.env.BASE_URL}blog/`} class="hover:text-purple-400 transition-colors" style="color: var(--text-muted);">Blog</a>
<a href={`${import.meta.env.BASE_URL}samples/`} class="hover:text-purple-400 transition-colors" style="color: var(--text-muted);">Samples</a>
<a href="https://learn.microsoft.com/microsoft-cloud/dev/dev-proxy/overview" target="_blank" rel="noopener" class="hover:text-purple-400 transition-colors" style="color: var(--text-muted);">Docs ↗</a>
<div class="flex items-center gap-3 ml-2 border-l pl-4" style="border-color: var(--border-primary);">
<a href="https://github.com/dotnet/dev-proxy" target="_blank" rel="noopener" class="hover:text-purple-400 transition-colors" style="color: var(--text-muted);" title="GitHub" aria-label="Dev Proxy on GitHub">
<svg class="w-5 h-5" fill="currentColor" viewBox="0 0 24 24" aria-hidden="true">
<path fill-rule="evenodd" d="M12 2C6.477 2 2 6.484 2 12.017c0 4.425 2.865 8.18 6.839 9.504.5.092.682-.217.682-.483 0-.237-.008-.868-.013-1.703-2.782.605-3.369-1.343-3.369-1.343-.454-1.158-1.11-1.466-1.11-1.466-.908-.62.069-.608.069-.608 1.003.07 1.531 1.032 1.531 1.032.892 1.53 2.341 1.088 2.91.832.092-.647.35-1.088.636-1.338-2.22-.253-4.555-1.113-4.555-4.951 0-1.093.39-1.988 1.029-2.688-.103-.253-.446-1.272.098-2.65 0 0 .84-.27 2.75 1.026A9.564 9.564 0 0112 6.844c.85.004 1.705.115 2.504.337 1.909-1.296 2.747-1.027 2.747-1.027.546 1.379.202 2.398.1 2.651.64.7 1.028 1.595 1.028 2.688 0 3.848-2.339 4.695-4.566 4.943.359.309.678.92.678 1.855 0 1.338-.012 2.419-.012 2.747 0 .268.18.58.688.482A10.019 10.019 0 0022 12.017C22 6.484 17.522 2 12 2z" clip-rule="evenodd" />
</svg>
</a>
<a href={`${import.meta.env.BASE_URL}rss.xml`} class="hover:text-purple-400 transition-colors" style="color: var(--text-muted);" title="RSS Feed" aria-label="RSS Feed">
<svg class="w-5 h-5" fill="currentColor" viewBox="0 0 24 24" aria-hidden="true">
<path d="M6.18 15.64a2.18 2.18 0 012.18 2.18C8.36 19.01 7.37 20 6.18 20 5 20 4 19.01 4 17.82a2.18 2.18 0 012.18-2.18M4 4.44A15.56 15.56 0 0119.56 20h-2.83A12.73 12.73 0 004 7.27V4.44m0 5.66a9.9 9.9 0 019.9 9.9h-2.83A7.07 7.07 0 004 12.93V10.1z" />
</svg>
</a>
<button id="theme-toggle" class="hover:text-purple-400 transition-colors cursor-pointer" style="color: var(--text-muted);" title="Toggle theme" aria-label="Toggle theme" type="button">
<svg id="theme-icon-sun" class="w-5 h-5 hidden" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2">
<path stroke-linecap="round" stroke-linejoin="round" d="M12 3v1m0 16v1m9-9h-1M4 12H3m15.364 6.364l-.707-.707M6.343 6.343l-.707-.707m12.728 0l-.707.707M6.343 17.657l-.707.707M16 12a4 4 0 11-8 0 4 4 0 018 0z" />
</svg>
<svg id="theme-icon-moon" class="w-5 h-5 hidden" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2">
<path stroke-linecap="round" stroke-linejoin="round" d="M20.354 15.354A9 9 0 018.646 3.646 9.003 9.003 0 0012 21a9.003 9.003 0 008.354-5.646z" />
</svg>
</button>
</div>
</div>
<!-- Mobile: icons + hamburger -->
<div class="flex md:hidden items-center gap-3">
<a href="https://github.com/dotnet/dev-proxy" target="_blank" rel="noopener" class="hover:text-purple-400 transition-colors" style="color: var(--text-muted);" title="GitHub" aria-label="Dev Proxy on GitHub">
<svg class="w-5 h-5" fill="currentColor" viewBox="0 0 24 24" aria-hidden="true">
<path fill-rule="evenodd" d="M12 2C6.477 2 2 6.484 2 12.017c0 4.425 2.865 8.18 6.839 9.504.5.092.682-.217.682-.483 0-.237-.008-.868-.013-1.703-2.782.605-3.369-1.343-3.369-1.343-.454-1.158-1.11-1.466-1.11-1.466-.908-.62.069-.608.069-.608 1.003.07 1.531 1.032 1.531 1.032.892 1.53 2.341 1.088 2.91.832.092-.647.35-1.088.636-1.338-2.22-.253-4.555-1.113-4.555-4.951 0-1.093.39-1.988 1.029-2.688-.103-.253-.446-1.272.098-2.65 0 0 .84-.27 2.75 1.026A9.564 9.564 0 0112 6.844c.85.004 1.705.115 2.504.337 1.909-1.296 2.747-1.027 2.747-1.027.546 1.379.202 2.398.1 2.651.64.7 1.028 1.595 1.028 2.688 0 3.848-2.339 4.695-4.566 4.943.359.309.678.92.678 1.855 0 1.338-.012 2.419-.012 2.747 0 .268.18.58.688.482A10.019 10.019 0 0022 12.017C22 6.484 17.522 2 12 2z" clip-rule="evenodd" />
</svg>
</a>
<a href={`${import.meta.env.BASE_URL}rss.xml`} class="hover:text-purple-400 transition-colors" style="color: var(--text-muted);" title="RSS Feed" aria-label="RSS Feed">
<svg class="w-5 h-5" fill="currentColor" viewBox="0 0 24 24" aria-hidden="true">
<path d="M6.18 15.64a2.18 2.18 0 012.18 2.18C8.36 19.01 7.37 20 6.18 20 5 20 4 19.01 4 17.82a2.18 2.18 0 012.18-2.18M4 4.44A15.56 15.56 0 0119.56 20h-2.83A12.73 12.73 0 004 7.27V4.44m0 5.66a9.9 9.9 0 019.9 9.9h-2.83A7.07 7.07 0 004 12.93V10.1z" />
</svg>
</a>
<button id="theme-toggle-mobile" class="hover:text-purple-400 transition-colors cursor-pointer" style="color: var(--text-muted);" title="Toggle theme" aria-label="Toggle theme" type="button">
<svg id="theme-icon-sun-mobile" class="w-5 h-5 hidden" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2">
<path stroke-linecap="round" stroke-linejoin="round" d="M12 3v1m0 16v1m9-9h-1M4 12H3m15.364 6.364l-.707-.707M6.343 6.343l-.707-.707m12.728 0l-.707.707M6.343 17.657l-.707.707M16 12a4 4 0 11-8 0 4 4 0 018 0z" />
</svg>
<svg id="theme-icon-moon-mobile" class="w-5 h-5 hidden" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2">
<path stroke-linecap="round" stroke-linejoin="round" d="M20.354 15.354A9 9 0 018.646 3.646 9.003 9.003 0 0012 21a9.003 9.003 0 008.354-5.646z" />
</svg>
</button>
<button id="mobile-menu-btn" class="hover:text-purple-400 transition-colors cursor-pointer p-1" style="color: var(--text-muted);" aria-label="Open menu" type="button">
<svg class="w-6 h-6" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2">
<path id="menu-icon-open" stroke-linecap="round" stroke-linejoin="round" d="M4 6h16M4 12h16M4 18h16" />
<path id="menu-icon-close" class="hidden" stroke-linecap="round" stroke-linejoin="round" d="M6 18L18 6M6 6l12 12" />
</svg>
</button>
</div>
</div>
<!-- Mobile menu panel -->
<div id="mobile-menu" class="hidden md:hidden border-t" style="border-color: var(--border-primary); background: var(--bg-nav);">
<div class="max-w-6xl mx-auto px-4 py-4 flex flex-col gap-3">
<a href={`${import.meta.env.BASE_URL}`} class="py-2 hover:text-purple-400 transition-colors" style="color: var(--text-muted);">Home</a>
<a href={`${import.meta.env.BASE_URL}blog/`} class="py-2 hover:text-purple-400 transition-colors" style="color: var(--text-muted);">Blog</a>
<a href={`${import.meta.env.BASE_URL}samples/`} class="py-2 hover:text-purple-400 transition-colors" style="color: var(--text-muted);">Samples</a>
<a href="https://learn.microsoft.com/microsoft-cloud/dev/dev-proxy/overview" target="_blank" rel="noopener" class="py-2 hover:text-purple-400 transition-colors" style="color: var(--text-muted);">Docs ↗</a>
</div>
</div>
</nav>
<main class="flex-1 overflow-x-hidden">
<slot />
</main>
<footer class="border-t py-8 mt-16" style="border-color: var(--border-primary);">
<div class="max-w-6xl mx-auto px-4 text-center text-sm" style="color: var(--text-faint);">
<p>© {new Date().getFullYear()} Dev Proxy.</p>
</div>
</footer>
<script is:inline>
(function() {
// Theme toggle (desktop + mobile)
var toggles = [document.getElementById('theme-toggle'), document.getElementById('theme-toggle-mobile')];
var sunIcons = [document.getElementById('theme-icon-sun'), document.getElementById('theme-icon-sun-mobile')];
var moonIcons = [document.getElementById('theme-icon-moon'), document.getElementById('theme-icon-moon-mobile')];
function updateIcons() {
var isDark = document.documentElement.classList.contains('dark');
sunIcons.forEach(function(el) { if (el) el.classList.toggle('hidden', !isDark); });
moonIcons.forEach(function(el) { if (el) el.classList.toggle('hidden', isDark); });
}
updateIcons();
toggles.forEach(function(btn) {
if (btn) btn.addEventListener('click', function() {
var isDark = document.documentElement.classList.toggle('dark');
localStorage.setItem('theme', isDark ? 'dark' : 'light');
updateIcons();
});
});
// Mobile menu
var menuBtn = document.getElementById('mobile-menu-btn');
var menu = document.getElementById('mobile-menu');
var iconOpen = document.getElementById('menu-icon-open');
var iconClose = document.getElementById('menu-icon-close');
if (menuBtn && menu) {
menuBtn.addEventListener('click', function() {
var isOpen = !menu.classList.contains('hidden');
menu.classList.toggle('hidden');
iconOpen.classList.toggle('hidden', !isOpen);
iconClose.classList.toggle('hidden', isOpen);
menuBtn.setAttribute('aria-label', isOpen ? 'Open menu' : 'Close menu');
});
}
})();
</script>
</body>
</html>