Skip to content

Commit fce98b6

Browse files
authored
Merge pull request #2990 from appwrite/feat/static-images-and-cta
refactor(components): update footer navigation and enhance asset hand…
2 parents 50144dc + e3962c7 commit fce98b6

63 files changed

Lines changed: 1031 additions & 1418 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.optimize-cache.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,9 @@
1212
"static/assets/logotype/white.png": "a6c0a516cafa38798b578597a50e1edc967494e986ee1a74e9170e3fa45c67fc",
1313
"static/assets/visuals/auth.jpg": "a310ed768b63e73eb09452352ffa5a59638b4223aebbcaac80bdb232b24de64f",
1414
"static/assets/visuals/auth.png": "6634419bdf4972706d08a03a148fbf2f0053377dca85ffd7d95ecc3e016a009b",
15+
"static/assets/visuals/dashboard-screenshot.png": "931eec1e7232b5754684e2652999648f3fada876b3d39351360a5bb87008367c",
1516
"static/assets/visuals/dashboard.jpg": "fbb2bae3d39f500337d6c4bca64ddaaea163a177ab3db77641ecd7050c43c10e",
16-
"static/assets/visuals/dashboard.png": "544b8af8bdb33546d5746fac6427c815248b2c321c4f28c3be7870c040b265b3",
17+
"static/assets/visuals/dashboard.png": "931eec1e7232b5754684e2652999648f3fada876b3d39351360a5bb87008367c",
1718
"static/assets/visuals/databases.jpg": "0de2e6b470f9903db803120d03e1b3abe21728802564d2702989a48128bd0abc",
1819
"static/assets/visuals/databases.png": "d50ce8119e31f7b8099e9b98fe38a7066adcf421eb061756db900b5e60f257fe",
1920
"static/assets/visuals/functions.jpg": "cb9dc9f434329949a8a0bd1302033e4106d4e6f16e05dada696529800e7236b3",

src/hooks.server.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,7 @@ const securityheaders: Handle = async ({ event, resolve }) => {
106106
'https://*.appwrite.io',
107107
'https://*.appwrite.org',
108108
'https://*.appwrite.network',
109+
'https://status.appwrite.online',
109110
'https://*.sentry.io',
110111
'https://*.plausible.io',
111112
'https://plausible.io',
Lines changed: 180 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,180 @@
1+
<script lang="ts">
2+
import { browser } from '$app/environment';
3+
import { onMount } from 'svelte';
4+
import { trackEvent } from '$lib/actions/analytics';
5+
import {
6+
fetchAppwriteCloudAggregateState,
7+
type AppwriteCloudAggregateState
8+
} from '$lib/status/fetch-appwrite-cloud-aggregate-state';
9+
10+
const STATUS_PAGE_URL = 'https://status.appwrite.online';
11+
const REFRESH_MS = 60_000;
12+
13+
let aggregateState: AppwriteCloudAggregateState = 'operational';
14+
15+
function labelFor(state: AppwriteCloudAggregateState): string {
16+
switch (state) {
17+
case 'maintenance':
18+
return 'Maintenance in progress';
19+
case 'downtime':
20+
return 'Major service disruption';
21+
case 'degraded':
22+
return 'Some services affected';
23+
default:
24+
return 'All systems normal';
25+
}
26+
}
27+
28+
onMount(() => {
29+
if (!browser) {
30+
return;
31+
}
32+
33+
let cancelled = false;
34+
35+
const refresh = () => {
36+
void fetchAppwriteCloudAggregateState().then((next) => {
37+
if (!cancelled) {
38+
aggregateState = next;
39+
}
40+
});
41+
};
42+
43+
/** Defer first fetch until idle (or short deadline) so it never competes with first paint. */
44+
let idleId: number | undefined;
45+
let fallbackId: ReturnType<typeof setTimeout> | undefined;
46+
if (typeof requestIdleCallback !== 'undefined') {
47+
idleId = requestIdleCallback(() => refresh(), { timeout: 2000 });
48+
} else {
49+
fallbackId = setTimeout(() => refresh(), 0);
50+
}
51+
52+
const interval = window.setInterval(refresh, REFRESH_MS);
53+
54+
return () => {
55+
cancelled = true;
56+
window.clearInterval(interval);
57+
if (idleId !== undefined && typeof cancelIdleCallback !== 'undefined') {
58+
cancelIdleCallback(idleId);
59+
}
60+
if (fallbackId !== undefined) {
61+
clearTimeout(fallbackId);
62+
}
63+
};
64+
});
65+
</script>
66+
67+
<a
68+
class="web-footer-cloud-status web-icon-button is-more-content"
69+
href={STATUS_PAGE_URL}
70+
target="_blank"
71+
rel="noopener noreferrer"
72+
data-state={aggregateState}
73+
aria-label="{labelFor(aggregateState)}. Opens the public status page in a new tab."
74+
onclick={() => trackEvent('footer-cloud-status-badge-click')}
75+
>
76+
<span class="web-footer-cloud-status__mark" aria-hidden="true">
77+
{#if aggregateState === 'operational'}
78+
<span class="web-icon-check web-footer-cloud-status__glyph"></span>
79+
{:else if aggregateState === 'maintenance'}
80+
<svg
81+
class="web-footer-cloud-status__svg"
82+
viewBox="0 0 24 24"
83+
fill="none"
84+
aria-hidden="true"
85+
>
86+
<path
87+
d="M14.7 6.3a1 1 0 0 0 0 1.4l1.6 1.6a1 1 0 0 0 1.4 0l3.77-3.77a6 6 0 0 1-7.94 7.94l-6.91 6.91a2.12 2.12 0 0 1-3-3l6.91-6.91a6 6 0 0 1 7.94-7.94l-3.76 3.76z"
88+
fill="currentColor"
89+
/>
90+
</svg>
91+
{:else}
92+
<svg class="web-footer-cloud-status__svg" viewBox="0 0 24 24" aria-hidden="true">
93+
<path
94+
fill="currentColor"
95+
d="M12 3 2 20h20L12 3zm0 3.5L17.5 18h-11L12 6.5zM11 10h2v5h-2v-5zm0 6h2v2h-2v-2z"
96+
/>
97+
</svg>
98+
{/if}
99+
</span>
100+
<span class="web-footer-cloud-status__label">{labelFor(aggregateState)}</span>
101+
</a>
102+
103+
<style lang="scss">
104+
@use '$scss/abstract' as *;
105+
106+
/* Same chrome as `.web-icon-button.is-more-content`, extended for label + status tint */
107+
.web-footer-cloud-status.web-icon-button.is-more-content {
108+
position: relative;
109+
display: inline-flex;
110+
max-inline-size: 100%;
111+
align-items: center;
112+
gap: pxToRem(6);
113+
min-block-size: pxToRem(26);
114+
padding-block: pxToRem(1);
115+
padding-inline: pxToRem(5) pxToRem(7);
116+
text-decoration: none;
117+
inline-size: fit-content;
118+
/* Slightly smaller than footer link copy so the chip reads as secondary */
119+
font-size: calc(var(--web-footer-nav-link-font-size, var(--text-caption)) * 0.9);
120+
font-weight: var(--font-weight-regular);
121+
line-height: var(--web-footer-nav-link-line-height, var(--text-caption--line-height));
122+
letter-spacing: var(
123+
--web-footer-nav-link-letter-spacing,
124+
var(--text-caption--letter-spacing)
125+
);
126+
/*
127+
* `web-icon.css` matches `[class*=' web-icon-']` — that substring appears inside the
128+
* token `web-icon-button`, so the whole anchor wrongly gets `font-family: web-icon !important`.
129+
* Reset to body UI font; keep icon font only on the glyph span.
130+
*/
131+
font-family: var(--web-font-family-inter), arial, sans-serif !important;
132+
133+
.web-footer-cloud-status__label {
134+
white-space: nowrap;
135+
}
136+
137+
.web-footer-cloud-status__mark {
138+
display: flex;
139+
width: pxToRem(16);
140+
height: pxToRem(16);
141+
flex-shrink: 0;
142+
align-items: center;
143+
justify-content: center;
144+
border-radius: pxToRem(6);
145+
background-color: hsl(var(--web-color-smooth));
146+
color: hsl(var(--web-color-secondary));
147+
}
148+
149+
.web-footer-cloud-status__glyph {
150+
font-family: 'web-icon' !important;
151+
font-size: pxToRem(9);
152+
line-height: 1;
153+
}
154+
155+
.web-footer-cloud-status__svg {
156+
width: pxToRem(10);
157+
height: pxToRem(10);
158+
}
159+
160+
&[data-state='operational'] .web-footer-cloud-status__mark {
161+
background-color: hsl(var(--web-color-mint-500) / 0.14);
162+
color: hsl(var(--web-color-mint-500));
163+
}
164+
165+
&[data-state='degraded'] .web-footer-cloud-status__mark {
166+
background-color: hsl(var(--web-color-yellow-500) / 0.14);
167+
color: hsl(var(--web-color-yellow-700));
168+
}
169+
170+
&[data-state='downtime'] .web-footer-cloud-status__mark {
171+
background-color: hsl(var(--web-color-red-500) / 0.14);
172+
color: hsl(var(--web-color-red-700));
173+
}
174+
175+
&[data-state='maintenance'] .web-footer-cloud-status__mark {
176+
background-color: hsl(var(--web-color-blue-500) / 0.14);
177+
color: hsl(var(--web-color-blue-700));
178+
}
179+
}
180+
</style>

src/lib/components/FooterNav.svelte

Lines changed: 60 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -47,10 +47,6 @@
4747
{ label: 'Docs', href: '/docs' },
4848
{ label: 'Integrations', href: '/integrations' },
4949
{ label: 'Community', href: '/community' },
50-
{
51-
label: 'Backend as a service (BaaS)',
52-
href: '/blog/post/backend-as-a-service'
53-
},
5450
{ label: 'Init', href: '/init' },
5551
{ label: 'Threads', href: '/threads' },
5652
{ label: 'Changelog', href: '/changelog' },
@@ -91,6 +87,40 @@
9187
{ label: 'Education', href: '/education' },
9288
{ label: 'Partners', href: '/partners' }
9389
],
90+
Compare: [
91+
{
92+
label: 'Appwrite vs. Supabase',
93+
href: '/blog/post/appwrite-compared-to-supabase'
94+
},
95+
{
96+
label: 'Appwrite vs. Firebase',
97+
href: '/blog/post/open-source-firebase-alternative'
98+
},
99+
{
100+
label: 'Appwrite vs. Neon',
101+
href: '/blog/post/appwrite-vs-neon-ai-backends'
102+
},
103+
{
104+
label: 'Appwrite vs. Vercel',
105+
href: '/blog/post/open-source-vercel-alternative'
106+
},
107+
{
108+
label: 'Appwrite vs. Netlify',
109+
href: '/blog/post/open-source-netlify-alternative'
110+
},
111+
{
112+
label: 'Appwrite vs. Cloudinary',
113+
href: '/blog/post/appwrite-vs-cloudinary'
114+
},
115+
{
116+
label: 'Appwrite vs. Auth0',
117+
href: '/blog/post/appwrite-vs-auth0'
118+
},
119+
{
120+
label: 'Backend as a service (BaaS)',
121+
href: '/blog/post/backend-as-a-service'
122+
}
123+
],
94124
About: [
95125
{ label: 'Company', href: '/company' },
96126
{ label: 'Pricing', href: '/pricing' },
@@ -118,16 +148,29 @@
118148
class="web-footer-nav relative mt-24"
119149
class:web-u-sep-block-start={!noBorder}
120150
>
121-
<img class="web-logo" src="/images/logos/appwrite.svg" alt="appwrite" height="24" width="130" />
151+
<img
152+
class="web-logo web-is-only-mobile"
153+
src="/images/logos/appwrite.svg"
154+
alt="appwrite"
155+
height="24"
156+
width="130"
157+
/>
122158
<ul class="web-footer-nav-main-list" use:melt={$root}>
123159
{#each Object.entries(links) as [title, items]}
124-
<li class="web-footer-nav-main-item web-is-not-mobile">
160+
<li
161+
class="web-footer-nav-main-item web-is-not-mobile"
162+
class:web-footer-nav-main-item--compare-col={title === 'Compare'}
163+
class:web-footer-nav-main-item--with-bottom-logo={title === 'About'}
164+
>
125165
<h2
126166
class="web-footer-nav-main-title web-is-not-mobile text-caption font-medium uppercase"
127167
>
128168
{title}
129169
</h2>
130-
<ul class="web-footer-nav-secondary-list text-sub-body">
170+
<ul
171+
class="web-footer-nav-secondary-list text-sub-body"
172+
class:web-footer-nav-secondary-list--compare={title === 'Compare'}
173+
>
131174
{#each items as { href, label, target, rel }}
132175
<li>
133176
<a
@@ -143,6 +186,15 @@
143186
</li>
144187
{/each}
145188
</ul>
189+
{#if title === 'About'}
190+
<img
191+
class="web-logo web-is-not-mobile"
192+
src="/images/logos/appwrite.svg"
193+
alt="appwrite"
194+
height="24"
195+
width="130"
196+
/>
197+
{/if}
146198
</li>
147199
<li
148200
class="web-footer-nav-main-item web-is-only-mobile"
@@ -164,6 +216,7 @@
164216
{#if $isSelected(title)}
165217
<ul
166218
class="web-footer-nav-secondary-list text-sub-body"
219+
class:web-footer-nav-secondary-list--compare={title === 'Compare'}
167220
use:melt={$content({ value: title })}
168221
transition:slide={{ duration: 250 }}
169222
>

src/lib/components/LogoList.svelte

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -67,9 +67,9 @@
6767
height: 41
6868
},
6969
{
70-
src: '/images/logos/trusted-by/k-collect.avif',
70+
src: '/images/logos/trusted-by/k-collect.svg',
7171
alt: 'K-collect',
72-
width: 127,
72+
width: 110,
7373
height: 35
7474
},
7575
{

0 commit comments

Comments
 (0)