Skip to content

Commit

Permalink
Full implementation of messages templates
Browse files Browse the repository at this point in the history
  • Loading branch information
ybizeul committed Sep 6, 2024
1 parent 1969dc4 commit a8a985a
Show file tree
Hide file tree
Showing 6 changed files with 99 additions and 75 deletions.
28 changes: 13 additions & 15 deletions html/src/Components/MarkdownEditor/FullHeightTextArea.tsx
Original file line number Diff line number Diff line change
@@ -1,26 +1,24 @@
import { Textarea, TextareaProps } from "@mantine/core";
import { ChangeEvent, useState } from "react";
import { Textarea } from "@mantine/core";

import classes from './FullHeightTextArea.module.css';
import { useUncontrolled } from "@mantine/hooks";

// interface FullHeightTextAreaProps extends TextareaProps {
// value: string | number | readonly string[];
// label: string;
// onChange: ChangeEventHandler<HTMLTextAreaElement>;
// }
export function FullHeightTextArea(props: TextareaProps) {
interface FullHeightTextAreaProps {
value?: string;
onChange?: (value: string) => void;
}
export function FullHeightTextArea(props: FullHeightTextAreaProps) {
const { value, onChange } = props;
const [_value, setValue] = useState<string | number | readonly string[] | undefined>(value);

function notifyChange(v: ChangeEvent<HTMLTextAreaElement>) {
setValue(v.target.value)
onChange && onChange(v)
}
const [_value, handleChange] = useUncontrolled({
value,
onChange,
});

return (
<Textarea {...props} resize="vertical" value={_value}
<Textarea w="100%" flex="1" label="Message" description="This markdown will be displayed to the user" resize="vertical" value={_value}
classNames={{root: classes.root, wrapper: classes.wrapper, input: classes.input}}
onChange={(v) => { notifyChange(v) }}
onChange={(e) => { handleChange(e.currentTarget.value) }}
/>
)
}
22 changes: 14 additions & 8 deletions html/src/Components/MarkdownEditor/MarkdownEditor.tsx
Original file line number Diff line number Diff line change
@@ -1,30 +1,36 @@
import { ActionIcon, Box, BoxComponentProps, InputWrapper, Paper, rem } from "@mantine/core";
import { useDisclosure } from "@mantine/hooks";
import { useDisclosure, useUncontrolled } from "@mantine/hooks";
import { IconEye } from "@tabler/icons-react";
import { useState } from "react";
import { Message } from "../Message";
import { FullHeightTextArea } from "./FullHeightTextArea";

interface MarkDownEditorProps {
onChange: (message: string) => void;
message: string;
}

export function MarkDownEditor(props: MarkDownEditorProps&BoxComponentProps&{children: string}) {
export function MarkDownEditor(props: MarkDownEditorProps&BoxComponentProps) {
// Initialize props
const { onChange, children } = props;
const { onChange, message } = props;

// Initialize state
const [markdown, setMarkdown] = useState<string>(children);
const [markdown, setMarkdown] = useUncontrolled({
value: message,
defaultValue: '',
finalValue: 'Final',
onChange,
});
//const [markdown, setMarkdown] = useState<string>(message);
const [preview, previewH] = useDisclosure(false);

// Functions
const notifyChange = (m: string) => {
setMarkdown(m)
onChange(m)
}

return(
<Box display="flex" flex="1" w={{base: '100%', xs: rem(500)}} pl={props.pl} style={props.style} pos={"relative"}>
<Box display="flex" flex="1" pl={props.pl} style={props.style} pos={"relative"}>
<ActionIcon size="xs" id="preview" variant={preview?"filled":"subtle"} m={rem(3)} radius="xl" onClick={previewH.toggle} style={{position:"absolute", top: 0, right: 0}}>
<IconEye style={{ width: rem(16), height: rem(16) }} stroke={1.5} />
</ActionIcon>
Expand All @@ -35,7 +41,7 @@ interface MarkDownEditorProps {
</Paper>
</InputWrapper>
:
<FullHeightTextArea w="100%" flex="1" label="Message" description="This markdown will be displayed to the user" value={markdown} onChange={(v) => { notifyChange(v.target.value); }}/>
<FullHeightTextArea value={markdown} onChange={(v) => { notifyChange(v); }}/>
}
</Box>
)
Expand Down
63 changes: 17 additions & 46 deletions html/src/Components/ShareEditor.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import { Message, Share } from "@/hupload";
import { ActionIcon, Box, BoxComponentProps, Button, Flex, Input, Menu, NumberInput, rem, SegmentedControl, Stack, TextInput, useMantineTheme } from "@mantine/core";
import { IconChevronLeft, IconChevronRight, IconListCheck } from "@tabler/icons-react";
import { Share } from "@/hupload";
import { ActionIcon, Box, BoxComponentProps, Button, Flex, Input, NumberInput, rem, SegmentedControl, Stack, TextInput, useMantineTheme } from "@mantine/core";
import { IconChevronLeft, IconChevronRight } from "@tabler/icons-react";
import { useDisclosure, useMediaQuery } from "@mantine/hooks";
import { useEffect, useState } from "react";
import { useState } from "react";
import classes from './ShareEditor.module.css';
import { MarkDownEditor } from "./MarkdownEditor";
import { H } from "@/APIClient";
import { TemplatesMenu } from "./TemplatesMenu";

interface ShareEditorProps {
onChange: (options: Share["options"]) => void;
Expand All @@ -21,30 +21,16 @@ export function ShareEditor(props: ShareEditorProps&BoxComponentProps) {

// Initialize state
const [_options, setOptions] = useState<Share["options"]>(options)
const [messages, setMessages] = useState<string[]>([])

// Initialize hooks
const [showMessage, showMessageH ] = useDisclosure(false);
const theme = useMantineTheme()
const isInBrowser = useMediaQuery('(min-width: +' + theme.breakpoints.xs + ')');

// effects
useEffect(() => {
H.get('/messages').then((res) => {
setMessages(res as string[])
})
},[])

const selectMessage = (index: number) => {
H.get('/messages/'+index).then((res) => {
const m = res as Message
notifyChange({..._options, message: m.message as string})
})
}
// Functions
const notifyChange = (o: Share["options"]) => {
setOptions(o)
onChange(o)
setOptions(o)
onChange(o)
}

return (
Expand Down Expand Up @@ -97,31 +83,16 @@ export function ShareEditor(props: ShareEditorProps&BoxComponentProps) {

{/* Right section */}
{(showMessage||!isInBrowser)&&
<>
<MarkDownEditor
pl={isInBrowser?"sm":"0"}
style={{borderLeft: isInBrowser?"1px solid lightGray":""}}
onChange={(v) => { notifyChange({..._options, message:v}); }}
>
{_options.message?_options.message:""}
</MarkDownEditor>
{messages.length>0&&
<Menu withArrow trapFocus={false}>
<Menu.Target>
<ActionIcon size="xs" id="template" variant={"subtle"} m={rem(3)} radius="xl" style={{position:"absolute", top: 12, right: 40}}>
<IconListCheck style={{ width: rem(16), height: rem(16) }} stroke={1.5} />
</ActionIcon>
</Menu.Target>
<Menu.Dropdown>
{messages.map((m, i) => (
<Menu.Item key={i+1} onClick={() => {selectMessage(i+1)}}>
{m}
</Menu.Item>
))}
</Menu.Dropdown>
</Menu>
}
</>
<Box display="flex" flex="1" w={{base: '100%', xs: rem(500)}} pos={"relative"}>
<MarkDownEditor
pl={isInBrowser?"sm":"0"}
style={{borderLeft: isInBrowser?"1px solid lightGray":""}}
onChange={(v) => { notifyChange({..._options, message:v}); }}
message={_options.message?_options.message:""}
/>
<TemplatesMenu onChange={(v) => { notifyChange({..._options, message: v}); }}/>
</Box>

}
</Flex>
<Flex >
Expand Down
49 changes: 49 additions & 0 deletions html/src/Components/TemplatesMenu.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import { H } from "@/APIClient";
import { Message } from "@/hupload";
import { ActionIcon, ActionIconProps, Menu, rem } from "@mantine/core";
import { IconListCheck } from "@tabler/icons-react";
import { useEffect, useState } from "react";

interface TemplatesMenuProps {
onChange: (message: string) => void;
}

export function TemplatesMenu(props:TemplatesMenuProps&ActionIconProps) {
// Initialize state
const [messages, setMessages] = useState<string[]>([])

// effects
useEffect(() => {
H.get('/messages').then((res) => {
setMessages(res as string[])
})
},[])

const selectMessage = (index: number) => {
H.get('/messages/'+index).then((res) => {
const m = res as Message
props.onChange(m.message)
})
}

if (messages.length === 0) {
return
}

return (
<Menu withArrow withinPortal={false}>
<Menu.Target>
<ActionIcon size="xs" id="template" variant={"subtle"} m={rem(3)} radius="xl" style={{position:"absolute", top:0, right: 25}}>
<IconListCheck style={{ width: rem(16), height: rem(16) }} stroke={1.5} />
</ActionIcon>
</Menu.Target>
<Menu.Dropdown>
{messages.map((m, i) => (
<Menu.Item key={i+1} onClick={() => {selectMessage(i+1)}}>
{m}
</Menu.Item>
))}
</Menu.Dropdown>
</Menu>
);
}
10 changes: 5 additions & 5 deletions html/src/hupload.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,12 +55,12 @@ export function humanFileSize(bytes: number, si=false, dp=1) {
return bytes.toFixed(dp) + ' ' + units[u];
}

export function prettyfiedCount(count: number|null, singular: string, plural: string, empty: string|null) {
export function prettyfiedCount(count: number|null, singular: string, plural: string, empty: string|null) {
if (count === 0 || count === null|| count === undefined) {
return empty
return empty
} else if (count === 1) {
return count.toFixed() + ' ' + singular
return count.toFixed() + ' ' + singular
} else {
return count.toFixed() + ' ' + plural
return count.toFixed() + ' ' + plural
}
}
}
2 changes: 1 addition & 1 deletion hupload/handlers.go
Original file line number Diff line number Diff line change
Expand Up @@ -405,7 +405,7 @@ func (h *Hupload) getMessage(w http.ResponseWriter, r *http.Request) {
return
}
t := h.Config.Values.MessageTemplates
if len(t) <= index && index > 0 {
if index <= len(t) && index > 0 {
writeSuccessJSON(w, t[index-1])
return
} else {
Expand Down

0 comments on commit a8a985a

Please sign in to comment.