Skip to content

Commit eaeefe9

Browse files
committed
mobile code editing
1 parent c109167 commit eaeefe9

File tree

7 files changed

+167
-101
lines changed

7 files changed

+167
-101
lines changed

components/buttons/fullscreenbutton.tsx

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,12 @@ export default function FullscreenButton() {
1212

1313
return (
1414
<Button
15-
onClick={() => {
16-
setRequestFullscreen(true);
15+
onClick={() => setRequestFullscreen(true)}
16+
sx={{
17+
color: theme.palette.dracula.cyan,
18+
minWidth: 0,
19+
padding: '2px'
1720
}}
18-
sx={{ color: theme.palette.dracula.cyan }}
1921
>
2022
<FullscreenIcon />
2123
</Button>

components/buttons/reloadbutton.tsx

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
'use client';
22
import PlayArrowRounded from '@mui/icons-material/PlayArrowRounded';
33
import PlayDisabledRounded from '@mui/icons-material/PlayDisabledRounded';
4+
import Box from '@mui/material/Box';
45
import Button from '@mui/material/Button';
56
import { useTheme } from '@mui/material/styles';
67
import { useAtomValue, useSetAtom } from 'jotai';
@@ -27,13 +28,13 @@ export default function ReloadButton() {
2728
setManualReload(true);
2829
}}
2930
title="Recompile <Alt + Enter>"
30-
sx={
31-
hotReload
32-
? { color: theme.status.disabled }
33-
: { color: theme.palette.primary.light }
34-
}
31+
sx={{
32+
color: theme.palette.primary[hotReload ? 'contrastText' : 'light']
33+
}}
3534
>
36-
<PlayIcon />
35+
<Box sx={{ transform: 'scale(1.1)' }}>
36+
<PlayIcon />
37+
</Box>
3738
</Button>
3839
);
3940
}
Lines changed: 20 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,24 +5,38 @@ import Button from '@mui/material/Button';
55
import { useTheme } from '@mui/material/styles';
66
import { useAtom, useAtomValue } from 'jotai';
77
import { halfResolutionAtom } from 'lib/atoms/atoms';
8+
import dynamic from 'next/dynamic';
89

910
const ScaleIcon = () => {
1011
const halfResolution = useAtomValue(halfResolutionAtom);
1112
return halfResolution ? <Sd /> : <Hd />;
1213
};
1314

14-
export default function ScaleButton() {
15+
const Resolution = dynamic(() => import('components/resolution'), {
16+
ssr: false
17+
});
18+
19+
export default function ResolutionButton() {
1520
const [halfResolution, setHalfResolution] = useAtom(halfResolutionAtom);
1621
const theme = useTheme();
22+
23+
// Define styles outside the return for better readability
24+
const buttonStyles = {
25+
padding: '2px',
26+
minWidth: 0,
27+
color: halfResolution ? theme.palette.primary.contrastText : theme.palette.primary.light,
28+
'&:hover': {
29+
backgroundColor: 'rgba(255, 255, 255, 0.08)'
30+
}
31+
};
32+
1733
return (
1834
<Button
1935
onClick={() => setHalfResolution(!halfResolution)}
20-
sx={
21-
halfResolution
22-
? { color: theme.palette.primary.contrastText }
23-
: { color: theme.palette.primary.light }
24-
}
36+
sx={buttonStyles}
37+
aria-label={halfResolution ? 'Full resolution' : 'Half resolution'}
2538
>
39+
<Resolution />
2640
<ScaleIcon />
2741
</Button>
2842
);

components/editor/editor.tsx

Lines changed: 92 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import Giscus from '@giscus/react';
66
import Box from '@mui/material/Box';
77
import Button from '@mui/material/Button';
88
import Grid from '@mui/material/Grid';
9+
import Stack from '@mui/material/Stack';
910
import { useTheme } from '@mui/material/styles';
1011
import useMediaQuery from '@mui/material/useMediaQuery';
1112
import { User } from '@supabase/supabase-js';
@@ -15,7 +16,7 @@ import PlayPauseButton from 'components/buttons/playpausebutton';
1516
import RecordButton from 'components/buttons/recordbutton';
1617
import ReloadButton from 'components/buttons/reloadbutton';
1718
import ResetButton from 'components/buttons/resetbutton';
18-
import ScaleButton from 'components/buttons/scalebutton';
19+
import ResolutionButton from 'components/buttons/resolutionbutton';
1920
import VimButton from 'components/buttons/vimbutton';
2021
import EntryPointDisplay from 'components/editor/entrypointdisplay';
2122
import { MetadataEditor } from 'components/editor/metadataeditor';
@@ -43,21 +44,23 @@ interface EditorProps {
4344

4445
function Comments() {
4546
return (
46-
<Giscus
47-
id="comments"
48-
repo="compute-toys/comments"
49-
repoId="R_kgDOKRTytw"
50-
category="Announcements"
51-
categoryId="DIC_kwDOKRTyt84CllQC"
52-
mapping="pathname"
53-
strict="0"
54-
reactionsEnabled="1"
55-
emitMetadata="1"
56-
inputPosition="top"
57-
theme="dark"
58-
lang="en"
59-
loading="lazy"
60-
/>
47+
<Box sx={{ marginTop: { xs: '2em', sm: 0 } }}>
48+
<Giscus
49+
id="comments"
50+
repo="compute-toys/comments"
51+
repoId="R_kgDOKRTytw"
52+
category="Announcements"
53+
categoryId="DIC_kwDOKRTyt84CllQC"
54+
mapping="pathname"
55+
strict="0"
56+
reactionsEnabled="1"
57+
emitMetadata="1"
58+
inputPosition="top"
59+
theme="dark"
60+
lang="en"
61+
loading="lazy"
62+
/>
63+
</Box>
6164
);
6265
}
6366

@@ -74,9 +77,6 @@ export default function Editor(props: EditorProps) {
7477
}, []);
7578

7679
const Timer = dynamic(() => import('components/timer'), { ssr: false });
77-
const Resolution = dynamic(() => import('components/resolution'), {
78-
ssr: false
79-
});
8080

8181
let metadataEditor: JSX.Element | null = null;
8282
if (supabase && !props.standalone) {
@@ -102,6 +102,40 @@ export default function Editor(props: EditorProps) {
102102
};
103103
}
104104

105+
const theme = useTheme();
106+
const isMobile = useMediaQuery(theme.breakpoints.down('md'));
107+
108+
const monacoOptions = (isMobile: boolean) => ({
109+
stopRenderingLineAfter: isMobile ? 500 : 1000,
110+
fontSize: isMobile ? 12 : 12,
111+
lineHeight: isMobile ? 16 : 18,
112+
fontFamily: "'Fira Code', monospace",
113+
'bracketPairColorization.enabled': true,
114+
mouseWheelZoom: true,
115+
minimap: { enabled: !isMobile },
116+
scrollBeyondLastLine: !isMobile,
117+
automaticLayout: true,
118+
lineNumbersMinChars: isMobile ? 3 : 4
119+
});
120+
121+
const monacoEditorWithButtons = (
122+
<ItemWithTransitionSignal transitionAtom={saveColorTransitionSignalAtom}>
123+
<div className="vim-status"></div>
124+
<Monaco editorOptions={monacoOptions(isMobile)} />
125+
<Box sx={{ paddingTop: '4px' }}>
126+
<Box sx={{ display: 'flex', justifyContent: 'space-between' }}>
127+
<Button style={{ pointerEvents: 'none' }} />
128+
<div>
129+
<ReloadButton />
130+
<HotReloadToggle />
131+
<Explainer />
132+
</div>
133+
<VimButton />
134+
</Box>
135+
</Box>
136+
</ItemWithTransitionSignal>
137+
);
138+
105139
const leftPanel = (
106140
<div ref={renderParentNodeRef}>
107141
<ItemWithTransitionSignal transitionAtom={saveColorTransitionSignalAtom}>
@@ -117,61 +151,63 @@ export default function Editor(props: EditorProps) {
117151
embed={props.embed}
118152
/>
119153
</Frame>
120-
<Grid container>
121-
<Grid item sx={{ textAlign: 'left' }} xs={2}>
122-
<Timer />
154+
<Grid
155+
container
156+
sx={{
157+
display: 'flex',
158+
alignItems: 'center', // Vertically centers
159+
justifyContent: 'center', // Horizontally centers
160+
height: '100%', // Ensures vertical alignment works
161+
padding: '5px 5px 4px 5px' // top right bottom left
162+
}}
163+
>
164+
<Grid item xs={2}>
165+
<Stack
166+
direction="column"
167+
justifyContent="flex-start"
168+
alignItems="flex-start"
169+
>
170+
<Timer />
171+
</Stack>
123172
</Grid>
124-
<Grid item xs={7}>
173+
<Grid item xs={8}>
125174
<PlayPauseButton />
126175
<ResetButton />
127176
<RecordButton />
128177
</Grid>
129-
<Grid item sx={{ textAlign: 'right' }} xs={3}>
130-
<Resolution />
131-
<ScaleButton />
132-
<FullscreenButton />
178+
<Grid item xs={2}>
179+
<Stack direction="column" justifyContent="flex-end" alignItems="flex-end">
180+
<ResolutionButton />
181+
<FullscreenButton />
182+
</Stack>
133183
</Grid>
134184
</Grid>
135185
<UniformSliders />
136186
</ItemWithTransitionSignal>
137187
{metadataEditor}
138-
{shaderID ? <Comments /> : null}
188+
189+
{/* Show code right after shader metadata on mobile */}
190+
{isMobile && monacoEditorWithButtons}
191+
192+
{/* Don't show comments on mobile */}
193+
{!isMobile && (shaderID ? <Comments /> : null)}
139194
</div>
140195
);
141196

142-
const theme = useTheme();
143-
144197
const rightPanel = (
145198
<div>
146-
<ItemWithTransitionSignal transitionAtom={saveColorTransitionSignalAtom}>
147-
<div className="vim-status"></div>
148-
<Monaco
149-
editorOptions={{
150-
stopRenderingLineAfter: 1000,
151-
fontFamily: "'Fira Code', monospace",
152-
'bracketPairColorization.enabled': true,
153-
mouseWheelZoom: true
154-
//fontLigatures: true,
155-
}}
156-
/>
157-
<Box sx={{ paddingTop: '4px' }}>
158-
<Box sx={{ display: 'flex', justifyContent: 'space-between' }}>
159-
<Button style={{ pointerEvents: 'none' }} />{' '}
160-
{/* invisible button, used only for centering */}
161-
<div>
162-
<ReloadButton />
163-
<HotReloadToggle />
164-
<Explainer />
165-
</div>
166-
<VimButton />
167-
</Box>
168-
</Box>
169-
</ItemWithTransitionSignal>
199+
{!isMobile && monacoEditorWithButtons}
170200
<Grid
171201
container
172202
spacing={2}
173203
sx={{
174-
flexWrap: useMediaQuery(theme.breakpoints.up('sm')) ? 'nowrap' : 'wrap'
204+
flexWrap: useMediaQuery(theme.breakpoints.up('sm')) ? 'nowrap' : 'wrap',
205+
'@media (max-width: 600px)': {
206+
'& > .MuiGrid-item': {
207+
minHeight: 'none',
208+
maxHeight: '350px' // Prevents stretch on mobiles
209+
}
210+
}
175211
}}
176212
>
177213
<Grid item>
@@ -184,6 +220,7 @@ export default function Editor(props: EditorProps) {
184220
<EntryPointDisplay />
185221
</Grid>
186222
</Grid>
223+
{isMobile && (shaderID ? <Comments /> : null)}
187224
</div>
188225
);
189226

components/editor/explainer.tsx

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -11,20 +11,18 @@ import DraggableWindow from '../global/draggable-window';
1111
import { HiLite } from '../global/hilite';
1212
import Logo from '../global/logo';
1313

14-
const EXPLAINER_INNER_HEIGHT = '570';
15-
1614
const ExplainerBody = () => {
1715
const theme = useTheme();
1816
const prelude = useAtomValue(wgputoyPreludeAtom);
1917

2018
return (
2119
<div
2220
style={{
21+
// Styles for inner text (Chrome/Webkit/Mobiles)
2322
textAlign: 'left',
24-
width: 'min-content',
25-
overflowY: 'auto',
23+
width: '100%',
24+
overflowY: 'unset',
2625
padding: '8px',
27-
height: `${EXPLAINER_INNER_HEIGHT}px`,
2826
color: theme.palette.primary.main
2927
}}
3028
>
@@ -256,7 +254,21 @@ export default function Explainer() {
256254
<DraggableWindow
257255
hidden={explainerHidden}
258256
setHidden={setExplainerHidden}
259-
sx={{ paddingTop: '8px' }}
257+
sx={{
258+
//styles for the draggable window (Chrome/Webkit/Mobiles)
259+
paddingTop: '8px',
260+
width: '70vw',
261+
maxWidth: '800px',
262+
height: '80vh',
263+
overflowX: 'auto',
264+
zIndex: '9999999999',
265+
//mobile specific
266+
'@media (max-width: 600px)': {
267+
width: '97vw',
268+
height: '60vh',
269+
maxHeight: '80%'
270+
}
271+
}}
260272
>
261273
<ExplainerBody />
262274
</DraggableWindow>

components/resolution.tsx

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
'use client';
22
import { useAtomValue } from 'jotai';
33
import { heightAtom, scaleAtom, widthAtom } from 'lib/atoms/atoms';
4-
import { Fragment } from 'react';
54
import { theme } from 'theme/theme';
65

76
export default function Resolution() {
@@ -11,11 +10,17 @@ export default function Resolution() {
1110

1211
if (width > 0 && height > 0) {
1312
return (
14-
<Fragment>
15-
<span style={{ color: theme.palette.dracula.foreground }}>
16-
{Math.floor(width * scale)}x{Math.floor(height * scale)}
17-
</span>
18-
</Fragment>
13+
<span
14+
style={{
15+
color: theme.palette.dracula.foreground,
16+
paddingTop: '1px',
17+
paddingRight: '2px',
18+
lineHeight: '10px',
19+
display: 'inline-block'
20+
}}
21+
>
22+
{Math.floor(width * scale)}x{Math.floor(height * scale)}
23+
</span>
1924
);
2025
}
2126
return null;

0 commit comments

Comments
 (0)