Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Rename boards, page scrolling and dialog style fixes in light mode #18

Merged
merged 2 commits into from
Jul 2, 2023
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
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ Concept image-board software for ambitious creatives 🎨
## What

Tornado is self-hosted software for the web (currently in development) that provides digital media artists with the ability to create concept and reference boards.
You can simply drag in images, or paste images you have copied in your clipboard, and then arrange them as you see fit.
You can simply paste images you have copied in your clipboard, and then arrange them as you see fit.


## Features:
Expand All @@ -22,6 +22,7 @@ You can simply drag in images, or paste images you have copied in your clipboard
* Image resizing on the server
* Canvas zoom and translate
* Image paste from clipboard and translate
* Name and rename boards

![](./images/screenshot.png)
![](./images/screenshot2.png)
Expand Down
4 changes: 4 additions & 0 deletions tornado-frontend/src/System.ts
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,10 @@ export class System {
makeObservable(this);
}

updateTitle(title: string) {
document.title = `Tornado${title ? ` | ${title}` : ''}`;
}

toggleTheme() {
if (this.theme.light) {
this.theme = ThemeDark;
Expand Down
2 changes: 1 addition & 1 deletion tornado-frontend/src/hooks/useButton.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,6 @@ export const useButton = (props: UseButtonOptions, ref: React.RefObject<HTMLDivE
return () => {
ref.current?.removeEventListener('click', l);
};
}, []);
}, [props.action, props.disabled]);
return { loading };
};
3 changes: 1 addition & 2 deletions tornado-frontend/src/routes/content/ConceptBoardPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ import { useEffect } from 'react';
import styled from '@emotion/styled';
import { useAuthenticated } from '../../hooks/useAuthenticated';
import { ContentViewWidget } from './widgets/ContentViewWidget';
import { usePasteMedia } from '../../hooks/usePasteMedia';
import { useSystem } from '../../hooks/useSystem';
import { ConceptCanvasWidget } from './widgets/react-canvas/ConceptCanvasWidget';
import { useParams } from 'react-router-dom';
Expand All @@ -21,7 +20,7 @@ export const ConceptBoardPage: React.FC<ConceptBoardPageProps> = observer((props
return autorun(() => {
const concept = system.conceptStore.getConcept(parseInt(id));
if (concept) {
concept.loadData();
system.updateTitle(`Concept ${concept.board.name}`);
}
});
}, [id]);
Expand Down
25 changes: 24 additions & 1 deletion tornado-frontend/src/routes/manage/ConceptBoardsPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ export const ConceptBoardsPage: React.FC = observer((props) => {
const system = useSystem();
useEffect(() => {
system.conceptStore.loadConcepts();
system.updateTitle('Concepts');
}, []);
return (
<S.Container>
Expand Down Expand Up @@ -51,7 +52,21 @@ export const ConceptBoardsPage: React.FC = observer((props) => {
render: ({ rowHover, row }) => {
return (
<TableRowActionsWidget show={rowHover}>
<ButtonWidget
<S.RowButton
label="Rename"
type={ButtonType.NORMAL}
action={async () => {
const name = await system.dialogStore.showInputDialog({
title: 'Enter a new name',
desc: `You are about to rename concept board ${row.board.board.name}`
});
if (!name) {
return;
}
return row.board.setName(name);
}}
/>
<S.RowButton
label="Delete"
type={ButtonType.NORMAL}
action={async () => {
Expand Down Expand Up @@ -96,4 +111,12 @@ namespace S {
export const Buttons = styled.div`
margin-bottom: 5px;
`;

export const RowButton = styled(ButtonWidget)`
margin-right: 5px;

&:last-of-type {
margin-right: 0;
}
`;
}
11 changes: 6 additions & 5 deletions tornado-frontend/src/stores/ConceptsStore.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,11 @@ export class ConceptBoardModel extends BaseObserver<ConceptBoardModelListener> {
});
}

updateBoard(board: ConceptBoard) {
this.board = board;
async setName(name: string) {
this.board.name = name;
await this.options.client.updateConcept({
board: this.board
});
}

get id() {
Expand All @@ -45,8 +48,6 @@ export class ConceptBoardModel extends BaseObserver<ConceptBoardModelListener> {
async delete() {
return this.iterateListenersAsync((cb) => cb.deleted?.());
}

async loadData() {}
}

export class ConceptsStore {
Expand All @@ -69,7 +70,7 @@ export class ConceptsStore {
});
return board;
},
update: (c, board) => board.updateBoard(c)
update: (c, board) => (board.board = c)
});
}

Expand Down
40 changes: 39 additions & 1 deletion tornado-frontend/src/stores/DialogStore.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,23 @@ import * as React from 'react';
import { Layer, LayerStore } from './LayerStore';
import { DialogWidget } from '../widgets/dialog/DialogWidget';
import { ButtonType } from '../widgets/forms/ButtonWidget';
import { InputDialogWidget } from '../widgets/dialog/InputDialogWidget';
import { Simulate } from 'react-dom/test-utils';
import submit = Simulate.submit;

export interface DialogStoreOptions {
layerStore: LayerStore;
}

export interface CommonDialogOptions {
title: string;
desc: string;
}

export class DialogStore {
constructor(protected options: DialogStoreOptions) {}

async showConfirmDialog(options: { title: string; desc: string }): Promise<boolean> {
async showConfirmDialog(options: CommonDialogOptions): Promise<boolean> {
return await new Promise<boolean>((resolve) => {
let confirm = false;
const layer = new Layer(() => {
Expand Down Expand Up @@ -48,4 +56,34 @@ export class DialogStore {
this.options.layerStore.addLayer(layer);
});
}

async showInputDialog(options: CommonDialogOptions & { initial?: string }): Promise<string | null> {
return await new Promise<string>((resolve) => {
let value: string = null;
const layer = new Layer(() => {
return (
<InputDialogWidget
title={options.title}
desc={options.desc}
submit={(val) => {
value = val;
layer.dispose();
}}
cancel={() => {
layer.dispose();
}}
initial={options.initial || ''}
/>
);
});
const l1 = layer.registerListener({
disposed: () => {
l1();
resolve(value);
}
});

this.options.layerStore.addLayer(layer);
});
}
}
12 changes: 6 additions & 6 deletions tornado-frontend/src/theme/theme-light.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,11 @@ export const ThemeLight: TornadoTheme = {
centerPanel: '#d2d2d2'
},
dialog: {
background: '#131315',
border: '#000',
header: '#fff',
desc: '#5f5f60',
shadow: 'rgba(0,0,0,0.3)'
background: '#eaeaea',
border: '#b6b6b6',
header: '#000000',
desc: '#424242',
shadow: 'rgba(122,122,122,0.3)'
},
text: {
heading: '#000000',
Expand All @@ -34,7 +34,7 @@ export const ThemeLight: TornadoTheme = {
controls: {
error: '#ab3838',
field: {
background: '#c4c4c4',
background: '#e1e1e1',
color: '#000000',
placeholder: '#616162'
},
Expand Down
45 changes: 45 additions & 0 deletions tornado-frontend/src/widgets/dialog/InputDialogWidget.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import * as React from 'react';
import { useState } from 'react';
import { ButtonType } from '../forms/ButtonWidget';
import { DialogWidget, DialogWidgetProps } from './DialogWidget';
import { FieldWidget } from '../forms/FieldWidget';

export interface InputDialogWidgetProps extends Omit<DialogWidgetProps, 'btns'> {
initial?: string;
submit: (value: string) => any;
cancel: () => any;
}

export const InputDialogWidget: React.FC<InputDialogWidgetProps> = (props) => {
const [value, setValue] = useState(props.initial);

return (
<DialogWidget
{...props}
btns={[
{
label: 'Submit',
action: async () => {
props.submit(value);
},
type: ButtonType.PRIMARY
},
{
label: 'Cancel',
action: async () => {
props.cancel();
},
type: ButtonType.NORMAL
}
]}
>
<FieldWidget
value={value}
onChange={(v) => {
setValue(v);
}}
placeholder=""
/>
</DialogWidget>
);
};
2 changes: 1 addition & 1 deletion tornado-frontend/src/widgets/forms/FieldWidget.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ export const FieldWidget: React.FC<FieldWidgetProps> = (props) => {
ref={props.forwardRef}
placeholder={props.placeholder}
type={props.type}
value={props.value?.trim() || ''}
value={props.value || ''}
onChange={(event) => {
let value = event.target.value;
if (value.trim() === '') {
Expand Down
1 change: 1 addition & 0 deletions tornado-frontend/src/widgets/layout/RootWidget.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ namespace S {

export const Body = styled(BodyWidget)`
flex-grow: 1;
overflow-y: auto;
`;

export const Layers = styled(LayersWidget)`
Expand Down