Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
9 changes: 9 additions & 0 deletions src/components/Editor.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,12 @@ export default function Editor({
pref => pref >= 10 && pref <= 22
);

const [wordWrap, setWordWrap] = usePreference<boolean>(
'wordwrap',
true,
() => true
);

useEffect(() => {
if (contentType) {
setLanguage(contentType);
Expand All @@ -66,6 +72,8 @@ export default function Editor({
setReadOnly={setReadOnly}
theme={theme}
setTheme={setTheme}
wordWrap={wordWrap}
setWordWrap={setWordWrap}
zoom={zoom}
/>
<EditorTextArea
Expand All @@ -76,6 +84,7 @@ export default function Editor({
language={language}
fontSize={fontSize}
readOnly={readOnly}
wordWrap={wordWrap}
resetFunction={resetFunction}
/>
</ThemeProvider>
Expand Down
11 changes: 10 additions & 1 deletion src/components/EditorControls.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ export interface EditorControlsProps {
setReadOnly: (value: boolean) => void;
theme: keyof Themes;
setTheme: (value: keyof Themes) => void;
wordWrap: boolean;
setWordWrap: (value: boolean) => void;
zoom: (delta: number) => void;
}

Expand All @@ -31,6 +33,8 @@ export default function EditorControls({
setReadOnly,
theme,
setTheme,
wordWrap,
setWordWrap,
zoom,
}: EditorControlsProps) {
const [saving, setSaving] = useState<boolean>(false);
Expand Down Expand Up @@ -113,6 +117,9 @@ export default function EditorControls({
<Section>
<Button onClick={() => zoom(1)}>[+ </Button>
<Button onClick={() => zoom(-1)}> -]</Button>
<Button onClick={() => setWordWrap(!wordWrap)}>
[wrap:{wordWrap ? 'on' : 'off'}]
</Button>
<MenuButton
label="theme"
value={theme}
Expand Down Expand Up @@ -144,13 +151,15 @@ const Header = styled.header`
display: flex;
justify-content: space-between;
user-select: none;
overflow-x: auto;
white-space: nowrap;
`;

const Section = styled.div`
display: flex;
align-items: center;

@media (max-width: 470px) {
@media (max-width: 850px) {
.optional {
display: none;
}
Expand Down
4 changes: 3 additions & 1 deletion src/components/EditorTextArea.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ export interface EditorTextAreaProps {
language: string;
fontSize: number;
readOnly: boolean;
wordWrap: boolean;
resetFunction: MutableRefObject<ResetFunction | null>;
}

Expand All @@ -73,6 +74,7 @@ export default function EditorTextArea({
language,
fontSize,
readOnly,
wordWrap,
resetFunction,
}: EditorTextAreaProps) {
const [editor, setEditor] = useState<editor.IStandaloneCodeEditor>();
Expand Down Expand Up @@ -166,7 +168,7 @@ export default function EditorTextArea({
fontFamily: 'JetBrains Mono',
fontSize: fontSize,
fontLigatures: true,
wordWrap: 'on',
wordWrap: wordWrap ? 'on' : 'off',
renderLineHighlight: 'none',
renderValidationDecorations: 'off',
readOnly,
Expand Down
41 changes: 35 additions & 6 deletions src/components/MenuButton.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import React, { useEffect, useState } from 'react';
import React, { useEffect, useRef, useState } from 'react';
import { createPortal } from 'react-dom';
import styled from 'styled-components';
import Button from './Button';

Expand All @@ -16,6 +17,11 @@ export default function MenuButton<T extends string>({
setValue,
}: MenuButtonProps<T>) {
const [open, setOpen] = useState<boolean>(false);
const [menuPosition, setMenuPosition] = useState<{
top: number;
left: number;
}>({ top: 0, left: 0 });
const buttonRef = useRef<HTMLDivElement | null>(null);

// close the menu when a click is made elsewhere
useEffect(() => {
Expand All @@ -26,6 +32,16 @@ export default function MenuButton<T extends string>({

function toggleOpen(e: React.MouseEvent) {
e.stopPropagation();
if (!buttonRef.current) {
return;
}
if (!open) {
const rect = buttonRef.current.getBoundingClientRect();
setMenuPosition({
top: rect.bottom + window.scrollY,
left: rect.left + window.scrollX,
});
}
setOpen(!open);
}

Expand Down Expand Up @@ -63,22 +79,35 @@ export default function MenuButton<T extends string>({
}

return (
<Button onClick={toggleOpen}>
[<span>{label}: </span>
{value}]{open && <Menu>{items}</Menu>}
</Button>
<>
<Button onClick={toggleOpen} ref={buttonRef}>
[<span>{label}: </span>
{value}]
</Button>
{open &&
createPortal(
<Menu style={{ top: menuPosition.top, left: menuPosition.left }}>
{items}
</Menu>,
document.body
)}
</>
);
}

const Menu = styled.ul`
position: absolute;
top: 2em;
margin: 0;
padding: 0;
list-style: none;
background-color: ${props => props.theme.highlight};
max-height: calc(100vh - 2em);
overflow: auto;
z-index: 20;

> li {
cursor: pointer;
}

> li.title {
text-align: center;
Expand Down
2 changes: 1 addition & 1 deletion src/hooks/usePreference.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ export default function usePreference<T>(
const [value, setValue] = useState<T>(() => {
const prefRaw = localStorage.getItem(id);
const pref = prefRaw !== null ? (JSON.parse(prefRaw) as T) : undefined;
if (pref && valid(pref)) {
if (pref !== null && pref !== undefined && valid(pref)) {
return pref;
} else {
return defaultValue;
Expand Down
Loading