Added First run dialog with Donation Component

This commit is contained in:
2026-05-14 02:51:05 -05:00
parent 71d631efbe
commit 67c82f61c7
2 changed files with 69 additions and 0 deletions

View File

@@ -47,6 +47,7 @@ Datacenter Modeler is a React-based web application for designing datacenter rac
- Export a PDF report with the diagram and rack inventory
- Dark/light theme selector
- Material UI-based interface
- Welcome dialog with an optional Cash App donation link
## Component Library
@@ -170,3 +171,4 @@ Each rack/cabinet contains its own metadata and an array of installed equipment.
- JSON export is the portable save format for moving diagrams between browsers or computers.
- PDF and image exports are generated from the rendered workspace.
- The current implementation is client-side only; no backend server or database is required.
- Donations are optional and use the Cash App link for `$MatthewPuckett`.

View File

@@ -42,6 +42,7 @@ import {
Image,
Inventory2,
LightMode,
OpenInNew,
PictureAsPdf,
Power,
Router,
@@ -50,6 +51,7 @@ import {
SettingsInputComponent,
Storage,
Terminal,
VolunteerActivism,
ViewColumn,
} from '@mui/icons-material';
import html2canvas from 'html2canvas';
@@ -147,6 +149,8 @@ export default function App() {
const [exportAnchor, setExportAnchor] = useState<HTMLElement | null>(null);
const [pendingContainer, setPendingContainer] = useState<'rack' | 'cabinet' | null>(null);
const [pendingSize, setPendingSize] = useState(42);
const [welcomeOpen, setWelcomeOpen] = useState(true);
const [donationAmount, setDonationAmount] = useState(5);
const [notice, setNotice] = useState('');
const workspaceRef = useRef<HTMLDivElement>(null);
const fileInputRef = useRef<HTMLInputElement>(null);
@@ -444,6 +448,11 @@ export default function App() {
}
};
const openDonation = () => {
const amount = clampNumber(donationAmount, 1, 500, 5);
window.open(`https://cash.app/$MatthewPuckett/${amount}`, '_blank', 'noopener,noreferrer');
};
const captureWorkspace = async () => {
if (!workspaceRef.current) {
throw new Error('Workspace is not ready.');
@@ -683,6 +692,64 @@ export default function App() {
</DialogActions>
</Dialog>
<Dialog open={welcomeOpen} onClose={() => setWelcomeOpen(false)} maxWidth="sm" fullWidth>
<DialogTitle sx={{ display: 'flex', alignItems: 'center', gap: 1 }}>
<Dns color="primary" />
Welcome to Datacenter Modeler
</DialogTitle>
<DialogContent>
<Stack spacing={2.5}>
<Typography color="text.secondary">
Build rack and cabinet diagrams by dragging components onto the workspace, snapping equipment into rack units,
editing metadata in the properties panel, and exporting your layout as JSON, images, or a PDF report.
</Typography>
<Divider />
<Box>
<Stack direction="row" alignItems="center" spacing={1} sx={{ mb: 1 }}>
<VolunteerActivism color="secondary" />
<Typography variant="subtitle1" sx={{ fontWeight: 800 }}>
Support the project
</Typography>
</Stack>
<Typography variant="body2" color="text.secondary" sx={{ mb: 2 }}>
This application was made by a homebrew developer. A donation is appreciated if this tool helps you,
but it is absolutely not required.
</Typography>
<Stack spacing={1.5}>
<Stack direction="row" spacing={1} flexWrap="wrap" useFlexGap>
{[5, 10, 20, 50].map((amount) => (
<Button
key={amount}
size="small"
variant={donationAmount === amount ? 'contained' : 'outlined'}
onClick={() => setDonationAmount(amount)}
>
${amount}
</Button>
))}
</Stack>
<TextField
label="Donation amount"
type="number"
value={donationAmount}
inputProps={{ min: 1, max: 500 }}
onChange={(event) => setDonationAmount(clampNumber(event.target.value, 1, 500, donationAmount))}
fullWidth
/>
<Button variant="contained" color="secondary" startIcon={<VolunteerActivism />} endIcon={<OpenInNew />} onClick={openDonation}>
Donate with Cash App
</Button>
</Stack>
</Box>
</Stack>
</DialogContent>
<DialogActions>
<Button onClick={() => setWelcomeOpen(false)}>Continue to app</Button>
</DialogActions>
</Dialog>
<Snackbar open={Boolean(notice)} autoHideDuration={3200} message={notice} onClose={() => setNotice('')} />
</Box>
</ThemeProvider>