Skip to content
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 5 additions & 3 deletions components/buttons/fullscreenbutton.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,12 @@ export default function FullscreenButton() {

return (
<Button
onClick={() => {
setRequestFullscreen(true);
onClick={() => setRequestFullscreen(true)}
sx={{
color: theme.palette.dracula.cyan,
minWidth: 0,
padding: '2px'
}}
sx={{ color: theme.palette.dracula.cyan }}
>
<FullscreenIcon />
</Button>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import Hd from '@mui/icons-material/Hd';
import Sd from '@mui/icons-material/Sd';
import Button from '@mui/material/Button';
import { useTheme } from '@mui/material/styles';
import Resolution from 'components/resolution';
import { useAtom, useAtomValue } from 'jotai';
import { halfResolutionAtom } from 'lib/atoms/atoms';

Expand All @@ -11,18 +12,27 @@ const ScaleIcon = () => {
return halfResolution ? <Sd /> : <Hd />;
};

export default function ScaleButton() {
export default function ResolutionButton() {
const [halfResolution, setHalfResolution] = useAtom(halfResolutionAtom);
const theme = useTheme();

// Define styles outside the return for better readability
const buttonStyles = {
padding: '2px',
minWidth: 0,
color: halfResolution ? theme.palette.primary.contrastText : theme.palette.primary.light,
'&:hover': {
backgroundColor: 'rgba(255, 255, 255, 0.08)'
}
};

return (
<Button
onClick={() => setHalfResolution(!halfResolution)}
sx={
halfResolution
? { color: theme.palette.primary.contrastText }
: { color: theme.palette.primary.light }
}
sx={buttonStyles}
aria-label={halfResolution ? 'Full resolution' : 'Half resolution'}
>
<Resolution />
<ScaleIcon />
</Button>
);
Expand Down
151 changes: 96 additions & 55 deletions components/editor/editor.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import Giscus from '@giscus/react';
import Box from '@mui/material/Box';
import Button from '@mui/material/Button';
import Grid from '@mui/material/Grid';
import Stack from '@mui/material/Stack';
import { useTheme } from '@mui/material/styles';
import useMediaQuery from '@mui/material/useMediaQuery';
import { User } from '@supabase/supabase-js';
Expand All @@ -15,7 +16,7 @@ import PlayPauseButton from 'components/buttons/playpausebutton';
import RecordButton from 'components/buttons/recordbutton';
import ReloadButton from 'components/buttons/reloadbutton';
import ResetButton from 'components/buttons/resetbutton';
import ScaleButton from 'components/buttons/scalebutton';
import ResolutionButton from 'components/buttons/resolutionbutton';
import VimButton from 'components/buttons/vimbutton';
import EntryPointDisplay from 'components/editor/entrypointdisplay';
import { MetadataEditor } from 'components/editor/metadataeditor';
Expand All @@ -31,6 +32,7 @@ import { createClient } from 'lib/supabase/client';
import dynamic from 'next/dynamic';
import { useCallback } from 'react';
import { ItemWithTransitionSignal } from 'theme/itemwithtransition';
import { MonacoTheme } from 'theme/monacotheme';
import { Frame } from 'theme/theme';
import ConfigurationPicker from './configurationpicker';
import Explainer from './explainer';
Expand All @@ -43,21 +45,23 @@ interface EditorProps {

function Comments() {
return (
<Giscus
id="comments"
repo="compute-toys/comments"
repoId="R_kgDOKRTytw"
category="Announcements"
categoryId="DIC_kwDOKRTyt84CllQC"
mapping="pathname"
strict="0"
reactionsEnabled="1"
emitMetadata="1"
inputPosition="top"
theme="dark"
lang="en"
loading="lazy"
/>
<Box sx={{ marginTop: { xs: '2em', sm: 0 } }}>
<Giscus
id="comments"
repo="compute-toys/comments"
repoId="R_kgDOKRTytw"
category="Announcements"
categoryId="DIC_kwDOKRTyt84CllQC"
mapping="pathname"
strict="0"
reactionsEnabled="1"
emitMetadata="1"
inputPosition="top"
theme="dark"
lang="en"
loading="lazy"
/>
</Box>
);
}

Expand All @@ -74,9 +78,6 @@ export default function Editor(props: EditorProps) {
}, []);

const Timer = dynamic(() => import('components/timer'), { ssr: false });
const Resolution = dynamic(() => import('components/resolution'), {
ssr: false
});

let metadataEditor: JSX.Element | null = null;
if (supabase && !props.standalone) {
Expand All @@ -102,6 +103,43 @@ export default function Editor(props: EditorProps) {
};
}

const theme = useTheme();
const isMobile = useMediaQuery(theme.breakpoints.down('md'));

const monacoOptions = (isMobile: boolean) => ({
stopRenderingLineAfter: isMobile ? 500 : 1000,
fontSize: isMobile ? 12 : 12,
lineHeight: isMobile ? 16 : 18,
fontFamily: "'Fira Code', monospace",
'bracketPairColorization.enabled': true,
mouseWheelZoom: true,
minimap: { enabled: !isMobile },
scrollBeyondLastLine: !isMobile,
automaticLayout: true,
lineNumbersMinChars: isMobile ? 3 : 4,
useShadowDOM: false // https://github.com/microsoft/monaco-editor/issues/3602
});

const monacoEditorWithButtons = (
<ItemWithTransitionSignal transitionAtom={saveColorTransitionSignalAtom}>
<div className="vim-status"></div>
<MonacoTheme>
<Monaco editorOptions={monacoOptions(isMobile)} />
</MonacoTheme>
<Box sx={{ paddingTop: '4px' }}>
<Box sx={{ display: 'flex', justifyContent: 'space-between' }}>
<Button style={{ pointerEvents: 'none' }} />
<div>
<ReloadButton />
<HotReloadToggle />
<Explainer />
</div>
<VimButton />
</Box>
</Box>
</ItemWithTransitionSignal>
);

const leftPanel = (
<div ref={renderParentNodeRef}>
<ItemWithTransitionSignal transitionAtom={saveColorTransitionSignalAtom}>
Expand All @@ -117,61 +155,63 @@ export default function Editor(props: EditorProps) {
embed={props.embed}
/>
</Frame>
<Grid container>
<Grid item sx={{ textAlign: 'left' }} xs={2}>
<Timer />
<Grid
container
sx={{
display: 'flex',
alignItems: 'center', // Vertically centers
justifyContent: 'center', // Horizontally centers
height: '100%', // Ensures vertical alignment works
padding: '5px 5px 4px 5px' // top right bottom left
}}
>
<Grid item xs={2}>
<Stack
direction="column"
justifyContent="flex-start"
alignItems="flex-start"
>
<Timer />
</Stack>
</Grid>
<Grid item xs={7}>
<Grid item xs={8}>
<PlayPauseButton />
<ResetButton />
<RecordButton />
</Grid>
<Grid item sx={{ textAlign: 'right' }} xs={3}>
<Resolution />
<ScaleButton />
<FullscreenButton />
<Grid item xs={2}>
<Stack direction="column" justifyContent="flex-end" alignItems="flex-end">
<ResolutionButton />
<FullscreenButton />
</Stack>
</Grid>
</Grid>
<UniformSliders />
</ItemWithTransitionSignal>
{metadataEditor}
{shaderID ? <Comments /> : null}

{/* Show code right after shader metadata on mobile */}
{isMobile && monacoEditorWithButtons}

{/* Don't show comments on mobile */}
{!isMobile && (shaderID ? <Comments /> : null)}
</div>
);

const theme = useTheme();

const rightPanel = (
<div>
<ItemWithTransitionSignal transitionAtom={saveColorTransitionSignalAtom}>
<div className="vim-status"></div>
<Monaco
editorOptions={{
stopRenderingLineAfter: 1000,
fontFamily: "'Fira Code', monospace",
'bracketPairColorization.enabled': true,
mouseWheelZoom: true
//fontLigatures: true,
}}
/>
<Box sx={{ paddingTop: '4px' }}>
<Box sx={{ display: 'flex', justifyContent: 'space-between' }}>
<Button style={{ pointerEvents: 'none' }} />{' '}
{/* invisible button, used only for centering */}
<div>
<ReloadButton />
<HotReloadToggle />
<Explainer />
</div>
<VimButton />
</Box>
</Box>
</ItemWithTransitionSignal>
{!isMobile && monacoEditorWithButtons}
<Grid
container
spacing={2}
sx={{
flexWrap: useMediaQuery(theme.breakpoints.up('sm')) ? 'nowrap' : 'wrap'
flexWrap: useMediaQuery(theme.breakpoints.up('sm')) ? 'nowrap' : 'wrap',
'@media (max-width: 600px)': {
'& > .MuiGrid-item': {
minHeight: 'none',
maxHeight: '400px' // Prevents stretch on mobiles
}
}
}}
>
<Grid item>
Expand All @@ -184,6 +224,7 @@ export default function Editor(props: EditorProps) {
<EntryPointDisplay />
</Grid>
</Grid>
{isMobile && (shaderID ? <Comments /> : null)}
</div>
);

Expand Down
24 changes: 18 additions & 6 deletions components/editor/explainer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,20 +11,18 @@ import DraggableWindow from '../global/draggable-window';
import { HiLite } from '../global/hilite';
import Logo from '../global/logo';

const EXPLAINER_INNER_HEIGHT = '570';

const ExplainerBody = () => {
const theme = useTheme();
const prelude = useAtomValue(wgputoyPreludeAtom);

return (
<div
style={{
// Styles for inner text (Chrome/Webkit/Mobiles)
textAlign: 'left',
width: 'min-content',
overflowY: 'auto',
width: '100%',
overflowY: 'unset',
padding: '8px',
height: `${EXPLAINER_INNER_HEIGHT}px`,
color: theme.palette.primary.main
}}
>
Expand Down Expand Up @@ -256,7 +254,21 @@ export default function Explainer() {
<DraggableWindow
hidden={explainerHidden}
setHidden={setExplainerHidden}
sx={{ paddingTop: '8px' }}
sx={{
//styles for the draggable window (Chrome/Webkit/Mobiles)
paddingTop: '8px',
width: '70vw',
maxWidth: '800px',
height: '80vh',
overflowX: 'auto',
zIndex: '9999999999',
//mobile specific
'@media (max-width: 600px)': {
width: '97vw',
height: '60vh',
maxHeight: '80%'
}
}}
>
<ExplainerBody />
</DraggableWindow>
Expand Down
33 changes: 33 additions & 0 deletions components/editor/monaco.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -280,6 +280,39 @@ const Monaco = props => {
);
// https://github.com/microsoft/monaco-editor/issues/392
document.fonts.ready.then(() => monaco.editor.remeasureFonts());

// https://github.com/suren-atoyan/monaco-react/issues/733
const handleMouseEvent = (e: MonacoEditor.IEditorMouseEvent) => {
const type = e['changedTouches']
? MonacoEditor.MouseTargetType.UNKNOWN
: MonacoEditor.MouseTargetType.CONTENT_EMPTY;
if (e?.target?.type === type) {
setTimeout(() => {
const position = _editor.getPosition();
const line = position?.lineNumber || 1;
const column =
(_editor.getModel()?.getLineContent(line).length || 0) + 1;
_editor.setSelection(new monaco.Selection(line, column, line, column));
}, 12);
}
};
const handleTouchEvent = e => {
e.preventDefault();
const touch = e.changedTouches[0];
const mouseEvent = new MouseEvent('mouseup', {
bubbles: true,
cancelable: true,
clientX: touch.clientX,
clientY: touch.clientY,
buttons: 1
});
domNode!.dispatchEvent(mouseEvent);
};
const domNode = _editor.getDomNode();
_editor.onMouseDown(handleMouseEvent);
_editor.onMouseUp(handleMouseEvent);
domNode!.addEventListener('touchstart', handleTouchEvent, { passive: false });
domNode!.addEventListener('touchend', handleTouchEvent, { passive: false });
}}
options={props.editorOptions}
theme="global" // preference
Expand Down
Loading