Skip to content

Commit df0705c

Browse files
committed
sync editable hashtag exportString to localStorage
1 parent 53bd71b commit df0705c

File tree

3 files changed

+95
-31
lines changed

3 files changed

+95
-31
lines changed

explorer/components/DrawingPage/AddTagModal.tsx

Lines changed: 24 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,9 @@ export const AddTagModal: React.FC<{ drawing: Drawing; isOpen: boolean; closeMod
1010
closeModal,
1111
}) => {
1212
const [newTag, setNewTag] = React.useState('')
13-
const [tagDrawingSets, setTagDrawingSets] = React.useState<TagDrawingSets>(loadTagDrawingSets())
13+
const [tagDrawingSets, setTagDrawingSets] = React.useState<TagDrawingSets>({})
14+
15+
React.useEffect(() => setTagDrawingSets(loadTagDrawingSets()), [isOpen])
1416

1517
function onNewTagSubmit(e: React.FormEvent<HTMLFormElement>) {
1618
addTagToDrawing(newTag, drawing)
@@ -74,12 +76,29 @@ const Code = styled.code.attrs({ classNames: 'Explorer__AddTagModal__Code' })`
7476
`
7577

7678
const TagList = styled.ul.attrs({ classNames: 'Explorer__AddTagModal__TagList' })`
77-
margin: 0 -8px;
79+
margin: 0 -12px;
7880
`
7981

8082
const Tag = styled.li.attrs({ classNames: 'Explorer__AddTagModal__Tag' })`
81-
border-right: 1px solid #DDD;
8283
display: inline-block;
83-
margin: 6px 0;
84-
padding: 0 8px;
84+
85+
&::after {
86+
content: '·';
87+
display: inline-block;
88+
opacity: 0.3;
89+
}
90+
91+
label {
92+
cursor: pointer;
93+
display: inline-block;
94+
padding: 4px 6px 4px 2px;
95+
96+
&:hover {
97+
box-shadow: inset 0 0 8px rgba(15, 100, 242, 0.15);
98+
99+
input[type="checkbox"]{
100+
box-shadow: inset 0 0 4px rgba(15, 100, 242, 0.5);
101+
}
102+
}
103+
}
85104
`
Lines changed: 66 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,52 +1,93 @@
11
import React from 'react'
2-
import styled from 'styled-components'
2+
import styled, { css } from 'styled-components'
33
import Modal from 'react-modal'
4-
import { loadTagDrawingSets } from '../../lib/hashtags'
4+
import { loadTagDrawingSets, saveTagDrawingSetsString } from '../../lib/hashtags'
55

66
export const ExportTagsModal: React.FC<{ isOpen: boolean; closeModal: () => void }> = ({
77
isOpen,
88
closeModal,
99
}) => {
1010
const tagDrawingSets = loadTagDrawingSets()
11-
const exportString = JSON.stringify(tagDrawingSets, null, 2)
11+
const initialExportString = JSON.stringify(tagDrawingSets, null, 2)
12+
13+
// exportString state powers selectAll
14+
const [exportString, setExportString] = React.useState(initialExportString)
15+
const [showCopySuccess, setShowCopySuccess] = React.useState(false)
1216

1317
function selectAll() {
1418
navigator.clipboard.writeText(exportString)
19+
setShowCopySuccess(true)
20+
setTimeout(() => setShowCopySuccess(false), 2000)
21+
}
22+
23+
// Edits in textarea are written to localStorage
24+
function onChange(e: React.ChangeEvent<HTMLTextAreaElement>) {
25+
setExportString(e.currentTarget.value)
26+
saveTagDrawingSetsString(e.currentTarget.value)
1527
}
1628

1729
return (
18-
<Modal
19-
isOpen={isOpen}
20-
onRequestClose={closeModal}
21-
>
22-
<div onKeyDown={e => e.stopPropagation()}>
23-
<CloseButton onClick={closeModal}>close</CloseButton>
30+
<Modal isOpen={isOpen} onRequestClose={closeModal}>
31+
<Wrap onKeyDown={e => e.stopPropagation()}>
2432
<Title>Export Hashtags</Title>
25-
<SelectAllButton onClick={selectAll}>select all</SelectAllButton>
26-
<Code>{exportString}</Code>
27-
</div>
33+
<ButtonBar>
34+
<SelectAllButton onClick={selectAll} showSuccess={showCopySuccess}>select all</SelectAllButton>
35+
<CloseButton onClick={closeModal}>close</CloseButton>
36+
</ButtonBar>
37+
<ExportTextarea value={exportString} onChange={onChange}>{exportString}</ExportTextarea>
38+
</Wrap>
2839
</Modal>
2940
)
3041
}
3142

32-
const CloseButton = styled.button.attrs({ classNames: 'Explorer__AddTagModal__CloseButton' })`
33-
font-size: 24px;
34-
position: absolute;
35-
right: 24px;
36-
top: 24px;
43+
const Wrap = styled.div.attrs({ classNames: 'Explorer__ExportTagsModal__Wrap' })`
44+
display: flex;
45+
flex-direction: column;
46+
height: 100%;
47+
`
48+
49+
const Title = styled.h1.attrs({ classNames: 'Explorer__ExportTagsModal__Title' })`
50+
text-align: center;
3751
`
3852

39-
const SelectAllButton = styled.button.attrs({ classNames: 'Explorer__AddTagModal__SelectAllButton' })`
53+
const ButtonBar = styled.div.attrs({ classNames: 'Explorer__ExportTagsModal__ButtonBar' })`
54+
display: flex;
55+
justify-content: space-between;
56+
`
57+
58+
const SelectAllButton = styled.button.attrs({ classNames: 'Explorer__ExportTagsModal__SelectAllButton' })<{
59+
showSuccess: boolean
60+
}>`
61+
align-self: flex-start;
4062
font-size: 24px;
63+
64+
${o => o.showSuccess && css`
65+
position: relative;
66+
67+
&::after {
68+
background: rgb(200, 255, 230);
69+
border: 1px solid rgba(8, 128, 44, 1);
70+
border-radius: 5px;
71+
box-shadow: inset 0 0 5px rgba(15, 225, 80, 1);
72+
color: rgba(0, 64, 0, 1);
73+
content: "copied to clipboard ✓";
74+
display: block;
75+
left: calc(100% + 16px);
76+
padding: 1px 0 2px;
77+
position: absolute;
78+
top: -2px;
79+
width: 250px;
80+
z-index: 1;
81+
}
82+
`}
4183
`
4284

43-
const Title = styled.h1.attrs({ classNames: 'Explorer__AddTagModal__Title' })`
44-
text-align: center;
85+
const CloseButton = styled.button.attrs({ classNames: 'Explorer__ExportTagsModal__CloseButton' })`
86+
font-size: 24px;
4587
`
4688

47-
const Code = styled.code.attrs({ classNames: 'Explorer__AddTagModal__Code' })`
48-
color: #999;
49-
display: block;
50-
margin: 24px 0 0;
51-
white-space: pre;
89+
const ExportTextarea = styled.textarea.attrs({ classNames: 'Explorer__ExportTagsModal__ExportTextarea' })`
90+
height: 100%;
91+
margin: 16px -20px -20px;
92+
padding: 16px;
5293
`

explorer/lib/hashtags.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,11 @@ export function loadTagDrawingSets(): TagDrawingSets {
66
}
77

88
export function saveTagDrawingSets(tagDrawingSets: TagDrawingSets) {
9-
localStorage.setItem('tagDrawingSets', JSON.stringify(tagDrawingSets))
9+
saveTagDrawingSetsString(JSON.stringify(tagDrawingSets || {}))
10+
}
11+
12+
export function saveTagDrawingSetsString(value: string) {
13+
localStorage.setItem('tagDrawingSets', value)
1014
}
1115

1216
export function drawingHasTag(drawing: Drawing, tag: string) {

0 commit comments

Comments
 (0)