diff --git a/theme/src/components/App/App.tsx b/theme/src/components/App/App.tsx
index ced9c05a50..95cc708ed5 100644
--- a/theme/src/components/App/App.tsx
+++ b/theme/src/components/App/App.tsx
@@ -6,6 +6,7 @@ import { useEffect, useRef } from 'react';
import slug from 'slug';
import { AppBar } from '@/components/AppBar';
+import { Footer } from '@/components/Footer';
import { GlobalTableOfContents } from '@/components/GlobalTableOfContents';
import { Media } from '@/components/media';
import { QuickLinks } from '@/components/QuickLinks';
@@ -232,11 +233,15 @@ export function App() {
*/}
{isSearch &&
}
-
+
{appScripts
.filter(({ src }) => {
diff --git a/theme/src/components/Footer.tsx b/theme/src/components/Footer.tsx
new file mode 100644
index 0000000000..9910e2860a
--- /dev/null
+++ b/theme/src/components/Footer.tsx
@@ -0,0 +1,103 @@
+import clsx from 'clsx';
+import { ComponentType, ReactNode } from 'react';
+
+import {
+ GitHub,
+ IconColorProps,
+ ImageSC,
+ NapariHub,
+ Twitter,
+ Zulip,
+} from '@/components/icons';
+import { Link } from '@/components/Link';
+
+interface FooterItem {
+ title: ReactNode | string;
+ link: string;
+ alt: string;
+ icon: ComponentType;
+ size?: string;
+}
+
+const FOOTER_LINKS: FooterItem[] = [
+ {
+ title: (
+ <>
+ napari hub
+ >
+ ),
+ link: 'https://napari-hub.org',
+ alt: 'Visit napari hub',
+ icon: NapariHub,
+ },
+ {
+ title: 'GitHub',
+ link: 'https://github.com/napari/napari',
+ alt: 'Visit GitHub repository',
+ icon: GitHub,
+ },
+ {
+ title: 'Twitter',
+ link: 'https://twitter.com/napari_imaging',
+ alt: 'Visit Twitter page',
+ icon: Twitter,
+ },
+ {
+ title: 'image.sc',
+ link: 'https://forum.image.sc/tag/napari',
+ alt: 'Visit image.sc forum',
+ icon: ImageSC,
+ size: 'h-[1.25em] w-[1.25em]',
+ },
+ {
+ title: 'Zulip',
+ link: 'https://napari.zulipchat.com',
+ alt: 'Visit Zulip chatroom',
+ icon: Zulip,
+ },
+];
+
+const STANDARD_ICON_SIZE = 'h-[1em] w-[1em]';
+
+function FooterLinks() {
+ return (
+ <>
+ {FOOTER_LINKS.map((item) => (
+
+
+ {item.title}
+
+ ))}
+ >
+ );
+}
+
+export function Footer() {
+ return (
+
+
+
+ );
+}
diff --git a/theme/src/components/icons/GitHub.tsx b/theme/src/components/icons/GitHub.tsx
index 40dbd61ce7..531e923692 100644
--- a/theme/src/components/icons/GitHub.tsx
+++ b/theme/src/components/icons/GitHub.tsx
@@ -1,6 +1,6 @@
-import { IconProps } from './icons.type';
+import { IconColorProps } from './icons.type';
-export function GitHub({ className, alt }: IconProps) {
+export function GitHub({ className, alt, color = 'black' }: IconColorProps) {
return (
);
diff --git a/theme/src/components/icons/ImageSC.tsx b/theme/src/components/icons/ImageSC.tsx
new file mode 100644
index 0000000000..f61b924c0f
--- /dev/null
+++ b/theme/src/components/icons/ImageSC.tsx
@@ -0,0 +1,46 @@
+import { IconColorProps } from './icons.type';
+
+export function ImageSC({ className, alt, color = 'black' }: IconColorProps) {
+ return (
+
+ );
+}
diff --git a/theme/src/components/icons/NapariHub.tsx b/theme/src/components/icons/NapariHub.tsx
new file mode 100644
index 0000000000..f746d3d2b7
--- /dev/null
+++ b/theme/src/components/icons/NapariHub.tsx
@@ -0,0 +1,100 @@
+import { IconColorProps } from './icons.type';
+
+export function NapariHub({
+ className,
+ alt,
+ color = '#009BF2',
+}: IconColorProps) {
+ return (
+
+ );
+}
diff --git a/theme/src/components/icons/Twitter.tsx b/theme/src/components/icons/Twitter.tsx
index 9e26387311..b6b8614811 100644
--- a/theme/src/components/icons/Twitter.tsx
+++ b/theme/src/components/icons/Twitter.tsx
@@ -1,6 +1,6 @@
-import { IconProps } from './icons.type';
+import { IconColorProps } from './icons.type';
-export function Twitter({ className, alt }: IconProps) {
+export function Twitter({ className, alt, color = 'black' }: IconColorProps) {
return (
);
diff --git a/theme/src/components/icons/Zulip.tsx b/theme/src/components/icons/Zulip.tsx
new file mode 100644
index 0000000000..0d73a1c6ca
--- /dev/null
+++ b/theme/src/components/icons/Zulip.tsx
@@ -0,0 +1,27 @@
+import { IconColorProps } from './icons.type';
+
+export function Zulip({ className, alt, color = 'black' }: IconColorProps) {
+ return (
+
+ );
+}
diff --git a/theme/src/components/icons/index.ts b/theme/src/components/icons/index.ts
index 7dd430f4db..fc1dfcb25a 100644
--- a/theme/src/components/icons/index.ts
+++ b/theme/src/components/icons/index.ts
@@ -2,7 +2,10 @@ export * from './Close';
export * from './ExternalLink';
export * from './GitHub';
export * from './icons.type';
+export * from './ImageSC';
export * from './Menu';
+export * from './NapariHub';
export * from './NapariLogo';
export * from './Search';
export * from './Twitter';
+export * from './Zulip';