Added First run dialog with Donation Component
This commit is contained in:
@@ -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
|
- Export a PDF report with the diagram and rack inventory
|
||||||
- Dark/light theme selector
|
- Dark/light theme selector
|
||||||
- Material UI-based interface
|
- Material UI-based interface
|
||||||
|
- Welcome dialog with an optional Cash App donation link
|
||||||
|
|
||||||
## Component Library
|
## 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.
|
- JSON export is the portable save format for moving diagrams between browsers or computers.
|
||||||
- PDF and image exports are generated from the rendered workspace.
|
- PDF and image exports are generated from the rendered workspace.
|
||||||
- The current implementation is client-side only; no backend server or database is required.
|
- 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`.
|
||||||
|
|||||||
67
src/App.tsx
67
src/App.tsx
@@ -42,6 +42,7 @@ import {
|
|||||||
Image,
|
Image,
|
||||||
Inventory2,
|
Inventory2,
|
||||||
LightMode,
|
LightMode,
|
||||||
|
OpenInNew,
|
||||||
PictureAsPdf,
|
PictureAsPdf,
|
||||||
Power,
|
Power,
|
||||||
Router,
|
Router,
|
||||||
@@ -50,6 +51,7 @@ import {
|
|||||||
SettingsInputComponent,
|
SettingsInputComponent,
|
||||||
Storage,
|
Storage,
|
||||||
Terminal,
|
Terminal,
|
||||||
|
VolunteerActivism,
|
||||||
ViewColumn,
|
ViewColumn,
|
||||||
} from '@mui/icons-material';
|
} from '@mui/icons-material';
|
||||||
import html2canvas from 'html2canvas';
|
import html2canvas from 'html2canvas';
|
||||||
@@ -147,6 +149,8 @@ export default function App() {
|
|||||||
const [exportAnchor, setExportAnchor] = useState<HTMLElement | null>(null);
|
const [exportAnchor, setExportAnchor] = useState<HTMLElement | null>(null);
|
||||||
const [pendingContainer, setPendingContainer] = useState<'rack' | 'cabinet' | null>(null);
|
const [pendingContainer, setPendingContainer] = useState<'rack' | 'cabinet' | null>(null);
|
||||||
const [pendingSize, setPendingSize] = useState(42);
|
const [pendingSize, setPendingSize] = useState(42);
|
||||||
|
const [welcomeOpen, setWelcomeOpen] = useState(true);
|
||||||
|
const [donationAmount, setDonationAmount] = useState(5);
|
||||||
const [notice, setNotice] = useState('');
|
const [notice, setNotice] = useState('');
|
||||||
const workspaceRef = useRef<HTMLDivElement>(null);
|
const workspaceRef = useRef<HTMLDivElement>(null);
|
||||||
const fileInputRef = useRef<HTMLInputElement>(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 () => {
|
const captureWorkspace = async () => {
|
||||||
if (!workspaceRef.current) {
|
if (!workspaceRef.current) {
|
||||||
throw new Error('Workspace is not ready.');
|
throw new Error('Workspace is not ready.');
|
||||||
@@ -683,6 +692,64 @@ export default function App() {
|
|||||||
</DialogActions>
|
</DialogActions>
|
||||||
</Dialog>
|
</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('')} />
|
<Snackbar open={Boolean(notice)} autoHideDuration={3200} message={notice} onClose={() => setNotice('')} />
|
||||||
</Box>
|
</Box>
|
||||||
</ThemeProvider>
|
</ThemeProvider>
|
||||||
|
|||||||
Reference in New Issue
Block a user