mirror of
https://github.com/Lissy93/dashy.git
synced 2026-07-30 11:06:09 -04:00
Makes deployment guides grid
This commit is contained in:
@@ -2,6 +2,7 @@ const { themes } = require('prism-react-renderer');
|
||||
const darkCodeTheme = themes.dracula;
|
||||
const lightCodeTheme = themes.github;
|
||||
const remarkGithubAlerts = require('./plugins/remark-github-alerts');
|
||||
const injectDeploymentGrid = require('./plugins/inject-deployment-grid');
|
||||
|
||||
/* External URLs */
|
||||
const externalUrl = {
|
||||
@@ -69,10 +70,6 @@ module.exports = {
|
||||
},
|
||||
}),
|
||||
},
|
||||
{
|
||||
tagName: 'link',
|
||||
attributes: { rel: 'manifest', href: '/manifest.json' },
|
||||
},
|
||||
// RSS feed autodiscovery
|
||||
{
|
||||
tagName: 'link',
|
||||
@@ -83,14 +80,21 @@ module.exports = {
|
||||
href: '/rss.xml',
|
||||
},
|
||||
},
|
||||
{
|
||||
tagName: 'meta',
|
||||
attributes: { name: 'theme-color', content: '#54bff7' },
|
||||
},
|
||||
],
|
||||
plugins: [
|
||||
'docusaurus-plugin-sass',
|
||||
require.resolve('./plugins/github-data'),
|
||||
[
|
||||
'@docusaurus/plugin-pwa',
|
||||
{
|
||||
offlineModeActivationStrategies: ['appInstalled', 'standalone', 'queryString'],
|
||||
pwaHead: [
|
||||
{ tagName: 'link', rel: 'manifest', href: '/manifest.json' },
|
||||
{ tagName: 'meta', name: 'theme-color', content: '#54bff7' },
|
||||
{ tagName: 'link', rel: 'apple-touch-icon', href: '/img/dashy.png' },
|
||||
],
|
||||
},
|
||||
],
|
||||
],
|
||||
themes: [
|
||||
[
|
||||
@@ -104,6 +108,12 @@ module.exports = {
|
||||
'@docusaurus/theme-mermaid',
|
||||
],
|
||||
themeConfig: {
|
||||
docs: {
|
||||
sidebar: {
|
||||
hideable: true,
|
||||
autoCollapseCategories: true,
|
||||
},
|
||||
},
|
||||
metadata: [
|
||||
{ name: 'keywords', content: 'dashy, dashboard, homelab, self-hosted, docker, homepage' },
|
||||
{ property: 'og:title', content: 'Dashy — The Ultimate Homepage for your Homelab' },
|
||||
@@ -124,9 +134,11 @@ module.exports = {
|
||||
prism: {
|
||||
theme: lightCodeTheme,
|
||||
darkTheme: darkCodeTheme,
|
||||
additionalLanguages: ['bash', 'ini', 'toml', 'nix'],
|
||||
},
|
||||
// Top Navigation Bar
|
||||
navbar: {
|
||||
hideOnScroll: true,
|
||||
title: 'Dashy',
|
||||
logo: {
|
||||
alt: 'Dashy Logo',
|
||||
@@ -214,7 +226,8 @@ module.exports = {
|
||||
sidebarPath: require.resolve('./sidebars.js'),
|
||||
editUrl: externalUrl.editUrl,
|
||||
showLastUpdateTime: true,
|
||||
beforeDefaultRemarkPlugins: [remarkGithubAlerts],
|
||||
showLastUpdateAuthor: true,
|
||||
beforeDefaultRemarkPlugins: [remarkGithubAlerts, injectDeploymentGrid],
|
||||
},
|
||||
sitemap: {
|
||||
changefreq: 'weekly',
|
||||
|
||||
23208
package-lock.json
generated
Normal file
23208
package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
@@ -4,7 +4,7 @@
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"docusaurus": "docusaurus",
|
||||
"start": "docusaurus start",
|
||||
"start": "docusaurus start --no-open",
|
||||
"build": "docusaurus build",
|
||||
"swizzle": "docusaurus swizzle",
|
||||
"deploy": "docusaurus deploy",
|
||||
@@ -15,6 +15,7 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@docusaurus/core": "^3.10.1",
|
||||
"@docusaurus/plugin-pwa": "^3.10.1",
|
||||
"@docusaurus/preset-classic": "^3.10.1",
|
||||
"@docusaurus/theme-mermaid": "^3.10.1",
|
||||
"@easyops-cn/docusaurus-search-local": "^0.55.2",
|
||||
|
||||
20
plugins/inject-deployment-grid.js
Normal file
20
plugins/inject-deployment-grid.js
Normal file
@@ -0,0 +1,20 @@
|
||||
// Renders <DeploymentMethods /> in docs/deployment.md without editing the
|
||||
// markdown itself, which gets overwritten by the upstream docs sync
|
||||
function injectDeploymentGrid() {
|
||||
return (tree, file) => {
|
||||
if (!file.path || !/[\\/]docs[\\/]deployment\.md$/.test(file.path)) return;
|
||||
const headingIndex = tree.children.findIndex(
|
||||
(node) => node.type === 'heading' && node.depth === 2
|
||||
&& node.children.some((child) => child.value === 'Deployment Methods'),
|
||||
);
|
||||
if (headingIndex === -1) return;
|
||||
tree.children.splice(headingIndex + 1, 0, {
|
||||
type: 'mdxJsxFlowElement',
|
||||
name: 'DeploymentMethods',
|
||||
attributes: [],
|
||||
children: [],
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
module.exports = injectDeploymentGrid;
|
||||
113
src/components/DeploymentMethods.js
Normal file
113
src/components/DeploymentMethods.js
Normal file
@@ -0,0 +1,113 @@
|
||||
import React, { useState } from 'react';
|
||||
import Link from '@docusaurus/Link';
|
||||
import styles from '../styles/DeploymentMethods.module.scss';
|
||||
|
||||
const icon = (file) => `https://pixelflare.cc/alicia/icons/${file}/w128`;
|
||||
|
||||
const METHODS = [
|
||||
{ name: 'Docker', link: '/docs/deployment/docker', icon: icon('docker.png'), official: true, category: 'Docker' },
|
||||
{ name: 'Docker Compose', link: '/docs/deployment/docker#docker-compose', icon: icon('docker-compose.png'), official: true, category: 'Docker' },
|
||||
{ name: 'Podman', link: '/docs/deployment/docker#podman', icon: icon('podman.png'), category: 'Docker' },
|
||||
{ name: 'Build from Source', link: '/docs/deployment/bare-metal#build-from-source', icon: icon('build-from-source.png'), official: true, category: 'Bare Metal' },
|
||||
{ name: 'Pre-Built Release', link: '/docs/deployment/bare-metal#pre-built-release', icon: icon('download-release.png'), official: true, category: 'Bare Metal' },
|
||||
{ name: 'TrueNAS SCALE', link: '/docs/deployment/self-hosted-os#truenas-scale', icon: icon('truenas-scale.png'), externalLink: 'https://apps.truenas.com/catalog/dashy_community/', category: 'Operating Systems' },
|
||||
{ name: 'Proxmox VE', link: '/docs/deployment/self-hosted-os#proxmox-ve', icon: icon('proxmox.png'), externalLink: 'https://community-scripts.github.io/ProxmoxVE/scripts?id=dashy', category: 'Operating Systems' },
|
||||
{ name: 'Unraid', link: '/docs/deployment/self-hosted-os#unraid', icon: icon('unraid.png'), category: 'Operating Systems' },
|
||||
{ name: 'Synology NAS', link: '/docs/deployment/self-hosted-os#synology-nas', icon: icon('synology.png'), category: 'Operating Systems' },
|
||||
{ name: 'NixOS', link: '/docs/deployment/self-hosted-os#nixos', icon: icon('nixos.png'), category: 'Operating Systems' },
|
||||
{ name: 'Kubernetes', link: '/docs/deployment/self-hosted-os#kubernetes', icon: icon('kubernetes.png'), category: 'Operating Systems' },
|
||||
{ name: 'Portainer', link: '/docs/deployment/self-hosted-platforms#portainer', icon: icon('portainer.png'), official: true, category: 'Platforms' },
|
||||
{ name: 'Coolify', link: '/docs/deployment/self-hosted-platforms#coolify', icon: icon('coolify.png'), category: 'Platforms' },
|
||||
{ name: '1Panel', link: '/docs/deployment/self-hosted-platforms#1panel', icon: icon('1panel.png'), externalLink: 'https://1panel.pro/apps/dashy', category: 'Platforms' },
|
||||
{ name: 'Runtipi', link: '/docs/deployment/self-hosted-platforms#runtipi', icon: icon('runtipi.png'), category: 'Platforms' },
|
||||
{ name: 'Cosmos Cloud', link: '/docs/deployment/self-hosted-platforms#cosmos-cloud', icon: icon('cosmos-cloud.png'), category: 'Platforms' },
|
||||
{ name: 'CasaOS', link: '/docs/deployment/self-hosted-platforms#casaos', icon: icon('casaos.png'), category: 'Platforms' },
|
||||
{ name: 'Umbrel', link: '/docs/deployment/self-hosted-platforms#umbrel', icon: icon('umbrel.png'), category: 'Platforms' },
|
||||
{ name: 'EasyPanel', link: '/docs/deployment/self-hosted-platforms#easypanel', icon: icon('easy-panel.png'), externalLink: 'https://easypanel.io/docs/templates/dashy', category: 'Platforms' },
|
||||
{ name: 'Saltbox', link: '/docs/deployment/self-hosted-platforms#saltbox', icon: icon('saltbox.png'), externalLink: 'https://docs.saltbox.dev/sandbox/apps/dashy/', category: 'Platforms' },
|
||||
{ name: 'Netlify', link: '/docs/deployment/cloud#netlify', icon: icon('netlify.png'), externalLink: 'https://app.netlify.com/start/deploy?repository=https://github.com/lissy93/dashy', official: true, category: 'Static Hosting' },
|
||||
{ name: 'Vercel', link: '/docs/deployment/cloud#vercel', icon: icon('vercel.png'), externalLink: 'https://vercel.com/new/clone?repository-url=https://github.com/lissy93/dashy', category: 'Static Hosting' },
|
||||
{ name: 'EdgeOne Pages', link: '/docs/deployment/cloud#edgeone-pages', icon: icon('edgeone.png'), category: 'Static Hosting' },
|
||||
{ name: 'Cloudflare Pages', link: '/docs/deployment/cloud#cloudflare-pages', icon: icon('cloudflare-pages.png'), category: 'Static Hosting' },
|
||||
{ name: 'Firebase Hosting', link: '/docs/deployment/cloud#firebase-hosting', icon: icon('firebase.png'), category: 'Static Hosting' },
|
||||
{ name: 'Azure Static Web Apps', link: '/docs/deployment/cloud#azure-static-web-apps', icon: icon('azure.png'), category: 'Static Hosting' },
|
||||
{ name: 'Any CDN', link: '/docs/deployment/cloud#hosting-with-any-cdn', icon: icon('cdn.png'), category: 'Static Hosting' },
|
||||
{ name: 'Render', link: '/docs/deployment/cloud#render', icon: icon('render.jpg'), externalLink: 'https://render.com/deploy?repo=https://github.com/lissy93/dashy', category: 'Container Services' },
|
||||
{ name: 'Railway', link: '/docs/deployment/cloud#railway', icon: icon('railway.png'), externalLink: 'https://railway.com/deploy/dashy', category: 'Container Services' },
|
||||
{ name: 'Fly.io', link: '/docs/deployment/cloud#flyio', icon: icon('fly-io.png'), category: 'Container Services' },
|
||||
{ name: 'Koyeb', link: '/docs/deployment/cloud#koyeb', icon: icon('koyeb.png'), externalLink: 'https://app.koyeb.com/deploy?type=docker&image=docker.io/lissy93/dashy:latest&name=dashy&ports=8080%3Bhttp%3B%2F', category: 'Container Services' },
|
||||
{ name: 'Northflank', link: '/docs/deployment/cloud#northflank', icon: icon('northflank.png'), externalLink: 'https://northflank.com/stacks/deploy-dashy', category: 'Container Services' },
|
||||
{ name: 'DigitalOcean', link: '/docs/deployment/cloud#digitalocean-app-platform', icon: icon('digital-ocean.png'), category: 'Container Services' },
|
||||
{ name: 'Azure Container Apps', link: '/docs/deployment/cloud#azure-container-apps', icon: icon('azure.png'), category: 'Container Services' },
|
||||
{ name: 'Google Cloud Run', link: '/docs/deployment/cloud#google-cloud-run', icon: icon('google-cloud-run.png'), category: 'Container Services' },
|
||||
{ name: 'Elestio', link: '/docs/deployment/cloud#managed-hosting', icon: icon('elestio.png'), externalLink: 'https://elest.io/open-source/dashy', category: 'Managed Hosting' },
|
||||
{ name: 'PikaPods', link: '/docs/deployment/cloud#managed-hosting', icon: icon('pikapods.png'), category: 'Managed Hosting' },
|
||||
{ name: 'Hostinger', link: '/docs/deployment/cloud#managed-hosting', icon: icon('hostinger.png'), externalLink: 'https://www.hostinger.com/applications/dashy', category: 'Managed Hosting' },
|
||||
];
|
||||
|
||||
const CATEGORIES = [...new Set(METHODS.map((m) => m.category))];
|
||||
|
||||
function MethodIcon({ src, name }) {
|
||||
const [failed, setFailed] = useState(false);
|
||||
if (!src || failed) {
|
||||
return <span className={styles.fallbackIcon} aria-hidden="true">{name.charAt(0)}</span>;
|
||||
}
|
||||
return (
|
||||
<img
|
||||
src={src}
|
||||
alt=""
|
||||
width="56"
|
||||
height="56"
|
||||
loading="lazy"
|
||||
decoding="async"
|
||||
onError={() => setFailed(true)}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
function MethodCard({ method }) {
|
||||
const external = Boolean(method.externalLink);
|
||||
const title = external
|
||||
? `Deploy Dashy with ${method.name} (opens in a new tab)`
|
||||
: `Dashy ${method.name} deployment guide`;
|
||||
return (
|
||||
<Link
|
||||
to={method.externalLink || method.link}
|
||||
className={styles.card}
|
||||
title={title}
|
||||
{...(external && { target: '_blank', rel: 'noopener noreferrer' })}
|
||||
>
|
||||
<MethodIcon src={method.icon} name={method.name} />
|
||||
<span className={styles.name}>{method.name}</span>
|
||||
{method.official && <span className={styles.official} title="Officially supported">official</span>}
|
||||
{external && <span className={styles.external} aria-hidden="true">↗</span>}
|
||||
</Link>
|
||||
);
|
||||
}
|
||||
|
||||
export default function DeploymentMethods() {
|
||||
const [filter, setFilter] = useState('All');
|
||||
const visible = METHODS.filter((m) => {
|
||||
if (filter === 'All') return true;
|
||||
if (filter === 'Official') return m.official;
|
||||
return m.category === filter;
|
||||
});
|
||||
return (
|
||||
<nav className={styles.wrapper} aria-label="Dashy deployment methods">
|
||||
<div className={styles.header}>
|
||||
<p className={styles.intro}>Click one of the {METHODS.length} guides below to get started</p>
|
||||
<select
|
||||
className={styles.filter}
|
||||
aria-label="Filter deployment methods"
|
||||
value={filter}
|
||||
onChange={(e) => setFilter(e.target.value)}
|
||||
>
|
||||
{['All', 'Official', ...CATEGORIES].map((c) => <option key={c}>{c}</option>)}
|
||||
</select>
|
||||
</div>
|
||||
<div className={styles.grid}>
|
||||
{visible.map((m) => <MethodCard key={m.name} method={m} />)}
|
||||
</div>
|
||||
</nav>
|
||||
);
|
||||
}
|
||||
14
src/components/GetStarted.js
Normal file
14
src/components/GetStarted.js
Normal file
@@ -0,0 +1,14 @@
|
||||
import React from 'react';
|
||||
import DeploymentMethods from './DeploymentMethods';
|
||||
import styles from '../styles/GetStarted.module.scss';
|
||||
|
||||
export default function GetStarted() {
|
||||
return (
|
||||
<section className={styles.getStartedSection} id="get-started" aria-label="Get started">
|
||||
<div className={styles.inner}>
|
||||
<h2 className={styles.heading}>Get Started Now</h2>
|
||||
<DeploymentMethods />
|
||||
</div>
|
||||
</section>
|
||||
);
|
||||
}
|
||||
@@ -5,6 +5,7 @@ import useDocusaurusContext from '@docusaurus/useDocusaurusContext';
|
||||
|
||||
import HomePageHeader from '../components/HomePageHeader';
|
||||
import HomePageFeatures from '../components/HomepageFeatures';
|
||||
import GetStarted from '../components/GetStarted';
|
||||
import Authors from '../components/Authors';
|
||||
import Stats from '../components/Stats';
|
||||
|
||||
@@ -23,6 +24,7 @@ export default function Home() {
|
||||
<Stats />
|
||||
<HomePageFeatures />
|
||||
<main id="top">
|
||||
<GetStarted />
|
||||
</main>
|
||||
<Authors />
|
||||
</Layout>
|
||||
|
||||
120
src/styles/DeploymentMethods.module.scss
Normal file
120
src/styles/DeploymentMethods.module.scss
Normal file
@@ -0,0 +1,120 @@
|
||||
.wrapper {
|
||||
margin-bottom: 2rem;
|
||||
}
|
||||
|
||||
.header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: 1rem;
|
||||
flex-wrap: wrap;
|
||||
margin-bottom: 0.75rem;
|
||||
}
|
||||
|
||||
.intro {
|
||||
margin: 0;
|
||||
opacity: 0.8;
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
.filter {
|
||||
padding: 0.3rem 0.5rem;
|
||||
border: 1px solid var(--ifm-toc-border-color);
|
||||
border-radius: 6px;
|
||||
background: var(--background);
|
||||
color: var(--text-color);
|
||||
font-family: inherit;
|
||||
font-size: 0.85rem;
|
||||
cursor: pointer;
|
||||
|
||||
&:hover, &:focus {
|
||||
border-color: var(--primary);
|
||||
}
|
||||
}
|
||||
|
||||
.grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fill, minmax(105px, 1fr));
|
||||
gap: 0.6rem;
|
||||
}
|
||||
|
||||
.card {
|
||||
position: relative;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
gap: 0.5rem;
|
||||
padding: 0.75rem 0.35rem 0.6rem;
|
||||
border: 1px solid var(--ifm-toc-border-color);
|
||||
border-radius: 8px;
|
||||
text-align: center;
|
||||
color: var(--text-color);
|
||||
background: transparent;
|
||||
transition: all 0.2s ease;
|
||||
|
||||
img {
|
||||
border-radius: 6px;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
border-color: var(--primary);
|
||||
background: var(--ifm-hover-overlay);
|
||||
box-shadow: var(--feature-img-shadow);
|
||||
text-decoration: none;
|
||||
color: var(--primary);
|
||||
transform: translateY(-3px);
|
||||
|
||||
.external {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.name {
|
||||
display: -webkit-box;
|
||||
-webkit-line-clamp: 2;
|
||||
-webkit-box-orient: vertical;
|
||||
overflow: hidden;
|
||||
font-size: 0.8rem;
|
||||
font-weight: bold;
|
||||
line-height: 1.2;
|
||||
overflow-wrap: anywhere;
|
||||
}
|
||||
|
||||
.official {
|
||||
position: absolute;
|
||||
top: -0.5rem;
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
padding: 0 0.4rem;
|
||||
border-radius: 1rem;
|
||||
background: var(--primary);
|
||||
color: var(--background);
|
||||
font-size: 0.6rem;
|
||||
font-weight: bold;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.05em;
|
||||
}
|
||||
|
||||
.external {
|
||||
position: absolute;
|
||||
top: 0.3rem;
|
||||
right: 0.45rem;
|
||||
opacity: 0;
|
||||
font-size: 0.85rem;
|
||||
transition: opacity 0.2s ease;
|
||||
}
|
||||
|
||||
.fallbackIcon {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 56px;
|
||||
height: 56px;
|
||||
border-radius: 6px;
|
||||
background: var(--primary);
|
||||
color: var(--background);
|
||||
font-size: 1.75rem;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
21
src/styles/GetStarted.module.scss
Normal file
21
src/styles/GetStarted.module.scss
Normal file
@@ -0,0 +1,21 @@
|
||||
.getStartedSection {
|
||||
background: var(--hero-background);
|
||||
padding: 3rem 1rem 0.5rem;
|
||||
border-bottom: 1px solid var(--ifm-toc-border-color);
|
||||
}
|
||||
|
||||
.inner {
|
||||
width: 80%;
|
||||
margin: 0.5rem auto;
|
||||
}
|
||||
|
||||
.heading {
|
||||
font-size: 2rem;
|
||||
color: var(--text-color);
|
||||
}
|
||||
|
||||
@media (max-width: 966px) {
|
||||
.inner {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
7
src/theme/MDXComponents.js
Normal file
7
src/theme/MDXComponents.js
Normal file
@@ -0,0 +1,7 @@
|
||||
import MDXComponents from '@theme-original/MDXComponents';
|
||||
import DeploymentMethods from '@site/src/components/DeploymentMethods';
|
||||
|
||||
export default {
|
||||
...MDXComponents,
|
||||
DeploymentMethods,
|
||||
};
|
||||
2
src/theme/PwaReloadPopup/index.js
Normal file
2
src/theme/PwaReloadPopup/index.js
Normal file
@@ -0,0 +1,2 @@
|
||||
// Keeps @theme/PwaReloadPopup resolvable in dev, where plugin-pwa is disabled
|
||||
export { default } from '@docusaurus/plugin-pwa/lib/theme/PwaReloadPopup';
|
||||
Reference in New Issue
Block a user