diff --git a/.dockerignore b/.dockerignore
index 6d1f51a..0cbb973 100644
--- a/.dockerignore
+++ b/.dockerignore
@@ -4,3 +4,4 @@ node_modules
dist
dist-ssr
compose.yml
+src/config.json
\ No newline at end of file
diff --git a/.gitignore b/.gitignore
index 767e2f7..2a199e2 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,4 +1,5 @@
node_modules
.DS_Store
dist
-dist-ssr
\ No newline at end of file
+dist-ssr
+src/config.json
\ No newline at end of file
diff --git a/compose.yml b/compose.yml
new file mode 100644
index 0000000..b286616
--- /dev/null
+++ b/compose.yml
@@ -0,0 +1,8 @@
+services:
+ homepage:
+ image: jordanroher/starbase-80
+ ports:
+ - 4173:4173
+ volumes:
+ - ./config.json:/app/src/config.json
+ - ./icons:/app/public/icons # or wherever, JSON icon paths are relative to /app/public
diff --git a/dockerfile b/dockerfile
index c674408..1a6cf46 100644
--- a/dockerfile
+++ b/dockerfile
@@ -1,4 +1,4 @@
-FROM node
+FROM node18:alpine
WORKDIR /app
@@ -7,7 +7,7 @@ RUN npm i
COPY . .
-RUN npm run build
+ENV NODE_ENV production
EXPOSE 4173
diff --git a/package.json b/package.json
index b06b6db..704873f 100644
--- a/package.json
+++ b/package.json
@@ -6,7 +6,7 @@
"scripts": {
"dev": "vite",
"build": "tsc && vite build",
- "start": "vite preview"
+ "start": "npm run build && vite preview"
},
"dependencies": {
"@types/react-dom": "^18.0.11",
diff --git a/public/favicon.ico b/public/favicon.ico
deleted file mode 100644
index 6ef539b..0000000
Binary files a/public/favicon.ico and /dev/null differ
diff --git a/public/icons/archivebox.jpg b/public/icons/archivebox.jpg
deleted file mode 100644
index 01cd12e..0000000
Binary files a/public/icons/archivebox.jpg and /dev/null differ
diff --git a/public/icons/authelia.png b/public/icons/authelia.png
deleted file mode 100644
index f3b58b7..0000000
Binary files a/public/icons/authelia.png and /dev/null differ
diff --git a/public/icons/calibre.png b/public/icons/calibre.png
deleted file mode 100644
index 05a95e0..0000000
Binary files a/public/icons/calibre.png and /dev/null differ
diff --git a/public/icons/ghost.jpg b/public/icons/ghost.jpg
deleted file mode 100644
index 7aa1ed5..0000000
Binary files a/public/icons/ghost.jpg and /dev/null differ
diff --git a/public/icons/gitea.svg b/public/icons/gitea.svg
deleted file mode 100644
index 5fe2981..0000000
--- a/public/icons/gitea.svg
+++ /dev/null
@@ -1,12 +0,0 @@
-
diff --git a/public/icons/home-assistant.svg b/public/icons/home-assistant.svg
deleted file mode 100644
index 7856cf1..0000000
--- a/public/icons/home-assistant.svg
+++ /dev/null
@@ -1,9 +0,0 @@
-
diff --git a/public/icons/jellyfin.svg b/public/icons/jellyfin.svg
deleted file mode 100644
index fcbc0ce..0000000
--- a/public/icons/jellyfin.svg
+++ /dev/null
@@ -1,24 +0,0 @@
-
diff --git a/public/icons/mastodon.jpg b/public/icons/mastodon.jpg
deleted file mode 100644
index 7e829e6..0000000
Binary files a/public/icons/mastodon.jpg and /dev/null differ
diff --git a/public/icons/mealie.jpg b/public/icons/mealie.jpg
deleted file mode 100644
index 3b6a63e..0000000
Binary files a/public/icons/mealie.jpg and /dev/null differ
diff --git a/public/icons/metube.jpg b/public/icons/metube.jpg
deleted file mode 100644
index 7decf6e..0000000
Binary files a/public/icons/metube.jpg and /dev/null differ
diff --git a/public/icons/miniflux.jpg b/public/icons/miniflux.jpg
deleted file mode 100644
index 4cb5277..0000000
Binary files a/public/icons/miniflux.jpg and /dev/null differ
diff --git a/public/icons/n8n.jpg b/public/icons/n8n.jpg
deleted file mode 100644
index 80ed356..0000000
Binary files a/public/icons/n8n.jpg and /dev/null differ
diff --git a/public/icons/portainer.png b/public/icons/portainer.png
deleted file mode 100644
index da7b6fd..0000000
Binary files a/public/icons/portainer.png and /dev/null differ
diff --git a/public/icons/router.png b/public/icons/router.png
deleted file mode 100644
index 7bb37ed..0000000
Binary files a/public/icons/router.png and /dev/null differ
diff --git a/public/icons/standardnotes.png b/public/icons/standardnotes.png
deleted file mode 100644
index 086da5a..0000000
Binary files a/public/icons/standardnotes.png and /dev/null differ
diff --git a/public/icons/synology.png b/public/icons/synology.png
deleted file mode 100644
index 7277471..0000000
Binary files a/public/icons/synology.png and /dev/null differ
diff --git a/public/icons/vaultwarden.svg b/public/icons/vaultwarden.svg
deleted file mode 100644
index b0b1347..0000000
--- a/public/icons/vaultwarden.svg
+++ /dev/null
@@ -1,25 +0,0 @@
-
diff --git a/public/icons/vscode.jpg b/public/icons/vscode.jpg
deleted file mode 100644
index 2a5edc9..0000000
Binary files a/public/icons/vscode.jpg and /dev/null differ
diff --git a/public/icons/wallabag.png b/public/icons/wallabag.png
deleted file mode 100644
index dbab6bc..0000000
Binary files a/public/icons/wallabag.png and /dev/null differ
diff --git a/public/icons/wikijs.svg b/public/icons/wikijs.svg
deleted file mode 100644
index 17557f3..0000000
--- a/public/icons/wikijs.svg
+++ /dev/null
@@ -1,291 +0,0 @@
-
diff --git a/public/icons/woodpecker.jpg b/public/icons/woodpecker.jpg
deleted file mode 100644
index 78753f0..0000000
Binary files a/public/icons/woodpecker.jpg and /dev/null differ
diff --git a/public/starbase-80.png b/public/starbase-80.png
deleted file mode 100644
index d053089..0000000
Binary files a/public/starbase-80.png and /dev/null differ
diff --git a/readme.md b/readme.md
new file mode 100644
index 0000000..e42dcbf
--- /dev/null
+++ b/readme.md
@@ -0,0 +1,75 @@
+# Starbase 80
+
+A nice looking homepage for Docker containers or any other services and links.
+
+No actual integration with Docker. Loads instantly.
+
+If you make a change to the config JSON, restart this container and refresh.
+
+Provide your own icons.
+
+# Docker compose
+
+```yaml
+services:
+ homepage:
+ image: jordanroher/starbase-80
+ ports:
+ - 4173:4173
+ volumes:
+ - ./config.json:/app/src/config.json
+ - ./icons:/app/public/icons # or wherever, JSON icon paths are relative to /app/public
+```
+
+# config.json format
+
+```json
+[
+ {
+ "category": "Services",
+ "services": [
+ {
+ "name": "Archivebox",
+ "uri": "https://archivebox.mywebsite.com",
+ "description": "Backup webpages",
+ "icon": "/icons/archivebox.jpg"
+ },
+ {
+ "name": "Authelia",
+ "uri": "https://auth.mywebsite.com",
+ "description": "Authentication",
+ "icon": "/icons/authelia.png"
+ },
+ {
+ "name": "Calibre",
+ "uri": "https://calibre.mywebsite.com",
+ "description": "eBook library",
+ "icon": "/icons/calibre.png"
+ }
+ ]
+ },
+ {
+ "category": "Devices",
+ "services": [
+ {
+ "name": "Router",
+ "uri": "http://192.168.1.1/",
+ "description": "Netgear Orbi",
+ "icon": "/icons/router.png"
+ },
+ {
+ "name": "Home Assistant",
+ "uri": "http://homeassistant.local:8123/",
+ "description": "Home automation",
+ "icon": "/icons/home-assistant.svg"
+ },
+ {
+ "name": "Synology",
+ "uri": "http://synology:5000",
+ "description": "Network storage",
+ "icon": "/icons/synology.png"
+ }
+ ]
+ }
+]
+```
diff --git a/src/components/icon.tsx b/src/components/icon.tsx
index d2f6d24..d63213e 100644
--- a/src/components/icon.tsx
+++ b/src/components/icon.tsx
@@ -1,6 +1,5 @@
import React from "react";
import { is } from "../shared/is";
-import { IIcon } from "../shared/types";
const iconColors = [
"blue",
@@ -25,7 +24,7 @@ const getIconColor = (index: number) => `bg-${iconColors[iconColors.length % ind
interface IProps {
index: number;
- icon?: IIcon;
+ icon?: string;
uri?: string;
}
@@ -45,12 +44,12 @@ export const Icon: React.FunctionComponent = ({ uri, icon, index }) => {
if (!is.null(uri)) {
return (
-
+
);
}
- return ;
+ return ;
};
interface IIconBlankProps {
@@ -68,18 +67,14 @@ const IconBlank: React.FunctionComponent = ({ index }) => {
};
interface IIconBaseProps {
- icon: IIcon;
- index: number;
+ icon: string;
}
-const IconBase: React.FunctionComponent = ({ icon, index }) => {
- const { href, alt, title } = icon;
-
+const IconBase: React.FunctionComponent = ({ icon }) => {
return (
);
diff --git a/src/config/services.json b/src/config/services.json
deleted file mode 100644
index 9356e4f..0000000
--- a/src/config/services.json
+++ /dev/null
@@ -1,180 +0,0 @@
-[
- {
- "category": "Services",
- "services": [
- {
- "name": "Archivebox",
- "uri": "https://archivebox.starbase80.dev",
- "description": "Backup webpages",
- "icon": {
- "href": "/icons/archivebox.jpg"
- }
- },
- {
- "name": "Authelia",
- "uri": "https://auth.starbase80.dev",
- "description": "Authentication",
- "icon": {
- "href": "/icons/authelia.png"
- }
- },
- {
- "name": "Calibre",
- "uri": "https://calibre.starbase80.dev",
- "description": "eBook library",
- "icon": {
- "href": "/icons/calibre.png"
- }
- },
- {
- "name": "Gitea",
- "uri": "https://git.starbase80.dev",
- "description": "Code hosting",
- "icon": {
- "href": "/icons/gitea.svg"
- }
- },
- {
- "name": "Jellyfin",
- "uri": "https://jellyfin.starbase80.dev",
- "description": "Media server",
- "icon": {
- "href": "/icons/jellyfin.svg"
- }
- },
- {
- "name": "Mastodon",
- "uri": "https://notclickable.social",
- "description": "NotClickable.social",
- "icon": {
- "href": "/icons/mastodon.jpg"
- }
- },
- {
- "name": "Mealie",
- "uri": "https://mealie.starbase80.dev",
- "description": "Recipe manager",
- "icon": {
- "href": "/icons/mealie.jpg"
- }
- },
- {
- "name": "N8N",
- "uri": "https://n8n.starbase80.dev",
- "description": "Workflow automation",
- "icon": {
- "href": "/icons/n8n.jpg"
- }
- },
- {
- "name": "MeTube",
- "uri": "https://metube.starbase80.dev",
- "description": "Archive YouTube",
- "icon": {
- "href": "/icons/metube.jpg"
- }
- },
- {
- "name": "Miniflux",
- "uri": "https://miniflux.starbase80.dev",
- "description": "RSS server",
- "icon": {
- "href": "/icons/miniflux.jpg"
- }
- },
- {
- "name": "Portainer",
- "uri": "https://portainer.starbase80.dev",
- "description": "Docker management",
- "icon": {
- "href": "/icons/portainer.png"
- }
- },
- {
- "name": "Roher Twins",
- "uri": "https://rohertwins.starbase80.dev",
- "description": "Weekly newsletter",
- "icon": {
- "href": "/icons/ghost.jpg"
- }
- },
- {
- "name": "Roher Wiki",
- "uri": "https://roherwiki.starbase80.dev",
- "description": "Family wiki",
- "icon": {
- "href": "/icons/wikijs.svg"
- }
- },
- {
- "name": "Standard Notes",
- "uri": "https://standardnotes.starbase80.dev",
- "description": "Knowledge base",
- "icon": {
- "href": "/icons/standardnotes.png"
- }
- },
- {
- "name": "Vaultwarden",
- "uri": "https://vaultwarden.starbase80.dev",
- "description": "Password manager",
- "icon": {
- "href": "/icons/vaultwarden.svg"
- }
- },
- {
- "name": "Visual Studio Code",
- "uri": "https://vscode.starbase80.dev",
- "description": "Code editor",
- "icon": {
- "href": "/icons/vscode.jpg"
- }
- },
- {
- "name": "Wallabag",
- "uri": "https://wallabag.starbase80.dev",
- "description": "Read later",
- "icon": {
- "href": "/icons/wallabag.png"
- }
- },
- {
- "name": "Woodpecker",
- "uri": "https://woodpecker.starbase80.dev",
- "description": "Continuous integration",
- "icon": {
- "href": "/icons/woodpecker.jpg"
- }
- }
- ]
- },
- {
- "category": "Devices",
- "services": [
- {
- "name": "Router",
- "uri": "http://192.168.1.1/",
- "description": "Netgear Orbi",
- "icon": {
- "href": "/icons/router.png"
- }
- },
- {
- "name": "Home Assistant",
- "uri": "http://homeassistant.local:8123/",
- "description": "Home automation",
- "icon": {
- "href": "/icons/home-assistant.svg"
- }
- },
- {
- "name": "Synology",
- "uri": "http://synology:5000",
- "description": "Network storage",
- "icon": {
- "href": "/icons/synology.png"
- }
- }
- ]
- }
-]
diff --git a/src/main.tsx b/src/main.tsx
index bc7da11..b1a3187 100644
--- a/src/main.tsx
+++ b/src/main.tsx
@@ -5,6 +5,6 @@ import "./tailwind.css";
ReactDOM.createRoot(document.getElementById("root") as HTMLElement).render(
-
+
);
diff --git a/src/pages/index.tsx b/src/pages/index.tsx
index 6a63271..91591a0 100644
--- a/src/pages/index.tsx
+++ b/src/pages/index.tsx
@@ -1,7 +1,7 @@
import React from "react";
import { Header } from "../components/header";
import { ServiceCatalogs } from "../components/service-catalogs";
-import userServices from "../config/services.json";
+import userServices from "../config.json";
import { IServiceCatalog } from "../shared/types";
interface IProps {
diff --git a/src/shared/types.ts b/src/shared/types.ts
index fc01a9a..5219bf0 100644
--- a/src/shared/types.ts
+++ b/src/shared/types.ts
@@ -8,11 +8,5 @@ export interface IService {
uri: string;
description?: string;
- icon?: IIcon;
-}
-
-export interface IIcon {
- href: string;
- title?: string;
- alt?: string;
+ icon?: string;
}
diff --git a/vite.config.ts b/vite.config.ts
index 3ce47f6..238a40d 100644
--- a/vite.config.ts
+++ b/vite.config.ts
@@ -8,7 +8,7 @@ export default defineConfig({
watch: {
usePolling: true,
},
- host: true, // needed for the Docker Container port mapping to work
+ host: true,
strictPort: true,
port: 4173,
},