Skip to content

Commit

Permalink
License + lots of tweaks
Browse files Browse the repository at this point in the history
  • Loading branch information
fileformat committed Jan 11, 2025
1 parent d666932 commit 4d0ed55
Show file tree
Hide file tree
Showing 17 changed files with 840 additions and 108 deletions.
661 changes: 661 additions & 0 deletions LICENSE.txt

Large diffs are not rendered by default.

10 changes: 4 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,18 +34,16 @@ This is a graphical sitemap viewer for [Sitemap.Style](https://www.sitemap.style

## To Do

- [ ] debug modal
- [ ] "powered by" hyperlink floater at the bottom on the tree
- [ ] footer with source, contact, etc at the bottom of the home page
- [ ] 404 page formatting
- [ ] loading spinner
- [ ] custom xml namespace: open/closed, allopen, style (and title, etc?)
- [ ] exit url to default to root of sitemap.xml URL
- [ ] `title` to allow markdown
- [ ] `title` to have variables for `host`, `barehost`
- [ ] name: punctuation to space
- [ ] name option: title case
- [ ] flag for show debug icon in navbar: shows `messages[]`
- [ ] move ModeSwitch someplace unobtrusive
- [ ] custom text instead of "Home"
- [ ] sort option `homename` to be name, but "Home" at top
- [ ] sort option: directories first
- [ ] sort option `homefirst` to be name, but "Home" at top
- [ ] demo button that loads local test sitemap.xml
- [ ] translations (and language picker)
2 changes: 1 addition & 1 deletion src/app/api/sitemap.json/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ export async function GET(request: Request) {
const url = new URL(request.url);
const url_str = url.searchParams.get("url") || "";

const retVal = await loadSitemap(url_str);
const retVal = await loadSitemap(url_str, {});

return handleJsonp(request, retVal);
}
2 changes: 1 addition & 1 deletion src/app/error.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ export default function Error({

return (
<div>
<h2>Something went wrong!</h2>
<h2>Something went wrong! (error)</h2>
<button
onClick={
// Attempt to recover by trying to re-render the segment
Expand Down
2 changes: 1 addition & 1 deletion src/app/global-error.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ export default function GlobalError({
// global-error must include html and body tags
<html>
<body>
<h2>Something went wrong!</h2>
<h2>Something went wrong! (global-error)</h2>
<button onClick={() => reset()}>Try again</button>
</body>
</html>
Expand Down
11 changes: 6 additions & 5 deletions src/app/not-found.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
import Link from 'next/link'
import Stack from '@mui/material/Stack'
import NextLink from 'next/link'

export default function NotFound() {
return (
<div>
<h2>Not Found</h2>
<Stack justifyContent="center" alignItems="center" sx={{height: '100vh', width: '100vw'}}>
<h2>Page Not Found</h2>
<p>Could not find requested resource</p>
<Link href="/">Return Home</Link>
</div>
<NextLink href="/">Home</NextLink>
</Stack>
)
}
31 changes: 22 additions & 9 deletions src/app/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -38,31 +38,44 @@ export default function Home() {
sx={{ mt: 2 }}
defaultValue={constants.DEFAULT_SITEMAP_URL}
/>
<TextField
fullWidth
id="exit"
label="Exit destination URL (optional)"
name="exit"
sx={{ mt: 2 }}
defaultValue="/"
/>
<SortSelect />
<TextField
fullWidth
id="title"
label="Title (optional)"
label="Title bar text (optional)"
name="title"
sx={{ mt: 2 }}
defaultValue={constants.DEFAULT_TITLE}
/>
<TextField
fullWidth
id="exit"
label="Exit destination URL (optional)"
name="exit"
id="home"
label="Home text (optional)"
name="home"
sx={{ mt: 2 }}
defaultValue="/"
defaultValue={constants.DEFAULT_HOME}
/>
<SortSelect />
<FormControlLabel control={<Checkbox name="debug" value="1" defaultChecked />} label="Debugging" />
<FormControlLabel control={<Checkbox name="debug" value="1" />} label="Debugging" />
<Stack direction="row" spacing={2} justifyContent="flex-start" sx={{ mt: 2 }}>
<Button variant="contained" type="submit">
<Button color="success" variant="contained" type="submit">
View
</Button>
<Button variant="outlined" component={NextLink} href="https://www.sitemap.style/">
<Button color="success" variant="outlined" component={NextLink} href="https://www.sitemap.style/">
Cancel
</Button>
<Stack direction="row" flex="1" justifyContent="flex-end" spacing={2} sx={{backgroundColor: 'transparent'}}>
<Button component={NextLink} variant="contained" href="/view.html?url=https://www.regex.zone/sitemap.xml&title=Regex+Zone+Site+Map&sort=name">
Demo
</Button>
</Stack>
</Stack>
</form>
<ProTip />
Expand Down
59 changes: 45 additions & 14 deletions src/app/view.html/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import { constants } from '@/lib/constants';
import { getFirst } from '@/lib/getFirst';
import { loadSitemap } from '@/lib/loadSitemap';
import { SitemapEntry, TreeItem } from '@/lib/types';
import PoweredBy from '@/components/PoweredBy';

export default async function View({
searchParams,
Expand All @@ -18,36 +19,45 @@ export default async function View({
const urlParams = (await searchParams);
const debug = getFirst(urlParams['debug'], '0') === '1';
const title = getFirst(urlParams['title'], 'Site Map');
const home = getFirst(urlParams['home'], 'Home');
let url_str = getFirst(urlParams['url'], constants.RANDOM_VALID_URL);
if (!url_str || url_str === constants.DEFAULT_SITEMAP_URL) {
url_str = constants.RANDOM_VALID_URL;
}
const sort = getFirst(urlParams['sort'], 'original');

const sme = await loadSitemap(url_str);
const sme = await loadSitemap(url_str, { home });
if (sort == "url") {
sme.entries.sort((a, b) => { return a.url.localeCompare(b.url); });
}
const items = listToTree(sme.entries);
if (sort == "name") {
sortTree(items);
sortTreeName(items);
} else if (sort == "dirfirst") {
sortTreeDirFirst(items);
}
return (
<Container maxWidth="lg" disableGutters={true} sx={{ minHeight: '100vh' }}>
<NavBar debug={debug} title={title} exitUrl="/" />
<Box
sx={{
display: 'flex',
flexDirection: 'column',
}}
>
{sme.success ? <SitemapTreeView items={items} /> : <h1>Failed to load sitemap</h1>}
</Box>
<>
<Container maxWidth={false} disableGutters={true} sx={{ minHeight: '100vh' }}>
<NavBar debug={debug} messages={sme.messages} title={title} exitUrl="/" />
<Container maxWidth="lg" disableGutters={true} sx={{ minHeight: '100vh' }}>
<Box
sx={{
display: 'flex',
flexDirection: 'column',
}}
>
{sme.success ? <SitemapTreeView items={items} /> : <h1>Failed to load sitemap</h1>}
</Box>
</Container>
</Container>
<PoweredBy />
</>

);
}

function sortTree(items: TreeItem[]) {
function sortTreeName(items: TreeItem[]) {
if (items.length == 0) {
return;
}
Expand All @@ -56,10 +66,31 @@ function sortTree(items: TreeItem[]) {
}

for (const item of items) {
sortTree(item.children);
sortTreeName(item.children);
}
}

function sortTreeDirFirst(items: TreeItem[]) {
if (items.length == 0) {
return;
}
if (items.length > 1) {
items.sort((a, b) => {
if (a.children.length > 0 && b.children.length == 0) {
return -1;
} else if (a.children.length == 0 && b.children.length > 0) {
return 1;
}
return a.label.localeCompare(b.label)
});
}

for (const item of items) {
sortTreeDirFirst(item.children);
}
}


function listToTree(entries: SitemapEntry[]): TreeItem[] {

const root: TreeItem[] = [];
Expand Down
35 changes: 20 additions & 15 deletions src/components/Copyright.tsx
Original file line number Diff line number Diff line change
@@ -1,20 +1,25 @@
import * as React from 'react';
import Typography from '@mui/material/Typography';
import MuiLink from '@mui/material/Link';
import NextLink from 'next/link';

export default function Copyright() {
return (
<Typography
variant="body2"
align="center"
sx={{
color: 'text.secondary',
}}
>
Copyright © 2025{' '}
<MuiLink color="inherit" href="https://andrew.marcuse.info/">
Andrew Marcuse
</MuiLink>. All Rights Reserved.
</Typography>
);
return (
<Typography
variant="body2"
align="center"
sx={{
color: 'text.secondary',
}}
>
Copyright © 2025 Andrew Marcuse. All Rights Reserved.
{' | '}
<NextLink color="inherit" href="https://andrew.marcuse.info/">
Contact
</NextLink>
{' | '}
<NextLink color="inherit" href="https://github.com/fileformat/view.sitemap.style">
Source
</NextLink>
</Typography>
);
}
46 changes: 15 additions & 31 deletions src/components/DebugButton.tsx
Original file line number Diff line number Diff line change
@@ -1,53 +1,36 @@
'use client';
import * as React from 'react';
import Avatar from '@mui/material/Avatar';
import List from '@mui/material/List';
import ListItem from '@mui/material/ListItem';
import ListItemAvatar from '@mui/material/ListItemAvatar';
import ListItemButton from '@mui/material/ListItemButton';
import ListItemText from '@mui/material/ListItemText';
import DialogTitle from '@mui/material/DialogTitle';
import Dialog from '@mui/material/Dialog';
import PersonIcon from '@mui/icons-material/Person';
import { blue } from '@mui/material/colors';
import { MdBugReport } from 'react-icons/md';

const emails = ['username@gmail.com', 'user02@gmail.com'];
import DialogContent from '@mui/material/DialogContent';

export interface DebugDialogProps {
open: boolean;
messages?: string[];
messages: string[];
onClose: () => void;
}

function DebugDialog(props: DebugDialogProps) {
const { open, onClose } = props;
const { messages, open, onClose } = props;

return (
<Dialog open={open}>
<Dialog maxWidth="lg" open={open} onClose={onClose} scroll="paper">
<DialogTitle onClick={onClose}>
Set backup account
Log Messages ({messages.length} lines)
</DialogTitle>
<List sx={{ pt: 0 }}>
{emails.map((email) => (
<ListItem disablePadding key={email}>
<ListItemButton >
<ListItemAvatar>
<Avatar sx={{ bgcolor: blue[100], color: blue[600] }}>
<PersonIcon />
</Avatar>
</ListItemAvatar>
<ListItemText primary={email} />
</ListItemButton>
</ListItem>
))}
</List>
<DialogContent dividers>
<pre>{messages.join('\n')}</pre>
</DialogContent>
</Dialog>
);
}

export interface DebugButtonProps {
messages: string[];
}

export default function DebugButton() {
export default function DebugButton({ messages }: DebugButtonProps) {
const [open, setOpen] = React.useState(false);
/*
const handleClickOpen = () => {
Expand All @@ -61,7 +44,8 @@ export default function DebugButton() {
return (
<>
<MdBugReport onClick={() => setOpen(true)} size={32} />
<DebugDialog open={open} onClose={() => setOpen(false)} />
<DebugDialog messages={messages} open={open} onClose={() => setOpen(false)} />
</>
);
}
}

38 changes: 21 additions & 17 deletions src/components/NavBar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,34 +4,38 @@ import AppBar from '@mui/material/AppBar';
import Toolbar from '@mui/material/Toolbar';
import Typography from '@mui/material/Typography';
import { MdLogout, MdMap } from 'react-icons/md';
import { Stack } from '@mui/material';
import Stack from '@mui/material/Stack';
import Container from '@mui/material/Container';
import DebugButton from './DebugButton';
import ModeButton from './ModeButton';

type NavBarProps = {
debug: boolean,
exitUrl: string,
messages: string[],
title: string,
}

export default function NavBar({ debug, exitUrl, title }: NavBarProps) {
export default function NavBar({ debug, exitUrl, messages, title }: NavBarProps) {
return (
<AppBar position="static" id="back-to-top-anchor" >
<Toolbar sx={{ justifyContent: 'space-between' }}>
<Stack direction="row" spacing={2}>
<MdMap size={32} />
<Typography variant="h6" component="div">
{title}
</Typography>
</Stack>
<Stack direction="row" spacing={2}>
<ModeButton />
{ debug ? <DebugButton /> : null }
<Link href={exitUrl}>
<MdLogout size={32} color="white" />
</Link>
</Stack>
</Toolbar>
<Container maxWidth="lg" disableGutters={true}>
<Toolbar sx={{ justifyContent: 'space-between' }}>
<Stack direction="row" spacing={2}>
<MdMap size={36} />
<Typography variant="h6" component="div">
{title}
</Typography>
</Stack>
<Stack direction="row" spacing={2}>
<ModeButton />
{debug ? <DebugButton messages={messages} /> : null}
<Link href={exitUrl}>
<MdLogout size={32} color="white" />
</Link>
</Stack>
</Toolbar>
</Container>
</AppBar>
);
}
Loading

0 comments on commit 4d0ed55

Please sign in to comment.