Skip to content

Commit

Permalink
Overhaul for some mobile friendliness and just-keep-running
Browse files Browse the repository at this point in the history
  • Loading branch information
robsimmons committed Nov 15, 2023
1 parent 76b77d0 commit 18b701f
Show file tree
Hide file tree
Showing 9 changed files with 527 additions and 324 deletions.
6 changes: 3 additions & 3 deletions index.html
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,10 @@
<a href="https://github.com/robsimmons/dusa/blob/main/README.md">Dusa</a>
</div>
</div>
<div id="session" class="dk-session">
<div id="codemirror-root" class="dk-edit"></div>
<div id="session" class="mobile-view-editor">
<div id="codemirror-root"></div>
<div id="session-divider"></div>
<div id="react-root" class="dk-view"></div>
<div id="react-root"></div>
</div>
</div>
</main>
Expand Down
4 changes: 2 additions & 2 deletions src/Config.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ export default function Config(props: Props) {
<div className="bottom-config">
<Tooltip.Root>
<Tooltip.Trigger asChild className="dk-trigger-button">
<button className="dk-icon-button" onClick={() => props.share()}>
<button onClick={() => props.share()}>
<Share1Icon width={ICON_SIZE} height={ICON_SIZE} />
</button>
</Tooltip.Trigger>
Expand All @@ -38,7 +38,7 @@ export default function Config(props: Props) {
</Tooltip.Root>
<Tooltip.Root>
<Tooltip.Trigger asChild className="dk-trigger-button">
<button id="themeswitcher" className="dk-icon-button" onClick={toggle}>
<button id="themeswitcher" onClick={toggle}>
{mode === 'light' && <SunIcon width={ICON_SIZE} height={ICON_SIZE} />}
{mode === 'dark' && <MoonIcon width={ICON_SIZE} height={ICON_SIZE} />}{' '}
</button>
Expand Down
204 changes: 91 additions & 113 deletions src/Program.tsx
Original file line number Diff line number Diff line change
@@ -1,105 +1,106 @@
import { EnterIcon, PauseIcon, ResumeIcon } from '@radix-ui/react-icons';
import {
EnterIcon,
MagnifyingGlassIcon,
PauseIcon,
PlayIcon,
ReaderIcon,
} from '@radix-ui/react-icons';
import { Session } from './sessions';
import { ICON_SIZE } from './constants';
import View from './View';

interface Props {
session: Session;
load: () => void;
run: () => void;
pause: () => void;
setSolution: (index: number | null) => void;
}

export default function Program({ load, run, pause, session }: Props) {
if (session.status === 'unconnected') {
return (
<>
<div className="dk-view-header">
export default function Program({ load, run, pause, setSolution, session }: Props) {
const shouldReload =
session.status !== 'unconnected' && session.status !== 'load-error' && session.textModified;

return (
<>
<div id="explorer-header">
<button
id="explorer-load-program"
title="Load program"
className={shouldReload ? 'urgent' : ''}
onClick={(event) => {
event.preventDefault();
document.getElementById('session')!.className = 'mobile-view-explorer';
load();
}}
>
<EnterIcon width={ICON_SIZE} height={ICON_SIZE} />{' '}
{session.status === 'unconnected' || session.status === 'load-error'
? 'load program'
: shouldReload
? 'program changed! reload?'
: 'reload'}
</button>
<button
id="explorer-view-code"
title="View code"
onClick={(event) => {
event.preventDefault();
document.getElementById('session')!.className = 'mobile-view-editor';
}}
>
<ReaderIcon width={ICON_SIZE} height={ICON_SIZE} /> view program
</button>
{session.status !== 'unconnected' && session.status !== 'load-error' && (
<button
title="Load program"
id="explorer-explore-solutions"
title="Explore solutions (without reloading)"
onClick={(event) => {
event.preventDefault();
load();
document.getElementById('session')!.className = 'mobile-view-explorer';
}}
>
<EnterIcon width={ICON_SIZE} height={ICON_SIZE} />
<MagnifyingGlassIcon width={ICON_SIZE} height={ICON_SIZE} /> explore
</button>
<span className="dk-view-status">program not loaded</span>
</div>
</>
);
}

const loadButton = (
<button
title="Reset and reoad program"
onClick={(event) => {
event.preventDefault();
load();
}}
>
<EnterIcon width={ICON_SIZE} height={ICON_SIZE} />
</button>
);

const reloadBar = session.textModified ? (
<div className="dk-view-edit-warning">
The program has been modified!{' '}
<a
href=""
onClick={(event) => {
event.preventDefault();
load();
}}
>
Reload
</a>
</div>
) : (
<div></div>
);

const solutionDescription =
session.status === 'error'
? session.errorMessage
: session.status === 'done'
? session.facts.length === 0
? 'Done, no solutions.'
: session.facts.length === 1
? 'Done, unique solution found.'
: `Done, ${session.facts.length} solutions found.`
: session.facts.length === 0
? 'No solutions found (yet).'
: `${session.facts.length} solution${session.facts.length === 1 ? '' : 's'} found (so far).`;

const stats = (
<div className="dk-view-status">
{solutionDescription}
{session.stats && session.stats.cycles > 0 && (
<>
{' '}
{session.stats.cycles} step{session.stats.cycles !== 1 && 's'}
{session.stats && session.stats.deadEnds > 0 ? (
)}
{session.status === 'paused' && (
<button title="Search for more solutions" onClick={() => run()}>
<PlayIcon width={ICON_SIZE} height={ICON_SIZE} /> resume
</button>
)}
{session.status === 'running' && (
<button title="Pause searching for solutions" onClick={() => pause()}>
<PauseIcon width={ICON_SIZE} height={ICON_SIZE} /> pause
</button>
)}
<div id="explorer-status">
{session.status === 'unconnected' || session.status === 'load-error' ? null : (
<>
, {session.stats.deadEnds} backtrack{session.stats.deadEnds !== 1 && 's.'}{' '}
<span className="basic-status">
{session.status === 'done' && session.stats.error
? 'done with errors'
: session.status}
</span>
<span className="extended-status">
{session.stats.cycles > 0 && (
<>
, {session.stats.cycles} step{session.stats.cycles !== 1 && 's'}
</>
)}
{session.stats.deadEnds > 0 && (
<>
, {session.stats.deadEnds} backtrack{session.stats.deadEnds !== 1 && 's'}
</>
)}
</span>
</>
) : (
'.'
)}
</>
)}
</div>
);

if (session.status === 'error') {
return (
<>
<div className="dk-view-header">
{loadButton}
{stats}
</div>
{reloadBar}
<div className="dk-view-errors">
</div>
{session.status === 'load-error' && (
<div id="explorer-view" className="errors">
<div className="dk-view-scroller">
{session.errorMessage}
<ul>
{' '}
{session.issues.map((issue, i) => (
Expand All @@ -111,38 +112,15 @@ export default function Program({ load, run, pause, session }: Props) {
</ul>
</div>
</div>
</>
);
}

return (
<>
<div className="dk-view-header">
{loadButton}
{session.status === 'paused' && (
<button title="Search for more solutions" onClick={() => run()}>
<ResumeIcon width={ICON_SIZE} height={ICON_SIZE} />
</button>
)}
{session.status === 'running' && (
<button title="Pause searching for solutions" onClick={() => pause()}>
<PauseIcon width={ICON_SIZE} height={ICON_SIZE} />
</button>
)}
{stats}
</div>
{reloadBar}
{session.facts.length > 0 && (
/* TODO: make dk-scroller end --dk-medium-padding above the bottom */
<div className="dk-view-solutions">
<div className="dk-view-scroller">
<div>Result #{session.facts.length}</div>
<ul>
{session.facts[session.facts.length - 1].sort().map((fact, i) => (
<li key={i}>{fact}</li>
))}
</ul>
</div>
)}
{session.status !== 'load-error' && session.status !== 'unconnected' && (
<div id="explorer-view">
<View
status={session.status}
stats={session.stats}
query={session.query}
setSolution={setSolution}
/>
</div>
)}
</>
Expand Down
20 changes: 11 additions & 9 deletions src/Tabs.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -46,15 +46,17 @@ export default function Tabs({
}
</div>
))}
<button
className="dk-new-tab"
onClick={(event) => {
event.preventDefault();
addSession();
}}
>
<PlusIcon width={ICON_SIZE} height={ICON_SIZE} />
</button>
<div className="dk-tab">
<button
className="dk-new-tab"
onClick={(event) => {
event.preventDefault();
addSession();
}}
>
<PlusIcon width={ICON_SIZE} height={ICON_SIZE} />
</button>
</div>
</>
);
}
94 changes: 94 additions & 0 deletions src/View.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
import {
ChevronLeftIcon,
ChevronRightIcon,
DoubleArrowLeftIcon,
DoubleArrowRightIcon,
} from '@radix-ui/react-icons';
import { WorkerQuery, WorkerStats } from './worker';
import { ICON_SIZE } from './constants';

interface Props {
status: 'done' | 'running' | 'paused';
stats: WorkerStats;
query: null | WorkerQuery;
setSolution: (index: number | null) => void;
}

export default function View(props: Props) {
const reportedSolutionNumber = (props.query?.solution ?? props.stats.solutions - 1) + 1;

return (
<>
<div id="explorer-view-header">
<div className="explorer-view-header">
<button
disabled={props.stats.solutions < 2 || reportedSolutionNumber === 1}
onClick={() => props.setSolution(0)}
>
<DoubleArrowLeftIcon width={ICON_SIZE} height={ICON_SIZE} />
</button>
<button
disabled={props.stats.solutions < 2 || reportedSolutionNumber === 1}
onClick={() => props.setSolution(reportedSolutionNumber - 2)}
>
<ChevronLeftIcon width={ICON_SIZE} height={ICON_SIZE} />
</button>
<div className="status">
{props.query === null && (
<>
{props.status === 'done' && 'no solutions'}
{props.status !== 'done' && 'no solutions yet'}
</>
)}
{props.query !== null && (
<>
{props.status === 'done' && (
<>
{props.stats.solutions === 1 && 'unique solution found'}
{props.stats.solutions > 1 &&
`solution ${reportedSolutionNumber} of ${props.stats.solutions}`}
</>
)}
{props.status !== 'done' && (
<>
{props.query.solution === null && `solution ${reportedSolutionNumber} of ?`}
{props.query.solution !== null &&
`solution ${reportedSolutionNumber} of ${props.stats.solutions}+`}
</>
)}
</>
)}
</div>
<button
disabled={
props.query?.solution == null || props.query.solution + 1 === props.stats.solutions
}
onClick={() => props.setSolution(reportedSolutionNumber)}
>
<ChevronRightIcon width={ICON_SIZE} height={ICON_SIZE} />
</button>
<button
disabled={
props.query?.solution == null ||
(props.status === 'done' && props.query.solution + 1 === props.stats.solutions)
}
onClick={() => props.setSolution(null)}
>
<DoubleArrowRightIcon width={ICON_SIZE} height={ICON_SIZE} />
</button>
</div>
</div>

<div id="explorer-view-data">
<div style={{ color: 'var(--oksolar-text-red)' }}>{props.stats.error}</div>
{props.query !== null && (
<ul>
{props.query.value.map((fact, i) => (
<li key={i}>{fact}</li>
))}
</ul>
)}
</div>
</>
);
}
Loading

0 comments on commit 18b701f

Please sign in to comment.