Skip to content
This repository has been archived by the owner on Jun 4, 2023. It is now read-only.

Commit

Permalink
feat: add editing bookmarks
Browse files Browse the repository at this point in the history
Closes #382
  • Loading branch information
sentialx committed Dec 21, 2019
1 parent 1afff66 commit fab8e0e
Show file tree
Hide file tree
Showing 8 changed files with 225 additions and 17 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@
"styled-components": "^5.0.0-rc.1",
"terser": "^4.4.3",
"ts-loader": "^6.2.1",
"typescript": "3.7.4",
"typescript": "^3.7.4",
"typescript-plugin-styled-components": "^1.4.3",
"webpack": "4.41.4",
"webpack-bundle-analyzer": "^3.6.0",
Expand Down
21 changes: 20 additions & 1 deletion src/renderer/components/Pages/index.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,29 @@
import styled from 'styled-components';
import styled, { css } from 'styled-components';

export const Container = styled.div`
display: flex;
overflow: auto;
height: 100vh;
overflow: hidden;
${({ darken }: { darken?: boolean }) => css`
&:after {
opacity: ${darken ? 0.54 : 0};
pointer-events: ${darken ? 'auto' : 'none'};
}
`}
&:after {
content: '';
position: fixed;
z-index: 99;
left: 0;
right: 0;
top: 0;
bottom: 0;
background-color: black;
transition: 0.2s opacity;
}
`;

export const Content = styled.div`
Expand Down
7 changes: 6 additions & 1 deletion src/renderer/components/Textfield/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -163,7 +163,12 @@ export class Textfield extends React.PureComponent<Props, State> {
value={value}
/>
{hasLabel && (
<Label activated={activated} focused={focused} color={primaryColor}>
<Label
dark={dark}
activated={activated}
focused={focused}
color={primaryColor}
>
{label}
</Label>
)}
Expand Down
11 changes: 8 additions & 3 deletions src/renderer/components/Textfield/style.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ interface InputProps {

export const Input = styled.input`
width: 100%;
height: 48px;
height: 55px;
font-size: 16px;
padding-left: 12px;
border: none;
Expand Down Expand Up @@ -69,6 +69,7 @@ interface LabelProps {
activated: boolean;
focused: boolean;
color: string;
dark: boolean;
}

export const Label = styled.div`
Expand All @@ -79,10 +80,14 @@ export const Label = styled.div`
-webkit-font-smoothing: antialiased;
${centerVertical()};
${({ activated, focused, color }: LabelProps) => css`
${({ activated, focused, color, dark }: LabelProps) => css`
font-size: ${activated ? 12 : 16}px;
margin-top: ${activated ? -12 : 0}px;
color: ${focused ? color : `rgba(0, 0, 0, ${transparency.text.medium})`};
color: ${focused
? color
: dark
? `rgba(255, 255, 255, ${transparency.text.medium})`
: `rgba(0, 0, 0, ${transparency.text.medium})`};
${activated ? robotoMedium() : robotoRegular()};
`}
`;
Expand Down
120 changes: 111 additions & 9 deletions src/renderer/views/bookmarks/components/App/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,13 @@ import { SelectionDialog } from '~/renderer/components/SelectionDialog';
import { Container, Content, LeftContent } from '~/renderer/components/Pages';
import { GlobalNavigationDrawer } from '~/renderer/components/GlobalNavigationDrawer';
import { IBookmark } from '~/interfaces';
import { PathView, PathItem } from './style';
import {
PathView,
PathItem,
Dialog,
DialogTitle,
DialogButtons,
} from './style';
import {
ContextMenu,
ContextMenuItem,
Expand All @@ -21,6 +27,8 @@ import { EmptySection } from '../BookmarksSection/style';
import Tree from '../Tree';
import { Bookmark } from '../Bookmark';
import { ipcRenderer } from 'electron';
import { Textfield } from '~/renderer/components/Textfield';
import { Button } from '~/renderer/components/Button';

const GlobalStyle = createGlobalStyle`${Style}`;

Expand Down Expand Up @@ -51,12 +59,15 @@ const onInput = (e: React.KeyboardEvent<HTMLInputElement>) => {
};

const onNewFolderClick = () => {
store.addItem({
title: 'New folder',
isFolder: true,
parent: store.currentFolder,
children: [],
});
store.showDialog('new-folder');
};

const onEditClick = () => {
store.showDialog('edit');
};

const onRenameClick = () => {
store.showDialog('rename-folder');
};

const onPathItemClick = (item: IBookmark) => () => {
Expand All @@ -80,6 +91,36 @@ const onContextMenuMouseDown = (e: React.MouseEvent) => {
e.stopPropagation();
};

const onContainerMouseDown = () => {
store.dialogVisible = false;
};

const onDialogMouseDown = (e: React.MouseEvent) => {
e.stopPropagation();
};

const onSaveClick = () => {
if (store.dialogContent === 'new-folder') {
store.addItem({
title: store.nameInputRef.current.value,
isFolder: true,
parent: store.currentFolder,
children: [],
});
} else if (store.dialogContent === 'edit') {
store.updateItem(store.currentBookmark._id, {
title: store.nameInputRef.current.value,
url: store.urlInputRef.current.value,
});
} else if (store.dialogContent === 'rename-folder') {
store.updateItem(store.currentBookmark._id, {
title: store.nameInputRef.current.value,
});
}

store.dialogVisible = false;
};

const BookmarksList = observer(() => {
const items = store.visibleItems;

Expand Down Expand Up @@ -112,9 +153,20 @@ const BookmarksList = observer(() => {

export default hot(
observer(() => {
let dialogTitle = 'New folder';

if (store.dialogContent === 'edit') {
dialogTitle = 'Edit bookmark';
} else if (store.dialogContent === 'rename-folder') {
dialogTitle = 'Rename folder';
}

return (
<ThemeProvider theme={{ ...store.theme }}>
<Container>
<Container
onMouseDown={onContainerMouseDown}
darken={store.dialogVisible}
>
<GlobalStyle />
<GlobalNavigationDrawer></GlobalNavigationDrawer>
<NavigationDrawer title="Bookmarks" search onSearchInput={onInput}>
Expand Down Expand Up @@ -144,17 +196,67 @@ export default hot(
}}
visible={store.menuVisible}
>
{store.currentBookmark && !store.currentBookmark.isFolder && (
<ContextMenuItem onClick={onEditClick} icon={icons.edit}>
Edit
</ContextMenuItem>
)}
{store.currentBookmark && store.currentBookmark.isFolder && (
<ContextMenuItem onClick={onRenameClick} icon={icons.edit}>
Rename
</ContextMenuItem>
)}
<ContextMenuItem
onClick={onRemoveClick(store.currentBookmark)}
icon={icons.trash}
>
Remove
Delete
</ContextMenuItem>
</ContextMenu>
<Content onScroll={onScroll}>
<BookmarksList />
</Content>
</Container>
<Dialog onMouseDown={onDialogMouseDown} visible={store.dialogVisible}>
<DialogTitle>{dialogTitle}</DialogTitle>
<Textfield
style={{ width: '100%' }}
dark={store.theme['dialog.lightForeground']}
ref={store.nameInputRef}
label="Name"
></Textfield>

<Textfield
style={{
width: '100%',
marginTop: 16,
display: store.dialogContent === 'edit' ? 'block' : 'none',
}}
dark={store.theme['dialog.lightForeground']}
ref={store.urlInputRef}
label="URL"
></Textfield>

<DialogButtons>
<Button
onClick={() => (store.dialogVisible = false)}
background={
store.theme['dialog.lightForeground']
? 'rgba(255, 255, 255, 0.08)'
: 'rgba(0, 0, 0, 0.08)'
}
foreground={
store.theme['dialog.lightForeground'] ? 'white' : 'black'
}
>
Cancel
</Button>
<Button onClick={onSaveClick} style={{ marginLeft: 8 }}>
Save
</Button>
</DialogButtons>
<div style={{ clear: 'both' }}></div>
</Dialog>
</ThemeProvider>
);
}),
Expand Down
35 changes: 34 additions & 1 deletion src/renderer/views/bookmarks/components/App/style.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import styled from 'styled-components';
import styled, { css } from 'styled-components';
import { shadows } from '~/renderer/mixins';
import { ITheme } from '~/interfaces';

export const PathView = styled.div`
margin-top: 48px;
Expand Down Expand Up @@ -27,3 +29,34 @@ export const PathItem = styled.div`
}
}
`;

export const Dialog = styled.div`
position: fixed;
width: 512px;
padding: 16px;
left: 50%;
top: 50%;
border-radius: 6px;
z-index: 999;
box-shadow: ${shadows(8)};
transition: 0.2s opacity;
transform: translate(-50%, -50%);
${({ visible, theme }: { visible: boolean; theme?: ITheme }) => css`
opacity: ${visible ? 1 : 0};
pointer-events: ${visible ? 'auto' : 'none'};
background-color: ${theme['dialog.backgroundColor']};
color: ${theme['dialog.lightForeground'] ? 'white' : 'black'};
`}
`;

export const DialogTitle = styled.div`
font-size: 16px;
margin-bottom: 16px;
`;

export const DialogButtons = styled.div`
float: right;
display: flex;
margin-top: 24px;
`;
44 changes: 44 additions & 0 deletions src/renderer/views/bookmarks/store/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ import { ISettings, IFavicon, ITheme, IBookmark } from '~/interfaces';
import { getTheme } from '~/utils/themes';
import { PreloadDatabase } from '~/preloads/models/database';
import { ipcRenderer } from 'electron';
import * as React from 'react';
import { Textfield } from '~/renderer/components/Textfield';

export class Store {
@observable
Expand Down Expand Up @@ -40,6 +42,43 @@ export class Store {
@observable
public currentFolder: string = null;

@observable
private _dialogVisible = false;

@computed
public get dialogVisible() {
return this._dialogVisible;
}

public set dialogVisible(value: boolean) {
if (!value) {
this.nameInputRef.current.inputRef.current.value = '';
}

this.menuVisible = false;

this._dialogVisible = value;
}

public showDialog(content: 'edit' | 'new-folder' | 'rename-folder') {
this.dialogContent = content;
this.dialogVisible = true;

if (content === 'edit' || content === 'rename-folder') {
this.nameInputRef.current.inputRef.current.value = this.currentBookmark.title;

if (content === 'edit') {
this.urlInputRef.current.inputRef.current.value = this.currentBookmark.url;
}
}

this.nameInputRef.current.inputRef.current.focus();
this.nameInputRef.current.inputRef.current.select();
}

@observable
public dialogContent: 'edit' | 'new-folder' | 'rename-folder' = 'new-folder';

@computed
public get visibleItems() {
return this.list
Expand All @@ -60,10 +99,15 @@ export class Store {
});
}

@observable
public currentBookmark: IBookmark;

public faviconsDb = new PreloadDatabase<IFavicon>('favicons');

public nameInputRef = React.createRef<Textfield>();

public urlInputRef = React.createRef<Textfield>();

public constructor() {
(window as any).updateSettings = (settings: ISettings) => {
this.settings = { ...this.settings, ...settings };
Expand Down
2 changes: 1 addition & 1 deletion yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -7312,7 +7312,7 @@ typescript-plugin-styled-components@^1.4.3:
resolved "https://registry.yarnpkg.com/typescript-plugin-styled-components/-/typescript-plugin-styled-components-1.4.3.tgz#7f87ce0194e7841aa121174089dddff9f40bb0fb"
integrity sha512-/n6+nwtYRJwj/uJdiMNrjsfy2V34uGDeBuY3WaL3a1lc+aaYyfxHLvRdV3W44O+ewijJrFcEHKYAJdYq4wxXlQ==

typescript@3.7.4:
typescript@^3.7.4:
version "3.7.4"
resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.7.4.tgz#1743a5ec5fef6a1fa9f3e4708e33c81c73876c19"
integrity sha512-A25xv5XCtarLwXpcDNZzCGvW2D1S3/bACratYBx2sax8PefsFhlYmkQicKHvpYflFS8if4zne5zT5kpJ7pzuvw==
Expand Down

0 comments on commit fab8e0e

Please sign in to comment.