mirror of
https://github.com/BoostIo/Boostnote
synced 2025-12-14 18:26:26 +00:00
Compare commits
401 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
414e0dbc05 | ||
|
|
081a3da9e1 | ||
|
|
626175b2b8 | ||
|
|
54db0c718a | ||
|
|
ae9175d1b1 | ||
|
|
16e1f0f882 | ||
|
|
179b830d14 | ||
|
|
aeb27f7bff | ||
|
|
0b2b89da0f | ||
|
|
804991b300 | ||
|
|
529f271e07 | ||
|
|
402d577ce0 | ||
|
|
4bb28a358e | ||
|
|
200a9275d2 | ||
|
|
9cb086cbd9 | ||
|
|
3a836aaf34 | ||
|
|
e14a6f2374 | ||
|
|
28794bff79 | ||
|
|
ecc9443c9a | ||
|
|
a1c499c026 | ||
|
|
4e8321268c | ||
|
|
8510325732 | ||
|
|
49102be894 | ||
|
|
1a97488dd7 | ||
|
|
b90c7e5318 | ||
|
|
ece1e37c16 | ||
|
|
3a6e3f5cae | ||
|
|
8e502eec80 | ||
|
|
042ebe8316 | ||
|
|
eee47b1f76 | ||
|
|
7978704f1b | ||
|
|
9392ac438c | ||
|
|
cbcfb57e35 | ||
|
|
29fa512a90 | ||
|
|
059d1fb4f2 | ||
|
|
4d3a538213 | ||
|
|
108a0db799 | ||
|
|
04f632570d | ||
|
|
92b919da6c | ||
|
|
4f0f611e52 | ||
|
|
90f7cf0996 | ||
|
|
ce43e80bdf | ||
|
|
c397752b7a | ||
|
|
2470364571 | ||
|
|
cab122ba8b | ||
|
|
56b01b5a85 | ||
|
|
cbcc9fb411 | ||
|
|
5bbc60d48a | ||
|
|
8fb8aab7b8 | ||
|
|
5b76216a64 | ||
|
|
7f5e372bdc | ||
|
|
01913a9a40 | ||
|
|
62f9fcf171 | ||
|
|
34c667f6b2 | ||
|
|
7a6de387e3 | ||
|
|
b6efbcedef | ||
|
|
3c70b2e5a0 | ||
|
|
62e108d460 | ||
|
|
b7f426b03f | ||
|
|
5ca13b70aa | ||
|
|
4644d107c6 | ||
|
|
06013b2a6a | ||
|
|
7380fc8500 | ||
|
|
81b550e66c | ||
|
|
f5972c273b | ||
|
|
c259ec2bed | ||
|
|
86a04b0dcb | ||
|
|
8b7c0c957c | ||
|
|
0cfe971a48 | ||
|
|
8884db858c | ||
|
|
0fe9dd4fbb | ||
|
|
ae57e99173 | ||
|
|
c238e1b5cb | ||
|
|
55ef998c55 | ||
|
|
166815ccbf | ||
|
|
34a16298d4 | ||
|
|
1613e72d47 | ||
|
|
e933ad89dc | ||
|
|
148fb25a15 | ||
|
|
fe0544dbc9 | ||
|
|
0aaea28e74 | ||
|
|
f4764afbf4 | ||
|
|
2a2b662a6f | ||
|
|
deade1f9f8 | ||
|
|
2b73c17cca | ||
|
|
369f8b6093 | ||
|
|
5391ca161d | ||
|
|
5b224d3b54 | ||
|
|
dad6a93944 | ||
|
|
10ec5c1342 | ||
|
|
8edfc15f45 | ||
|
|
792e41f161 | ||
|
|
9fbdf895af | ||
|
|
dbc0fedf43 | ||
|
|
cb298b8cad | ||
|
|
2459a80e15 | ||
|
|
0a973c4db3 | ||
|
|
a84fddd5fa | ||
|
|
1cd26d2e71 | ||
|
|
f88ac891ff | ||
|
|
17aa9ae85f | ||
|
|
bb46a9ba4c | ||
|
|
4a6c16df8d | ||
|
|
95787fafc6 | ||
|
|
c51d79e4d7 | ||
|
|
d5232a1b0e | ||
|
|
e093c7f982 | ||
|
|
3f53bddf7e | ||
|
|
e03d8175e3 | ||
|
|
7ab2e9f6ca | ||
|
|
6316ddc6a6 | ||
|
|
11c46ede5d | ||
|
|
2ec5238d97 | ||
|
|
b7f359f6cf | ||
|
|
8ef485221c | ||
|
|
afddb6fc33 | ||
|
|
f28ee1bc4b | ||
|
|
b997f0a5a7 | ||
|
|
48dc47ce57 | ||
|
|
f1a90f4a11 | ||
|
|
990d7edba4 | ||
|
|
13a1da91be | ||
|
|
930b58d2a8 | ||
|
|
b88b1065ee | ||
|
|
5fbb802b32 | ||
|
|
a40f8d25ef | ||
|
|
0a28798d54 | ||
|
|
6047987c25 | ||
|
|
2ce96186f2 | ||
|
|
26357bd4bc | ||
|
|
e94b45a7e4 | ||
|
|
4be1eb7a28 | ||
|
|
f4bbbb640d | ||
|
|
94b4e70b0f | ||
|
|
b31e3f7783 | ||
|
|
6375ac857a | ||
|
|
5eac08430f | ||
|
|
ef0b109ad4 | ||
|
|
7fbe6c0955 | ||
|
|
c86e43597c | ||
|
|
123a73a5e6 | ||
|
|
706b5d253f | ||
|
|
8fb8c7a40b | ||
|
|
21220f93b1 | ||
|
|
705e64377b | ||
|
|
5c3f0cd060 | ||
|
|
a238be5b7c | ||
|
|
2351bb78da | ||
|
|
6bbc5a91fe | ||
|
|
2f52233bd0 | ||
|
|
92eccb635a | ||
|
|
1f8acc3afc | ||
|
|
f8eaa9e796 | ||
|
|
7c9fecd943 | ||
|
|
3df8cbb357 | ||
|
|
993cb9cb0b | ||
|
|
5bd4a3f761 | ||
|
|
fcad84ced3 | ||
|
|
0bd48981ec | ||
|
|
0bf7e8b705 | ||
|
|
875c451221 | ||
|
|
c8256bea3a | ||
|
|
7d10b951b7 | ||
|
|
34e9238cc4 | ||
|
|
7d97784a58 | ||
|
|
1265e7c4a1 | ||
|
|
44ece2bf34 | ||
|
|
fde2a8055d | ||
|
|
f9643c2503 | ||
|
|
e6a97e5cb3 | ||
|
|
73b5546ae9 | ||
|
|
f98719ee73 | ||
|
|
7666182ae3 | ||
|
|
05af30f336 | ||
|
|
20de08b625 | ||
|
|
e60f4f4a64 | ||
|
|
6af25d932c | ||
|
|
3f49a8a15a | ||
|
|
bfa8db7b55 | ||
|
|
d6f2e7588c | ||
|
|
a594332ffb | ||
|
|
ceb18ebf1c | ||
|
|
b9038e254e | ||
|
|
b351e42538 | ||
|
|
8910c26ee2 | ||
|
|
7549a7bbbe | ||
|
|
17fbe6e232 | ||
|
|
ccdac8f604 | ||
|
|
88a828c9ef | ||
|
|
ae3291b90e | ||
|
|
2c6f0452b8 | ||
|
|
4651acd6f4 | ||
|
|
bba7babce3 | ||
|
|
73dc6a4a92 | ||
|
|
992f5a525a | ||
|
|
b38d5789f3 | ||
|
|
47b5945e17 | ||
|
|
73544b0f06 | ||
|
|
e7d9311e23 | ||
|
|
c97c65b707 | ||
|
|
1c02b4e62a | ||
|
|
d23156d11a | ||
|
|
bd013adb4d | ||
|
|
c0368ce713 | ||
|
|
80283b5f55 | ||
|
|
4078645958 | ||
|
|
955ade0b8a | ||
|
|
4b158af9f6 | ||
|
|
642fae3ac7 | ||
|
|
d249967aee | ||
|
|
7b6b7f05e0 | ||
|
|
35b9bf5d34 | ||
|
|
59f0cc4f98 | ||
|
|
a29ca73fb4 | ||
|
|
59b658f059 | ||
|
|
3397b3108f | ||
|
|
cae7baa5e1 | ||
|
|
4af71fd1dd | ||
|
|
4194b61373 | ||
|
|
c91fd6783d | ||
|
|
89bbed1dfd | ||
|
|
2aeb53920c | ||
|
|
fe51c232b6 | ||
|
|
57b054794c | ||
|
|
8318c56046 | ||
|
|
0d52417ee7 | ||
|
|
6f3b1b8d6f | ||
|
|
a460d7722e | ||
|
|
d770208d4c | ||
|
|
0434109908 | ||
|
|
289d3a4e6b | ||
|
|
ffb9be63c7 | ||
|
|
bf2b53cbce | ||
|
|
1d9bf65c31 | ||
|
|
4744b918d3 | ||
|
|
588b1809a9 | ||
|
|
dc1c19293d | ||
|
|
1f548959e3 | ||
|
|
8cae5670fc | ||
|
|
07c0982d4f | ||
|
|
2f9e4b3198 | ||
|
|
89dba149a3 | ||
|
|
aa71b4c1b8 | ||
|
|
43110f8f2a | ||
|
|
e48540713d | ||
|
|
cfd13139e0 | ||
|
|
ac5cdf384f | ||
|
|
e9d858d902 | ||
|
|
1beae4403a | ||
|
|
dedf36f704 | ||
|
|
1477de3899 | ||
|
|
0d947c7dd8 | ||
|
|
ebfd8f40e3 | ||
|
|
3159cc0ded | ||
|
|
10dcbfb891 | ||
|
|
19dc16e14a | ||
|
|
95586b3156 | ||
|
|
0637daf645 | ||
|
|
fdcd62617d | ||
|
|
0f3e5ee4ed | ||
|
|
7b171ecc67 | ||
|
|
7a4052ede3 | ||
|
|
3f53a1f629 | ||
|
|
31daec5fe2 | ||
|
|
0d7155bda6 | ||
|
|
35beec3e39 | ||
|
|
ff4b96b622 | ||
|
|
9b60814292 | ||
|
|
3c4fa83161 | ||
|
|
e8564f6540 | ||
|
|
a22e97d4bd | ||
|
|
046e6af489 | ||
|
|
f805e8a688 | ||
|
|
2fddc32eb7 | ||
|
|
6018cd5d81 | ||
|
|
3533903be3 | ||
|
|
d867292f66 | ||
|
|
7691b662d6 | ||
|
|
86270dd856 | ||
|
|
012e2dde4f | ||
|
|
ad7a3c49f9 | ||
|
|
e8abd43c8a | ||
|
|
3192ce9d39 | ||
|
|
d09de09fef | ||
|
|
4689ddeb98 | ||
|
|
e300b33a4f | ||
|
|
0ca87ea407 | ||
|
|
2886da4f63 | ||
|
|
bf9ecb02e5 | ||
|
|
852617726c | ||
|
|
c2aa35104c | ||
|
|
95e237d4a3 | ||
|
|
59e5c547e9 | ||
|
|
06bd2b2b79 | ||
|
|
faede48217 | ||
|
|
ad0ac19d3d | ||
|
|
3154110de1 | ||
|
|
5248c05e61 | ||
|
|
8311030bec | ||
|
|
c429fc6b2c | ||
|
|
590aa9ab17 | ||
|
|
f9a7c2d457 | ||
|
|
b4506168fb | ||
|
|
f203ab3aaf | ||
|
|
c197dd0a4b | ||
|
|
457e596851 | ||
|
|
d274563b2c | ||
|
|
2003bea3cf | ||
|
|
f9b3284852 | ||
|
|
9bca133d88 | ||
|
|
03fc453608 | ||
|
|
3027cc81b3 | ||
|
|
2415fbf676 | ||
|
|
725c6a7ba9 | ||
|
|
c33da0cf8e | ||
|
|
d915d19425 | ||
|
|
f3370242bf | ||
|
|
0e312ba929 | ||
|
|
6440395197 | ||
|
|
5433abddaf | ||
|
|
0ccb465288 | ||
|
|
8fd4deb3eb | ||
|
|
fe8045c51d | ||
|
|
b890c59134 | ||
|
|
f39caeb967 | ||
|
|
7ab482184b | ||
|
|
78b12ae686 | ||
|
|
caa5deac4e | ||
|
|
af3083825e | ||
|
|
5255708ff2 | ||
|
|
9331f2034b | ||
|
|
fc6a5c22bf | ||
|
|
51c397d177 | ||
|
|
7c9596308e | ||
|
|
15dc424ade | ||
|
|
49243a8010 | ||
|
|
93e188d118 | ||
|
|
df3195fc1e | ||
|
|
da6b8c30a0 | ||
|
|
70468b6b7d | ||
|
|
2511512d94 | ||
|
|
4418617d3b | ||
|
|
6e480ba146 | ||
|
|
b4f5913a80 | ||
|
|
6a3062709c | ||
|
|
d66bc1faef | ||
|
|
bef7d45c3e | ||
|
|
bb9489a8d3 | ||
|
|
700eeb8f5a | ||
|
|
7e2f0049b6 | ||
|
|
b2388544d8 | ||
|
|
d772551c60 | ||
|
|
31dca6f06b | ||
|
|
83f68fe153 | ||
|
|
08a2ae0fd3 | ||
|
|
53d3f51c74 | ||
|
|
f7cdafb087 | ||
|
|
5b17808569 | ||
|
|
a7328e21f1 | ||
|
|
e64370e9a2 | ||
|
|
d5b37b2418 | ||
|
|
4da08d93fd | ||
|
|
c39e5c67f5 | ||
|
|
00d5cf13c9 | ||
|
|
1120bcfc0c | ||
|
|
8e506cb7c2 | ||
|
|
145b66d375 | ||
|
|
82e4a8bbc3 | ||
|
|
bca9bfb960 | ||
|
|
d8e19d9c17 | ||
|
|
95d74d1ca2 | ||
|
|
ebdd6d77f7 | ||
|
|
d56bcc4fdf | ||
|
|
4bb18cfc9a | ||
|
|
6f30692534 | ||
|
|
e249c1ec65 | ||
|
|
c2b4c77003 | ||
|
|
e64733827a | ||
|
|
ea81b0d414 | ||
|
|
000cf2a864 | ||
|
|
dc13b919b3 | ||
|
|
a0c8ec3171 | ||
|
|
80c13f7c4f | ||
|
|
1a6f3d808b | ||
|
|
ec8fac1199 | ||
|
|
98c93d3248 | ||
|
|
a053706c24 | ||
|
|
43c49f54d2 | ||
|
|
a15dfffa44 | ||
|
|
59985dee72 | ||
|
|
6b7132f134 | ||
|
|
5c2c99282d | ||
|
|
94e6f89d07 | ||
|
|
3804a746df | ||
|
|
5c2d7e2d2a | ||
|
|
c34dd462b6 | ||
|
|
9141b1a641 | ||
|
|
0fea85e2f2 | ||
|
|
a58c191ded | ||
|
|
77089a1178 | ||
|
|
b6304a04e6 |
BIN
.snapcraft/travis_snapcraft.cfg
Normal file
BIN
.snapcraft/travis_snapcraft.cfg
Normal file
Binary file not shown.
22
.travis.yml
22
.travis.yml
@@ -1,6 +1,20 @@
|
|||||||
language: node_js
|
language: node_js
|
||||||
node_js:
|
node_js:
|
||||||
- 'stable'
|
- stable
|
||||||
- 'lts/*'
|
- lts/*
|
||||||
|
script:
|
||||||
script: npm run lint && npm run test
|
- npm run lint && npm run test
|
||||||
|
- 'if [[ ${TRAVIS_PULL_REQUEST_BRANCH:-$TRAVIS_BRANCH} = "master" ]]; then npm install -g grunt npm@5.2 && grunt pre-build; fi'
|
||||||
|
after_success:
|
||||||
|
- openssl aes-256-cbc -K $encrypted_440d7f9a3c38_key -iv $encrypted_440d7f9a3c38_iv
|
||||||
|
-in .snapcraft/travis_snapcraft.cfg -out .snapcraft/snapcraft.cfg -d
|
||||||
|
sudo: required
|
||||||
|
services:
|
||||||
|
- docker
|
||||||
|
deploy:
|
||||||
|
'on':
|
||||||
|
branch: master
|
||||||
|
provider: script
|
||||||
|
script: if [ ${TRAVIS_NODE_VERSION} = "stable" ];then docker run -v $(pwd):$(pwd) -t snapcore/snapcraft sh -c "apt update -qq
|
||||||
|
&& cd $(pwd) && snapcraft && snapcraft push *.snap --release edge"; fi
|
||||||
|
skip_cleanup: true
|
||||||
|
|||||||
52
Backers.md
52
Backers.md
@@ -1,9 +1,49 @@
|
|||||||
Become a [backer](https://salt.bountysource.com/teams/boostnote) and support Boostnote!
|
<h1 align="center">Sponsors & Backers</h1>
|
||||||
You can support Boostnote from $ 5 a month!
|
|
||||||
|
|
||||||
# Backers
|
Boostnote is an open source project. It's an independent project with its ongoing development made possible entirely thanks to the support by these awesome [backers](https://github.com/BoostIO/Boostnote/blob/master/Backers.md). If you'd like to join them, please consider:
|
||||||
[Kazu Yokomizo](https://twitter.com/kazup_bot)
|
|
||||||
|
|
||||||
kolchan11
|
- [Become a backer or sponsor on Open Collective.](https://opencollective.com/boostnoteio)
|
||||||
|
|
||||||
RonWalker22
|
---
|
||||||
|
|
||||||
|
## Backers via OpenCollective
|
||||||
|
<a href="https://opencollective.com/boostnoteio#backers" target="_blank"><img src="https://opencollective.com/boostnoteio/backers.svg?width=890"></a>
|
||||||
|
|
||||||
|
- [Ralph03](https://opencollective.com/ralph03) - $24
|
||||||
|
|
||||||
|
- [Nikolas Dan](https://opencollective.com/nikolas-dan) - $20
|
||||||
|
|
||||||
|
- [tatoosh11](https://twitter.com/ta11) - $10
|
||||||
|
|
||||||
|
- [Alexander Borovkov](https://opencollective.com/alexander-borovkov) - $10
|
||||||
|
|
||||||
|
- [Yeojong Kim](https://twitter.com/yeojoy) - $5
|
||||||
|
|
||||||
|
- [Scotia Draven](https://opencollective.com/scotia-draven) - $5
|
||||||
|
|
||||||
|
- [spoonhoop](https://opencollective.com/spoonhoop) - $5
|
||||||
|
|
||||||
|
## Backers via Bountysource
|
||||||
|
https://salt.bountysource.com/teams/boostnote
|
||||||
|
|
||||||
|
- Kuzz - $65
|
||||||
|
|
||||||
|
- Intense Raiden - $45
|
||||||
|
|
||||||
|
- ravy22 - $25
|
||||||
|
|
||||||
|
- trentpolack - $20
|
||||||
|
|
||||||
|
- hikariru - $10
|
||||||
|
|
||||||
|
- kolchan11 - $10
|
||||||
|
|
||||||
|
- RonWalker22 - $10
|
||||||
|
|
||||||
|
- hocchuc - $5
|
||||||
|
|
||||||
|
- Adam - $5
|
||||||
|
|
||||||
|
- Steve - $5
|
||||||
|
|
||||||
|
- evmin - $5
|
||||||
|
|||||||
@@ -1 +1,10 @@
|
|||||||
Please paste some **screenshots** with the **developer tool** open if you report a bug.
|
<!--
|
||||||
|
Please paste some **screenshots** with the **developer tool** open (console tab) when you report a bug.
|
||||||
|
|
||||||
|
If your issue is regarding boostnote mobile, move to https://github.com/BoostIO/boostnote-mobile.
|
||||||
|
-->
|
||||||
|
|
||||||
|
<!--
|
||||||
|
Love Boostnote? Please consider supporting us via OpenCollective:
|
||||||
|
👉 https://opencollective.com/boostnoteio
|
||||||
|
-->
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import CodeMirror from 'codemirror'
|
|||||||
import path from 'path'
|
import path from 'path'
|
||||||
import copyImage from 'browser/main/lib/dataApi/copyImage'
|
import copyImage from 'browser/main/lib/dataApi/copyImage'
|
||||||
import { findStorage } from 'browser/lib/findStorage'
|
import { findStorage } from 'browser/lib/findStorage'
|
||||||
|
import fs from 'fs'
|
||||||
|
|
||||||
CodeMirror.modeURL = '../node_modules/codemirror/mode/%N/%N.js'
|
CodeMirror.modeURL = '../node_modules/codemirror/mode/%N/%N.js'
|
||||||
|
|
||||||
@@ -66,7 +67,7 @@ export default class CodeEditor extends React.Component {
|
|||||||
if (cm.somethingSelected()) cm.indentSelection('add')
|
if (cm.somethingSelected()) cm.indentSelection('add')
|
||||||
else {
|
else {
|
||||||
const tabs = cm.getOption('indentWithTabs')
|
const tabs = cm.getOption('indentWithTabs')
|
||||||
if (line.trimLeft() === '- ' || line.trimLeft() === '* ' || line.trimLeft() === '+ ') {
|
if (line.trimLeft().match(/^(-|\*|\+) (\[( |x)\] )?$/)) {
|
||||||
cm.execCommand('goLineStart')
|
cm.execCommand('goLineStart')
|
||||||
if (tabs) {
|
if (tabs) {
|
||||||
cm.execCommand('insertTab')
|
cm.execCommand('insertTab')
|
||||||
@@ -109,6 +110,7 @@ export default class CodeEditor extends React.Component {
|
|||||||
CodeMirror.Vim.defineEx('q!', 'q!', this.quitEditor)
|
CodeMirror.Vim.defineEx('q!', 'q!', this.quitEditor)
|
||||||
CodeMirror.Vim.defineEx('wq', 'wq', this.quitEditor)
|
CodeMirror.Vim.defineEx('wq', 'wq', this.quitEditor)
|
||||||
CodeMirror.Vim.defineEx('qw', 'qw', this.quitEditor)
|
CodeMirror.Vim.defineEx('qw', 'qw', this.quitEditor)
|
||||||
|
CodeMirror.Vim.map('ZZ', ':q', 'normal')
|
||||||
}
|
}
|
||||||
|
|
||||||
quitEditor () {
|
quitEditor () {
|
||||||
@@ -212,9 +214,7 @@ export default class CodeEditor extends React.Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
insertImageMd (imageMd) {
|
insertImageMd (imageMd) {
|
||||||
const textarea = this.editor.getInputField()
|
this.editor.replaceSelection(imageMd)
|
||||||
const cm = this.editor
|
|
||||||
cm.replaceSelection(`${textarea.value.substr(0, textarea.selectionStart)}${imageMd}${textarea.value.substr(textarea.selectionEnd)}`)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
handlePaste (editor, e) {
|
handlePaste (editor, e) {
|
||||||
@@ -232,9 +232,10 @@ export default class CodeEditor extends React.Component {
|
|||||||
const binaryData = new Buffer(base64data, 'base64').toString('binary')
|
const binaryData = new Buffer(base64data, 'base64').toString('binary')
|
||||||
const imageName = Math.random().toString(36).slice(-16)
|
const imageName = Math.random().toString(36).slice(-16)
|
||||||
const storagePath = findStorage(this.props.storageKey).path
|
const storagePath = findStorage(this.props.storageKey).path
|
||||||
const imagePath = path.join(`${storagePath}`, 'images', `${imageName}.png`)
|
const imageDir = path.join(storagePath, 'images')
|
||||||
|
if (!fs.existsSync(imageDir)) fs.mkdirSync(imageDir)
|
||||||
require('fs').writeFile(imagePath, binaryData, 'binary')
|
const imagePath = path.join(imageDir, `${imageName}.png`)
|
||||||
|
fs.writeFile(imagePath, binaryData, 'binary')
|
||||||
const imageMd = `})`
|
const imageMd = `})`
|
||||||
this.insertImageMd(imageMd)
|
this.insertImageMd(imageMd)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -266,6 +266,7 @@ class MarkdownEditor extends React.Component {
|
|||||||
onMouseUp={(e) => this.handlePreviewMouseUp(e)}
|
onMouseUp={(e) => this.handlePreviewMouseUp(e)}
|
||||||
onMouseDown={(e) => this.handlePreviewMouseDown(e)}
|
onMouseDown={(e) => this.handlePreviewMouseDown(e)}
|
||||||
onCheckboxClick={(e) => this.handleCheckboxClick(e)}
|
onCheckboxClick={(e) => this.handleCheckboxClick(e)}
|
||||||
|
showCopyNotification={config.ui.showCopyNotification}
|
||||||
storagePath={storage.path}
|
storagePath={storage.path}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ import eventEmitter from 'browser/main/lib/eventEmitter'
|
|||||||
import fs from 'fs'
|
import fs from 'fs'
|
||||||
import htmlTextHelper from 'browser/lib/htmlTextHelper'
|
import htmlTextHelper from 'browser/lib/htmlTextHelper'
|
||||||
import copy from 'copy-to-clipboard'
|
import copy from 'copy-to-clipboard'
|
||||||
|
import mdurl from 'mdurl'
|
||||||
|
|
||||||
const { remote } = require('electron')
|
const { remote } = require('electron')
|
||||||
const { app } = remote
|
const { app } = remote
|
||||||
@@ -32,15 +33,23 @@ function buildStyle (fontFamily, fontSize, codeBlockFontFamily, lineNumber) {
|
|||||||
font-weight: normal;
|
font-weight: normal;
|
||||||
text-rendering: optimizeLegibility;
|
text-rendering: optimizeLegibility;
|
||||||
}
|
}
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Lato';
|
||||||
|
src: url('${appPath}/resources/fonts/Lato-Black.woff2') format('woff2'), /* Modern Browsers */
|
||||||
|
url('${appPath}/resources/fonts/Lato-Black.woff') format('woff'), /* Modern Browsers */
|
||||||
|
url('${appPath}/resources/fonts/Lato-Black.ttf') format('truetype');
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 700;
|
||||||
|
text-rendering: optimizeLegibility;
|
||||||
|
}
|
||||||
${markdownStyle}
|
${markdownStyle}
|
||||||
body {
|
body {
|
||||||
font-family: ${fontFamily.join(', ')};
|
font-family: '${fontFamily.join("','")}';
|
||||||
font-size: ${fontSize}px;
|
font-size: ${fontSize}px;
|
||||||
}
|
}
|
||||||
code {
|
code {
|
||||||
font-family: ${codeBlockFontFamily.join(', ')};
|
font-family: ${codeBlockFontFamily.join(', ')};
|
||||||
background-color: rgba(0,0,0,0.04);
|
background-color: rgba(0,0,0,0.04);
|
||||||
color: #CC305F;
|
|
||||||
}
|
}
|
||||||
.lineNumber {
|
.lineNumber {
|
||||||
${lineNumber && 'display: block !important;'}
|
${lineNumber && 'display: block !important;'}
|
||||||
@@ -92,7 +101,7 @@ const OSX = global.process.platform === 'darwin'
|
|||||||
|
|
||||||
const defaultFontFamily = ['helvetica', 'arial', 'sans-serif']
|
const defaultFontFamily = ['helvetica', 'arial', 'sans-serif']
|
||||||
if (!OSX) {
|
if (!OSX) {
|
||||||
defaultFontFamily.unshift('\'Microsoft YaHei\'')
|
defaultFontFamily.unshift('Microsoft YaHei')
|
||||||
defaultFontFamily.unshift('meiryo')
|
defaultFontFamily.unshift('meiryo')
|
||||||
}
|
}
|
||||||
const defaultCodeBlockFontFamily = ['Monaco', 'Menlo', 'Ubuntu Mono', 'Consolas', 'source-code-pro', 'monospace']
|
const defaultCodeBlockFontFamily = ['Monaco', 'Menlo', 'Ubuntu Mono', 'Consolas', 'source-code-pro', 'monospace']
|
||||||
@@ -184,6 +193,16 @@ export default class MarkdownPreview extends React.Component {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fixDecodedURI (node) {
|
||||||
|
if (node && node.children.length === 1 && typeof node.children[0] === 'string') {
|
||||||
|
const { innerText, href } = node
|
||||||
|
|
||||||
|
node.innerText = mdurl.decode(href) === innerText
|
||||||
|
? href
|
||||||
|
: innerText
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
componentDidMount () {
|
componentDidMount () {
|
||||||
this.refs.root.setAttribute('sandbox', 'allow-scripts')
|
this.refs.root.setAttribute('sandbox', 'allow-scripts')
|
||||||
this.refs.root.contentWindow.document.body.addEventListener('contextmenu', this.contextMenuHandler)
|
this.refs.root.contentWindow.document.body.addEventListener('contextmenu', this.contextMenuHandler)
|
||||||
@@ -224,6 +243,7 @@ export default class MarkdownPreview extends React.Component {
|
|||||||
prevProps.codeBlockFontFamily !== this.props.codeBlockFontFamily ||
|
prevProps.codeBlockFontFamily !== this.props.codeBlockFontFamily ||
|
||||||
prevProps.codeBlockTheme !== this.props.codeBlockTheme ||
|
prevProps.codeBlockTheme !== this.props.codeBlockTheme ||
|
||||||
prevProps.lineNumber !== this.props.lineNumber ||
|
prevProps.lineNumber !== this.props.lineNumber ||
|
||||||
|
prevProps.showCopyNotification !== this.props.showCopyNotification ||
|
||||||
prevProps.theme !== this.props.theme) {
|
prevProps.theme !== this.props.theme) {
|
||||||
this.applyStyle()
|
this.applyStyle()
|
||||||
this.rewriteIframe()
|
this.rewriteIframe()
|
||||||
@@ -247,7 +267,9 @@ export default class MarkdownPreview extends React.Component {
|
|||||||
theme = consts.THEMES.some((_theme) => _theme === theme) && theme !== 'default'
|
theme = consts.THEMES.some((_theme) => _theme === theme) && theme !== 'default'
|
||||||
? theme
|
? theme
|
||||||
: 'elegant'
|
: 'elegant'
|
||||||
this.getWindow().document.getElementById('codeTheme').href = `${appPath}/node_modules/codemirror/theme/${theme}.css`
|
this.getWindow().document.getElementById('codeTheme').href = theme.startsWith('solarized')
|
||||||
|
? `${appPath}/node_modules/codemirror/theme/solarized.css`
|
||||||
|
: `${appPath}/node_modules/codemirror/theme/${theme}.css`
|
||||||
}
|
}
|
||||||
|
|
||||||
rewriteIframe () {
|
rewriteIframe () {
|
||||||
@@ -262,7 +284,7 @@ export default class MarkdownPreview extends React.Component {
|
|||||||
el.removeEventListener('click', this.linkClickHandler)
|
el.removeEventListener('click', this.linkClickHandler)
|
||||||
})
|
})
|
||||||
|
|
||||||
let { value, theme, indentSize, codeBlockTheme, storagePath } = this.props
|
let { value, theme, indentSize, codeBlockTheme, showCopyNotification, storagePath } = this.props
|
||||||
|
|
||||||
this.refs.root.contentWindow.document.body.setAttribute('data-theme', theme)
|
this.refs.root.contentWindow.document.body.setAttribute('data-theme', theme)
|
||||||
|
|
||||||
@@ -279,6 +301,7 @@ export default class MarkdownPreview extends React.Component {
|
|||||||
})
|
})
|
||||||
|
|
||||||
_.forEach(this.refs.root.contentWindow.document.querySelectorAll('a'), (el) => {
|
_.forEach(this.refs.root.contentWindow.document.querySelectorAll('a'), (el) => {
|
||||||
|
this.fixDecodedURI(el)
|
||||||
el.addEventListener('click', this.anchorClickHandler)
|
el.addEventListener('click', this.anchorClickHandler)
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -309,14 +332,21 @@ export default class MarkdownPreview extends React.Component {
|
|||||||
copyIcon.innerHTML = '<button class="clipboardButton"><svg width="13" height="13" viewBox="0 0 1792 1792" ><path d="M768 1664h896v-640h-416q-40 0-68-28t-28-68v-416h-384v1152zm256-1440v-64q0-13-9.5-22.5t-22.5-9.5h-704q-13 0-22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h704q13 0 22.5-9.5t9.5-22.5zm256 672h299l-299-299v299zm512 128v672q0 40-28 68t-68 28h-960q-40 0-68-28t-28-68v-160h-544q-40 0-68-28t-28-68v-1344q0-40 28-68t68-28h1088q40 0 68 28t28 68v328q21 13 36 28l408 408q28 28 48 76t20 88z"/></svg></button>'
|
copyIcon.innerHTML = '<button class="clipboardButton"><svg width="13" height="13" viewBox="0 0 1792 1792" ><path d="M768 1664h896v-640h-416q-40 0-68-28t-28-68v-416h-384v1152zm256-1440v-64q0-13-9.5-22.5t-22.5-9.5h-704q-13 0-22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h704q13 0 22.5-9.5t9.5-22.5zm256 672h299l-299-299v299zm512 128v672q0 40-28 68t-68 28h-960q-40 0-68-28t-28-68v-160h-544q-40 0-68-28t-28-68v-1344q0-40 28-68t68-28h1088q40 0 68 28t28 68v328q21 13 36 28l408 408q28 28 48 76t20 88z"/></svg></button>'
|
||||||
copyIcon.onclick = (e) => {
|
copyIcon.onclick = (e) => {
|
||||||
copy(content)
|
copy(content)
|
||||||
this.notify('Saved to Clipboard!', {
|
if (showCopyNotification) {
|
||||||
body: 'Paste it wherever you want!',
|
this.notify('Saved to Clipboard!', {
|
||||||
silent: true
|
body: 'Paste it wherever you want!',
|
||||||
})
|
silent: true
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
el.parentNode.appendChild(copyIcon)
|
el.parentNode.appendChild(copyIcon)
|
||||||
el.innerHTML = ''
|
el.innerHTML = ''
|
||||||
el.parentNode.className += ` cm-s-${codeBlockTheme} CodeMirror`
|
if (codeBlockTheme.indexOf('solarized') === 0) {
|
||||||
|
const [refThema, color] = codeBlockTheme.split(' ')
|
||||||
|
el.parentNode.className += ` cm-s-${refThema} cm-s-${color} CodeMirror`
|
||||||
|
} else {
|
||||||
|
el.parentNode.className += ` cm-s-${codeBlockTheme} CodeMirror`
|
||||||
|
}
|
||||||
CodeMirror.runMode(content, syntax.mime, el, {
|
CodeMirror.runMode(content, syntax.mime, el, {
|
||||||
tabSize: indentSize
|
tabSize: indentSize
|
||||||
})
|
})
|
||||||
@@ -426,5 +456,6 @@ MarkdownPreview.propTypes = {
|
|||||||
onMouseDown: PropTypes.func,
|
onMouseDown: PropTypes.func,
|
||||||
className: PropTypes.string,
|
className: PropTypes.string,
|
||||||
value: PropTypes.string,
|
value: PropTypes.string,
|
||||||
|
showCopyNotification: PropTypes.bool,
|
||||||
storagePath: PropTypes.string
|
storagePath: PropTypes.string
|
||||||
}
|
}
|
||||||
|
|||||||
29
browser/components/NavToggleButton.js
Normal file
29
browser/components/NavToggleButton.js
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
/**
|
||||||
|
* @fileoverview Micro component for toggle SideNav
|
||||||
|
*/
|
||||||
|
import React, { PropTypes } from 'react'
|
||||||
|
import styles from './NavToggleButton.styl'
|
||||||
|
import CSSModules from 'browser/lib/CSSModules'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {boolean} isFolded
|
||||||
|
* @param {Function} handleToggleButtonClick
|
||||||
|
*/
|
||||||
|
|
||||||
|
const NavToggleButton = ({isFolded, handleToggleButtonClick}) => (
|
||||||
|
<button styleName='navToggle'
|
||||||
|
onClick={(e) => handleToggleButtonClick(e)}
|
||||||
|
>
|
||||||
|
{isFolded
|
||||||
|
? <i className='fa fa-angle-double-right' />
|
||||||
|
: <i className='fa fa-angle-double-left' />
|
||||||
|
}
|
||||||
|
</button>
|
||||||
|
)
|
||||||
|
|
||||||
|
NavToggleButton.propTypes = {
|
||||||
|
isFolded: PropTypes.bool.isRequired,
|
||||||
|
handleToggleButtonClick: PropTypes.func.isRequired
|
||||||
|
}
|
||||||
|
|
||||||
|
export default CSSModules(NavToggleButton, styles)
|
||||||
22
browser/components/NavToggleButton.styl
Normal file
22
browser/components/NavToggleButton.styl
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
.navToggle
|
||||||
|
navButtonColor()
|
||||||
|
display block
|
||||||
|
position absolute
|
||||||
|
left 5px
|
||||||
|
bottom 5px
|
||||||
|
border-radius 16.5px
|
||||||
|
height 34px
|
||||||
|
width 34px
|
||||||
|
line-height 32px
|
||||||
|
padding 0
|
||||||
|
|
||||||
|
body[data-theme="white"]
|
||||||
|
navWhiteButtonColor()
|
||||||
|
|
||||||
|
body[data-theme="dark"]
|
||||||
|
.navToggle
|
||||||
|
&:hover
|
||||||
|
background-color alpha($ui-dark-button--active-backgroundColor, 20%)
|
||||||
|
transition 0.15s
|
||||||
|
color $ui-dark-text-color
|
||||||
|
|
||||||
@@ -41,16 +41,18 @@ const TagElementList = (tags) => {
|
|||||||
* @param {boolean} isActive
|
* @param {boolean} isActive
|
||||||
* @param {Object} note
|
* @param {Object} note
|
||||||
* @param {Function} handleNoteClick
|
* @param {Function} handleNoteClick
|
||||||
|
* @param {Function} handleNoteContextMenu
|
||||||
* @param {Function} handleDragStart
|
* @param {Function} handleDragStart
|
||||||
* @param {string} dateDisplay
|
* @param {string} dateDisplay
|
||||||
*/
|
*/
|
||||||
const NoteItem = ({ isActive, note, dateDisplay, handleNoteClick, handleDragStart }) => (
|
const NoteItem = ({ isActive, note, dateDisplay, handleNoteClick, handleNoteContextMenu, handleDragStart, pathname }) => (
|
||||||
<div styleName={isActive
|
<div styleName={isActive
|
||||||
? 'item--active'
|
? 'item--active'
|
||||||
: 'item'
|
: 'item'
|
||||||
}
|
}
|
||||||
key={`${note.storage}-${note.key}`}
|
key={`${note.storage}-${note.key}`}
|
||||||
onClick={e => handleNoteClick(e, `${note.storage}-${note.key}`)}
|
onClick={e => handleNoteClick(e, `${note.storage}-${note.key}`)}
|
||||||
|
onContextMenu={e => handleNoteContextMenu(e, `${note.storage}-${note.key}`)}
|
||||||
onDragStart={e => handleDragStart(e, note)}
|
onDragStart={e => handleDragStart(e, note)}
|
||||||
draggable='true'
|
draggable='true'
|
||||||
>
|
>
|
||||||
@@ -68,7 +70,10 @@ const NoteItem = ({ isActive, note, dateDisplay, handleNoteClick, handleDragStar
|
|||||||
|
|
||||||
<div styleName='item-bottom-time'>{dateDisplay}</div>
|
<div styleName='item-bottom-time'>{dateDisplay}</div>
|
||||||
{note.isStarred
|
{note.isStarred
|
||||||
? <i styleName='item-star' className='fa fa-star' /> : ''
|
? <img styleName='item-star' src='../resources/icon/icon-starred.svg' /> : ''
|
||||||
|
}
|
||||||
|
{note.isPinned && !pathname.match(/\/home|\/starred|\/trash/)
|
||||||
|
? <i styleName='item-pin' className='fa fa-thumb-tack' /> : ''
|
||||||
}
|
}
|
||||||
{note.type === 'MARKDOWN_NOTE'
|
{note.type === 'MARKDOWN_NOTE'
|
||||||
? <TodoProcess todoStatus={getTodoStatus(note.content)} />
|
? <TodoProcess todoStatus={getTodoStatus(note.content)} />
|
||||||
@@ -99,6 +104,7 @@ NoteItem.propTypes = {
|
|||||||
isTrashed: PropTypes.bool.isRequired
|
isTrashed: PropTypes.bool.isRequired
|
||||||
}),
|
}),
|
||||||
handleNoteClick: PropTypes.func.isRequired,
|
handleNoteClick: PropTypes.func.isRequired,
|
||||||
|
handleNoteContextMenu: PropTypes.func.isRequired,
|
||||||
handleDragStart: PropTypes.func.isRequired,
|
handleDragStart: PropTypes.func.isRequired,
|
||||||
handleDragEnd: PropTypes.func.isRequired
|
handleDragEnd: PropTypes.func.isRequired
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,9 +11,9 @@ $control-height = 30px
|
|||||||
user-select none
|
user-select none
|
||||||
cursor pointer
|
cursor pointer
|
||||||
background-color $ui-noteList-backgroundColor
|
background-color $ui-noteList-backgroundColor
|
||||||
transition background-color 0.2s
|
transition 0.2s
|
||||||
&:hover
|
&:hover
|
||||||
background-color alpha($ui-button--active-backgroundColor, 40%)
|
background-color alpha($ui-button--active-backgroundColor, 20%)
|
||||||
.item-title
|
.item-title
|
||||||
.item-title-icon
|
.item-title-icon
|
||||||
.item-bottom-time
|
.item-bottom-time
|
||||||
@@ -25,7 +25,7 @@ $control-height = 30px
|
|||||||
.item-star
|
.item-star
|
||||||
color $ui-favorite-star-button-color
|
color $ui-favorite-star-button-color
|
||||||
&:active
|
&:active
|
||||||
background-color $ui-button--active-backgroundColor
|
background-color alpha($ui-button--active-backgroundColor, 40%)
|
||||||
color $ui-text-color
|
color $ui-text-color
|
||||||
.item-title
|
.item-title
|
||||||
.item-title-icon
|
.item-title-icon
|
||||||
@@ -43,7 +43,7 @@ $control-height = 30px
|
|||||||
|
|
||||||
.item--active
|
.item--active
|
||||||
@extend .item
|
@extend .item
|
||||||
background-color $ui-button--active-backgroundColor
|
background-color alpha($ui-button--active-backgroundColor, 60%)
|
||||||
color $ui-text-color
|
color $ui-text-color
|
||||||
.item-title
|
.item-title
|
||||||
.item-title-empty
|
.item-title-empty
|
||||||
@@ -59,7 +59,15 @@ $control-height = 30px
|
|||||||
.item-star
|
.item-star
|
||||||
color $ui-favorite-star-button-color
|
color $ui-favorite-star-button-color
|
||||||
&:hover
|
&:hover
|
||||||
background-color $ui-button--active-backgroundColor
|
background-color alpha($ui-button--active-backgroundColor, 40%)
|
||||||
|
color #e74c3c
|
||||||
|
.menu-button-label
|
||||||
|
color $ui-text-color
|
||||||
|
&:active, &:active:hover
|
||||||
|
background-color alpha($ui-button--active-backgroundColor, 40%)
|
||||||
|
color #e74c3c
|
||||||
|
.menu-button-label
|
||||||
|
color $ui-text-color
|
||||||
|
|
||||||
.item-title-icon
|
.item-title-icon
|
||||||
position relative
|
position relative
|
||||||
@@ -67,7 +75,8 @@ $control-height = 30px
|
|||||||
color $ui-inactive-text-color
|
color $ui-inactive-text-color
|
||||||
|
|
||||||
.item-title
|
.item-title
|
||||||
font-size 14px
|
font-size 15px
|
||||||
|
font-weight 700
|
||||||
position relative
|
position relative
|
||||||
top -12px
|
top -12px
|
||||||
left 20px
|
left 20px
|
||||||
@@ -83,7 +92,7 @@ $control-height = 30px
|
|||||||
.item-bottom
|
.item-bottom
|
||||||
position relative
|
position relative
|
||||||
bottom 0px
|
bottom 0px
|
||||||
margin-top 2px
|
margin-top 10px
|
||||||
font-size 12px
|
font-size 12px
|
||||||
line-height 20px
|
line-height 20px
|
||||||
overflow ellipsis
|
overflow ellipsis
|
||||||
@@ -92,40 +101,63 @@ $control-height = 30px
|
|||||||
.item-bottom-tagList
|
.item-bottom-tagList
|
||||||
flex 1
|
flex 1
|
||||||
overflow ellipsis
|
overflow ellipsis
|
||||||
line-height 20px
|
line-height 25px
|
||||||
padding-top 7px
|
|
||||||
padding-left 2px
|
padding-left 2px
|
||||||
margin-right 27px
|
margin-right 40px
|
||||||
|
|
||||||
.item-bottom-tagList-item
|
.item-bottom-tagList-item
|
||||||
font-size 11px
|
font-size 11px
|
||||||
margin-right 8px
|
margin-right 8px
|
||||||
padding 0
|
padding 0
|
||||||
height 20px
|
|
||||||
box-sizing border-box
|
box-sizing border-box
|
||||||
border-radius 2px
|
border-radius 2px
|
||||||
padding 1px 2px
|
padding 4px
|
||||||
vertical-align middle
|
vertical-align middle
|
||||||
background-color white
|
background-color white
|
||||||
color $ui-inactive-text-color
|
color $ui-inactive-text-color
|
||||||
|
|
||||||
.item-bottom-time
|
.item-bottom-time
|
||||||
color $ui-inactive-text-color
|
color $ui-inactive-text-color
|
||||||
font-size 11px
|
font-size 13px
|
||||||
padding-left 2px
|
padding-left 2px
|
||||||
padding-bottom 2px
|
padding-bottom 2px
|
||||||
|
|
||||||
.item-star
|
.item-star
|
||||||
position absolute
|
position absolute
|
||||||
right -20px
|
right -6px
|
||||||
bottom 2px
|
bottom 23px
|
||||||
width 34px
|
width 16px
|
||||||
height 34px
|
height 16px
|
||||||
color alpha($ui-favorite-star-button-color, 60%)
|
color alpha($ui-favorite-star-button-color, 60%)
|
||||||
font-size 12px
|
font-size 12px
|
||||||
padding 0
|
padding 0
|
||||||
border-radius 17px
|
border-radius 17px
|
||||||
|
|
||||||
|
.item-pin
|
||||||
|
position absolute
|
||||||
|
right 0px
|
||||||
|
bottom 2px
|
||||||
|
width 34px
|
||||||
|
height 34px
|
||||||
|
color #E54D42
|
||||||
|
font-size 14px
|
||||||
|
padding 0
|
||||||
|
border-radius 17px
|
||||||
|
|
||||||
|
body[data-theme="white"]
|
||||||
|
.item
|
||||||
|
background-color $ui-white-noteList-backgroundColor
|
||||||
|
&:hover
|
||||||
|
background-color alpha($ui-button--active-backgroundColor, 60%)
|
||||||
|
&:active
|
||||||
|
background-color $ui-button--active-backgroundColor
|
||||||
|
|
||||||
|
.item--active
|
||||||
|
@extend .item
|
||||||
|
background-color $ui-button--active-backgroundColor
|
||||||
|
&:hover
|
||||||
|
background-color alpha($ui-button--active-backgroundColor, 60%)
|
||||||
|
|
||||||
body[data-theme="dark"]
|
body[data-theme="dark"]
|
||||||
.root
|
.root
|
||||||
border-color $ui-dark-borderColor
|
border-color $ui-dark-borderColor
|
||||||
@@ -137,6 +169,7 @@ body[data-theme="dark"]
|
|||||||
&:hover
|
&:hover
|
||||||
transition 0.15s
|
transition 0.15s
|
||||||
background-color alpha($ui-dark-button--active-backgroundColor, 20%)
|
background-color alpha($ui-dark-button--active-backgroundColor, 20%)
|
||||||
|
color $ui-dark-text-color
|
||||||
.item-title
|
.item-title
|
||||||
.item-title-icon
|
.item-title-icon
|
||||||
.item-bottom-time
|
.item-bottom-time
|
||||||
@@ -144,11 +177,12 @@ body[data-theme="dark"]
|
|||||||
color $ui-dark-text-color
|
color $ui-dark-text-color
|
||||||
.item-bottom-tagList-item
|
.item-bottom-tagList-item
|
||||||
transition 0.15s
|
transition 0.15s
|
||||||
background-color alpha($ui-dark-button--active-backgroundColor, 40%)
|
background-color alpha(#fff, 20%)
|
||||||
color $ui-dark-text-color
|
color $ui-dark-text-color
|
||||||
&:active
|
&:active
|
||||||
transition 0.15s
|
transition 0.15s
|
||||||
background-color $ui-dark-button--active-backgroundColor
|
background-color $ui-dark-button--active-backgroundColor
|
||||||
|
color $ui-dark-text-color
|
||||||
.item-title
|
.item-title
|
||||||
.item-title-icon
|
.item-title-icon
|
||||||
.item-bottom-time
|
.item-bottom-time
|
||||||
@@ -174,6 +208,11 @@ body[data-theme="dark"]
|
|||||||
.item-bottom-tagList-item
|
.item-bottom-tagList-item
|
||||||
background-color alpha(white, 10%)
|
background-color alpha(white, 10%)
|
||||||
color $ui-dark-text-color
|
color $ui-dark-text-color
|
||||||
|
&:hover
|
||||||
|
background-color alpha($ui-dark-button--active-backgroundColor, 60%)
|
||||||
|
color #c0392b
|
||||||
|
.item-bottom-tagList-item
|
||||||
|
background-color alpha(#fff, 20%)
|
||||||
|
|
||||||
.item-title
|
.item-title
|
||||||
color $ui-inactive-text-color
|
color $ui-inactive-text-color
|
||||||
|
|||||||
@@ -10,15 +10,17 @@ import styles from './NoteItemSimple.styl'
|
|||||||
* @param {boolean} isActive
|
* @param {boolean} isActive
|
||||||
* @param {Object} note
|
* @param {Object} note
|
||||||
* @param {Function} handleNoteClick
|
* @param {Function} handleNoteClick
|
||||||
|
* @param {Function} handleNoteContextMenu
|
||||||
* @param {Function} handleDragStart
|
* @param {Function} handleDragStart
|
||||||
*/
|
*/
|
||||||
const NoteItemSimple = ({ isActive, note, handleNoteClick, handleDragStart }) => (
|
const NoteItemSimple = ({ isActive, note, handleNoteClick, handleNoteContextMenu, handleDragStart }) => (
|
||||||
<div styleName={isActive
|
<div styleName={isActive
|
||||||
? 'item-simple--active'
|
? 'item-simple--active'
|
||||||
: 'item-simple'
|
: 'item-simple'
|
||||||
}
|
}
|
||||||
key={`${note.storage}-${note.key}`}
|
key={`${note.storage}-${note.key}`}
|
||||||
onClick={e => handleNoteClick(e, `${note.storage}-${note.key}`)}
|
onClick={e => handleNoteClick(e, `${note.storage}-${note.key}`)}
|
||||||
|
onContextMenu={e => handleNoteContextMenu(e, `${note.storage}-${note.key}`)}
|
||||||
onDragStart={e => handleDragStart(e, note)}
|
onDragStart={e => handleDragStart(e, note)}
|
||||||
draggable='true'
|
draggable='true'
|
||||||
>
|
>
|
||||||
@@ -44,6 +46,7 @@ NoteItemSimple.propTypes = {
|
|||||||
title: PropTypes.string.isrequired
|
title: PropTypes.string.isrequired
|
||||||
}),
|
}),
|
||||||
handleNoteClick: PropTypes.func.isRequired,
|
handleNoteClick: PropTypes.func.isRequired,
|
||||||
|
handleNoteContextMenu: PropTypes.func.isRequired,
|
||||||
handleDragStart: PropTypes.func.isRequired
|
handleDragStart: PropTypes.func.isRequired
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -11,15 +11,15 @@ $control-height = 30px
|
|||||||
user-select none
|
user-select none
|
||||||
cursor pointer
|
cursor pointer
|
||||||
background-color $ui-noteList-backgroundColor
|
background-color $ui-noteList-backgroundColor
|
||||||
transition background-color 0.15s
|
transition 0.2s
|
||||||
&:hover
|
&:hover
|
||||||
background-color alpha($ui-button--active-backgroundColor, 40%)
|
background-color alpha($ui-button--active-backgroundColor, 20%)
|
||||||
.item-simple-title
|
.item-simple-title
|
||||||
.item-simple-title-empty
|
.item-simple-title-empty
|
||||||
.item-simple-title-icon
|
.item-simple-title-icon
|
||||||
color $ui-text-color
|
color $ui-text-color
|
||||||
&:active
|
&:active
|
||||||
background-color $ui-button--active-backgroundColor
|
background-color alpha($ui-button--active-backgroundColor, 40%)
|
||||||
color $ui-text-color
|
color $ui-text-color
|
||||||
.item-simple-title
|
.item-simple-title
|
||||||
.item-simple-title-empty
|
.item-simple-title-empty
|
||||||
@@ -28,7 +28,7 @@ $control-height = 30px
|
|||||||
|
|
||||||
.item-simple--active
|
.item-simple--active
|
||||||
@extend .item-simple
|
@extend .item-simple
|
||||||
background-color $ui-button--active-backgroundColor
|
background-color alpha($ui-button--active-backgroundColor, 60%)
|
||||||
color $ui-text-color
|
color $ui-text-color
|
||||||
.item-simple-title
|
.item-simple-title
|
||||||
.item-simple-title-empty
|
.item-simple-title-empty
|
||||||
@@ -37,7 +37,15 @@ $control-height = 30px
|
|||||||
.item-simple-title-icon
|
.item-simple-title-icon
|
||||||
color $ui-text-color
|
color $ui-text-color
|
||||||
&:hover
|
&:hover
|
||||||
background-color $ui-button--active-backgroundColor
|
background-color alpha($ui-button--active-backgroundColor, 40%)
|
||||||
|
color #e74c3c
|
||||||
|
.menu-button-label
|
||||||
|
color $ui-text-color
|
||||||
|
&:active, &:active:hover
|
||||||
|
background-color alpha($ui-button--active-backgroundColor, 40%)
|
||||||
|
color #e74c3c
|
||||||
|
.menu-button-label
|
||||||
|
color $ui-text-color
|
||||||
|
|
||||||
.item-simple-title
|
.item-simple-title
|
||||||
font-size 13px
|
font-size 13px
|
||||||
@@ -59,6 +67,20 @@ $control-height = 30px
|
|||||||
font-weight normal
|
font-weight normal
|
||||||
color $ui-inactive-text-color
|
color $ui-inactive-text-color
|
||||||
|
|
||||||
|
body[data-theme="white"]
|
||||||
|
.item-simple
|
||||||
|
background-color $ui-white-noteList-backgroundColor
|
||||||
|
&:hover
|
||||||
|
background-color alpha($ui-button--active-backgroundColor, 60%)
|
||||||
|
&:active
|
||||||
|
background-color $ui-button--active-backgroundColor
|
||||||
|
|
||||||
|
.item-simple--active
|
||||||
|
@extend .item-simple
|
||||||
|
background-color $ui-button--active-backgroundColor
|
||||||
|
&:hover
|
||||||
|
background-color alpha($ui-button--active-backgroundColor, 60%)
|
||||||
|
|
||||||
body[data-theme="dark"]
|
body[data-theme="dark"]
|
||||||
.root
|
.root
|
||||||
border-color $ui-dark-borderColor
|
border-color $ui-dark-borderColor
|
||||||
@@ -67,33 +89,50 @@ body[data-theme="dark"]
|
|||||||
.item-simple
|
.item-simple
|
||||||
border-color $ui-dark-borderColor
|
border-color $ui-dark-borderColor
|
||||||
background-color $ui-dark-noteList-backgroundColor
|
background-color $ui-dark-noteList-backgroundColor
|
||||||
&:active
|
&:hover
|
||||||
background-color $ui-dark-button--active-backgroundColor
|
transition 0.15s
|
||||||
|
background-color alpha($ui-dark-button--active-backgroundColor, 20%)
|
||||||
|
color $ui-dark-text-color
|
||||||
.item-simple-title
|
.item-simple-title
|
||||||
.item-simple-title-icon
|
.item-simple-title-icon
|
||||||
.item-simple-bottom-time
|
.item-simple-bottom-time
|
||||||
.item-simple-bottom-tagList-item
|
|
||||||
transition 0.15s
|
transition 0.15s
|
||||||
color $ui-dark-text-color
|
color $ui-dark-text-color
|
||||||
&:hover
|
.item-simple-bottom-tagList-item
|
||||||
background-color alpha($ui-dark-button--active-backgroundColor, 20%)
|
transition 0.15s
|
||||||
|
background-color alpha(#fff, 20%)
|
||||||
|
color $ui-dark-text-color
|
||||||
|
&:active
|
||||||
|
transition 0.15s
|
||||||
|
background-color $ui-dark-button--active-backgroundColor
|
||||||
|
color $ui-dark-text-color
|
||||||
.item-simple-title
|
.item-simple-title
|
||||||
.item-simple-title-icon
|
.item-simple-title-icon
|
||||||
.item-simple-bottom-time
|
.item-simple-bottom-time
|
||||||
|
transition 0.15s
|
||||||
|
color $ui-dark-text-color
|
||||||
.item-simple-bottom-tagList-item
|
.item-simple-bottom-tagList-item
|
||||||
transition 0.15s
|
transition 0.15s
|
||||||
|
background-color alpha(white, 10%)
|
||||||
color $ui-dark-text-color
|
color $ui-dark-text-color
|
||||||
|
|
||||||
.item-simple--active
|
.item-simple--active
|
||||||
border-color $ui-dark-borderColor
|
border-color $ui-dark-borderColor
|
||||||
background-color $ui-dark-button--active-backgroundColor
|
background-color $ui-dark-button--active-backgroundColor
|
||||||
|
.item-simple-wrapper
|
||||||
|
border-color transparent
|
||||||
.item-simple-title
|
.item-simple-title
|
||||||
.item-simple-title-icon
|
.item-simple-title-icon
|
||||||
.item-simple-bottom-time
|
.item-simple-bottom-time
|
||||||
color $ui-dark-text-color
|
color $ui-dark-text-color
|
||||||
.item-simple-bottom-tagList-item
|
.item-simple-bottom-tagList-item
|
||||||
background-color transparent
|
background-color alpha(white, 10%)
|
||||||
color $ui-dark-text-color
|
color $ui-dark-text-color
|
||||||
|
&:hover
|
||||||
|
background-color alpha($ui-dark-button--active-backgroundColor, 60%)
|
||||||
|
color #c0392b
|
||||||
|
.item-simple-bottom-tagList-item
|
||||||
|
background-color alpha(#fff, 20%)
|
||||||
|
|
||||||
.item-simple-title
|
.item-simple-title
|
||||||
color $ui-inactive-text-color
|
color $ui-inactive-text-color
|
||||||
|
|||||||
@@ -40,12 +40,12 @@ class RealtimeNotification extends React.Component {
|
|||||||
? <a styleName='notification-link' href={notifications[0].linkUrl}
|
? <a styleName='notification-link' href={notifications[0].linkUrl}
|
||||||
onClick={(e) => this.handleLinkClick(e)}
|
onClick={(e) => this.handleLinkClick(e)}
|
||||||
>
|
>
|
||||||
{notifications[0].text}
|
Info: {notifications[0].text}
|
||||||
</a>
|
</a>
|
||||||
: ''
|
: ''
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div styleName='notification-area'>{link}</div>
|
<div styleName='notification-area' style={this.props.style}>{link}</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,29 +2,28 @@
|
|||||||
z-index 1000
|
z-index 1000
|
||||||
font-size 12px
|
font-size 12px
|
||||||
position absolute
|
position absolute
|
||||||
bottom 0px
|
bottom 20px
|
||||||
background-color #EBEBEB
|
width 100%
|
||||||
width 100vw
|
float left
|
||||||
height 30px
|
height 30px
|
||||||
text-align center
|
background-color none
|
||||||
|
|
||||||
.notification-link
|
.notification-link
|
||||||
|
position absolute
|
||||||
text-decoration none
|
text-decoration none
|
||||||
color #282A36
|
color #282A36
|
||||||
|
font-size 14px
|
||||||
border 1px solid #6FA8E6
|
border 1px solid #6FA8E6
|
||||||
background-color alpha(#6FA8E6, 0.2)
|
background-color alpha(#6FA8E6, 0.2)
|
||||||
padding 3px 9px
|
padding 5px 12px
|
||||||
border-radius 2px
|
border-radius 2px
|
||||||
position absolute
|
|
||||||
bottom 4px
|
|
||||||
margin-left -10%
|
|
||||||
transition 0.2s
|
transition 0.2s
|
||||||
&:hover
|
&:hover
|
||||||
color #1378BD
|
color #1378BD
|
||||||
|
|
||||||
body[data-theme="dark"]
|
body[data-theme="dark"]
|
||||||
.notification-area
|
.notification-area
|
||||||
background-color #1E2124
|
background-color none
|
||||||
|
|
||||||
.notification-link
|
.notification-link
|
||||||
color #fff
|
color #fff
|
||||||
|
|||||||
@@ -15,27 +15,53 @@ import styles from './SideNavFilter.styl'
|
|||||||
*/
|
*/
|
||||||
const SideNavFilter = ({
|
const SideNavFilter = ({
|
||||||
isFolded, isHomeActive, handleAllNotesButtonClick,
|
isFolded, isHomeActive, handleAllNotesButtonClick,
|
||||||
isStarredActive, handleStarredButtonClick, isTrashedActive, handleTrashedButtonClick
|
isStarredActive, handleStarredButtonClick, isTrashedActive, handleTrashedButtonClick, counterDelNote,
|
||||||
|
counterTotalNote, counterStarredNote
|
||||||
}) => (
|
}) => (
|
||||||
<div styleName={isFolded ? 'menu--folded' : 'menu'}>
|
<div styleName={isFolded ? 'menu--folded' : 'menu'}>
|
||||||
|
|
||||||
<button styleName={isHomeActive ? 'menu-button--active' : 'menu-button'}
|
<button styleName={isHomeActive ? 'menu-button--active' : 'menu-button'}
|
||||||
onClick={handleAllNotesButtonClick}
|
onClick={handleAllNotesButtonClick}
|
||||||
>
|
>
|
||||||
<i className='fa fa-archive fa-fw' />
|
<div styleName='iconWrap'>
|
||||||
|
<img src={isHomeActive
|
||||||
|
? '../resources/icon/icon-all-active.svg'
|
||||||
|
: '../resources/icon/icon-all.svg'
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
<span styleName='menu-button-label'>All Notes</span>
|
<span styleName='menu-button-label'>All Notes</span>
|
||||||
|
<span styleName='counters'>{counterTotalNote}</span>
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
<button styleName={isStarredActive ? 'menu-button-star--active' : 'menu-button'}
|
<button styleName={isStarredActive ? 'menu-button-star--active' : 'menu-button'}
|
||||||
onClick={handleStarredButtonClick}
|
onClick={handleStarredButtonClick}
|
||||||
>
|
>
|
||||||
<i className='fa fa-star fa-fw' />
|
<div styleName='iconWrap'>
|
||||||
|
<img src={isStarredActive
|
||||||
|
? '../resources/icon/icon-star-active.svg'
|
||||||
|
: '../resources/icon/icon-star.svg'
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
<span styleName='menu-button-label'>Starred</span>
|
<span styleName='menu-button-label'>Starred</span>
|
||||||
|
<span styleName='counters'>{counterStarredNote}</span>
|
||||||
</button>
|
</button>
|
||||||
<button styleName={isTrashedActive ? 'menu-button--active' : 'menu-button'}
|
|
||||||
|
<button styleName={isTrashedActive ? 'menu-button-trash--active' : 'menu-button'}
|
||||||
onClick={handleTrashedButtonClick}
|
onClick={handleTrashedButtonClick}
|
||||||
>
|
>
|
||||||
<i className='fa fa-trash fa-fw' />
|
<div styleName='iconWrap'>
|
||||||
|
<img src={isTrashedActive
|
||||||
|
? '../resources/icon/icon-trash-active.svg'
|
||||||
|
: '../resources/icon/icon-trash.svg'
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
<span styleName='menu-button-label'>Trash</span>
|
<span styleName='menu-button-label'>Trash</span>
|
||||||
|
<span styleName='counters'>{counterDelNote}</span>
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -3,49 +3,55 @@
|
|||||||
|
|
||||||
.menu-button
|
.menu-button
|
||||||
navButtonColor()
|
navButtonColor()
|
||||||
height 32px
|
height 36px
|
||||||
padding 0 15px
|
padding 0 15px 0 20px
|
||||||
font-size 12px
|
font-size 14px
|
||||||
width 100%
|
width 100%
|
||||||
text-align left
|
text-align left
|
||||||
overflow ellipsis
|
overflow ellipsis
|
||||||
|
display flex
|
||||||
|
align-items center
|
||||||
|
&:hover, &:active, &:active:hover
|
||||||
|
color #1EC38B
|
||||||
|
background-color alpha($ui-button-default--active-backgroundColor, 20%)
|
||||||
|
|
||||||
|
.iconWrap
|
||||||
|
width 20px
|
||||||
|
text-align center
|
||||||
|
|
||||||
|
.counters
|
||||||
|
float right
|
||||||
|
color $ui-inactive-text-color
|
||||||
|
|
||||||
.menu-button--active
|
.menu-button--active
|
||||||
@extend .menu-button
|
@extend .menu-button
|
||||||
color #e74c3c
|
SideNavFilter()
|
||||||
background-color $ui-button--active-backgroundColor
|
color #1EC38B
|
||||||
.menu-button-label
|
background-color alpha($ui-button-default--active-backgroundColor, 20%)
|
||||||
color $ui-text-color
|
.menu-button-label, .counters
|
||||||
|
color #1EC38B
|
||||||
&:hover
|
&:hover
|
||||||
background-color $ui-button--active-backgroundColor
|
color #1EC38B
|
||||||
color #e74c3c
|
|
||||||
.menu-button-label
|
|
||||||
color $ui-text-color
|
|
||||||
&:active, &:active:hover
|
|
||||||
background-color $ui-button--active-backgroundColor
|
|
||||||
color #e74c3c
|
|
||||||
.menu-button-label
|
|
||||||
color $ui-text-color
|
|
||||||
|
|
||||||
.menu-button-star--active
|
.menu-button-star--active
|
||||||
@extend .menu-button
|
@extend .menu-button
|
||||||
color #F9BF3B
|
SideNavFilter()
|
||||||
background-color $ui-button--active-backgroundColor
|
color #1EC38B
|
||||||
.menu-button-label
|
background-color alpha($ui-button-default--active-backgroundColor, 20%)
|
||||||
color $ui-text-color
|
.menu-button-label, .counters
|
||||||
&:hover
|
color #1EC38B
|
||||||
background-color $ui-button--active-backgroundColor
|
|
||||||
color #F9BF3B
|
.menu-button-trash--active
|
||||||
.menu-button-label
|
@extend .menu-button
|
||||||
color $ui-text-color
|
SideNavFilter()
|
||||||
&:active, &:active:hover
|
color #1EC38B
|
||||||
background-color $ui-button--active-backgroundColor
|
background-color alpha($ui-button-default--active-backgroundColor, 20%)
|
||||||
color #F9BF3B
|
.menu-button-label, .counters
|
||||||
.menu-button-label
|
color #1EC38B
|
||||||
color $ui-text-color
|
|
||||||
|
|
||||||
.menu-button-label
|
.menu-button-label
|
||||||
margin-left 5px
|
margin-left 10px
|
||||||
|
flex 1
|
||||||
|
|
||||||
.menu--folded
|
.menu--folded
|
||||||
@extend .menu
|
@extend .menu
|
||||||
@@ -54,6 +60,7 @@
|
|||||||
&:hover .menu-button-label
|
&:hover .menu-button-label
|
||||||
transition opacity 0.15s
|
transition opacity 0.15s
|
||||||
opacity 1
|
opacity 1
|
||||||
|
|
||||||
.menu-button-label
|
.menu-button-label
|
||||||
position fixed
|
position fixed
|
||||||
display inline-block
|
display inline-block
|
||||||
@@ -63,15 +70,73 @@
|
|||||||
margin-top -8px
|
margin-top -8px
|
||||||
margin-left 0
|
margin-left 0
|
||||||
overflow ellipsis
|
overflow ellipsis
|
||||||
background-color $ui-tooltip-backgroundColor
|
|
||||||
z-index 10
|
z-index 10
|
||||||
color white
|
|
||||||
line-height 32px
|
line-height 32px
|
||||||
border-top-right-radius 2px
|
border-top-right-radius 2px
|
||||||
border-bottom-right-radius 2px
|
border-bottom-right-radius 2px
|
||||||
pointer-events none
|
pointer-events none
|
||||||
opacity 0
|
opacity 0
|
||||||
font-size 12px
|
font-size 13px
|
||||||
|
.counters
|
||||||
|
display none
|
||||||
|
|
||||||
|
body[data-theme="white"]
|
||||||
|
.menu-button
|
||||||
|
navWhiteButtonColor()
|
||||||
|
|
||||||
|
.counters
|
||||||
|
color $ui-inactive-text-color
|
||||||
|
|
||||||
|
.menu-button--active
|
||||||
|
@extend .menu-button
|
||||||
|
color #e74c3c
|
||||||
|
background-color $ui-button--active-backgroundColor
|
||||||
|
.menu-button-label
|
||||||
|
color $ui-text-color
|
||||||
|
&:hover
|
||||||
|
background-color alpha($ui-button--active-backgroundColor, 50%)
|
||||||
|
color #e74c3c
|
||||||
|
.menu-button-label
|
||||||
|
color $ui-text-color
|
||||||
|
&:active, &:active:hover
|
||||||
|
background-color alpha($ui-button--active-backgroundColor, 50%)
|
||||||
|
color #e74c3c
|
||||||
|
.menu-button-label
|
||||||
|
color $ui-text-color
|
||||||
|
|
||||||
|
.menu-button-star--active
|
||||||
|
@extend .menu-button
|
||||||
|
color #F9BF3B
|
||||||
|
background-color $ui-button--active-backgroundColor
|
||||||
|
.menu-button-label
|
||||||
|
color $ui-text-color
|
||||||
|
&:hover
|
||||||
|
background-color alpha($ui-button--active-backgroundColor, 50%)
|
||||||
|
color #F9BF3B
|
||||||
|
.menu-button-label
|
||||||
|
color $ui-text-color
|
||||||
|
&:active, &:active:hover
|
||||||
|
background-color alpha($ui-button--active-backgroundColor, 50%)
|
||||||
|
color #F9BF3B
|
||||||
|
.menu-button-label
|
||||||
|
color $ui-text-color
|
||||||
|
|
||||||
|
.menu-button-trash--active
|
||||||
|
@extend .menu-button
|
||||||
|
color #5D9E36
|
||||||
|
background-color $ui-button--active-backgroundColor
|
||||||
|
.menu-button-label
|
||||||
|
color $ui-text-color
|
||||||
|
&:hover
|
||||||
|
background-color alpha($ui-button--active-backgroundColor, 50%)
|
||||||
|
color #5D9E36
|
||||||
|
.menu-button-label
|
||||||
|
color $ui-text-color
|
||||||
|
&:active, &:active:hover
|
||||||
|
background-color alpha($ui-button--active-backgroundColor, 50%)
|
||||||
|
color #5D9E36
|
||||||
|
.menu-button-label
|
||||||
|
color $ui-text-color
|
||||||
|
|
||||||
body[data-theme="dark"]
|
body[data-theme="dark"]
|
||||||
.menu-button
|
.menu-button
|
||||||
@@ -88,7 +153,7 @@ body[data-theme="dark"]
|
|||||||
.menu-button-label
|
.menu-button-label
|
||||||
color $ui-dark-text-color
|
color $ui-dark-text-color
|
||||||
&:hover
|
&:hover
|
||||||
background-color $ui-dark-button--active-backgroundColor
|
background-color alpha($ui-dark-button--active-backgroundColor, 50%)
|
||||||
color #c0392b
|
color #c0392b
|
||||||
.menu-button-label
|
.menu-button-label
|
||||||
color $ui-dark-text-color
|
color $ui-dark-text-color
|
||||||
@@ -99,7 +164,18 @@ body[data-theme="dark"]
|
|||||||
.menu-button-label
|
.menu-button-label
|
||||||
color $ui-dark-text-color
|
color $ui-dark-text-color
|
||||||
&:hover
|
&:hover
|
||||||
background-color $ui-dark-button--active-backgroundColor
|
background-color alpha($ui-dark-button--active-backgroundColor, 50%)
|
||||||
color $ui-favorite-star-button-color
|
color $ui-favorite-star-button-color
|
||||||
.menu-button-label
|
.menu-button-label
|
||||||
color $ui-dark-text-color
|
color $ui-dark-text-color
|
||||||
|
|
||||||
|
.menu-button-trash--active
|
||||||
|
color #5D9E36
|
||||||
|
background-color $ui-dark-button--active-backgroundColor
|
||||||
|
.menu-button-label
|
||||||
|
color $ui-dark-text-color
|
||||||
|
&:hover
|
||||||
|
background-color alpha($ui-dark-button--active-backgroundColor, 50%)
|
||||||
|
color #5D9E36
|
||||||
|
.menu-button-label
|
||||||
|
color $ui-dark-text-color
|
||||||
@@ -35,10 +35,8 @@ const StorageItem = ({
|
|||||||
>
|
>
|
||||||
<span styleName={isFolded
|
<span styleName={isFolded
|
||||||
? 'folderList-item-name--folded' : 'folderList-item-name'
|
? 'folderList-item-name--folded' : 'folderList-item-name'
|
||||||
}
|
}>
|
||||||
style={{borderColor: folderColor}}
|
<text style={{color: folderColor, paddingRight: '10px'}}>{isActive ? <i className='fa fa-folder-open-o' /> : <i className='fa fa-folder-o' />}</text>{isFolded ? folderName.substring(0, 1) : folderName}
|
||||||
>
|
|
||||||
{isFolded ? folderName.substring(0, 1) : folderName}
|
|
||||||
</span>
|
</span>
|
||||||
{(!isFolded && isNumber(noteCount)) &&
|
{(!isFolded && isNumber(noteCount)) &&
|
||||||
<span styleName='folderList-item-noteCount'>{noteCount}</span>
|
<span styleName='folderList-item-noteCount'>{noteCount}</span>
|
||||||
|
|||||||
@@ -5,37 +5,36 @@
|
|||||||
.folderList-item
|
.folderList-item
|
||||||
display flex
|
display flex
|
||||||
width 100%
|
width 100%
|
||||||
height 26px
|
height 34px
|
||||||
background-color transparent
|
background-color transparent
|
||||||
color $ui-inactive-text-color
|
color $ui-inactive-text-color
|
||||||
padding 0
|
padding 0
|
||||||
margin-bottom 5px
|
|
||||||
text-align left
|
text-align left
|
||||||
border none
|
border none
|
||||||
overflow ellipsis
|
overflow ellipsis
|
||||||
font-size 12px
|
font-size 14px
|
||||||
&:first-child
|
&:first-child
|
||||||
margin-top 0
|
margin-top 0
|
||||||
&:hover
|
&:hover
|
||||||
color $ui-text-color
|
color #1EC38B;
|
||||||
background-color alpha($ui-button--active-backgroundColor, 20%)
|
background-color alpha($ui-button-default--active-backgroundColor, 20%)
|
||||||
transition background-color 0.15s
|
transition background-color 0.15s
|
||||||
&:active
|
&:active
|
||||||
color $ui-text-color
|
color $$ui-button-default-color
|
||||||
background-color $ui-button--active-backgroundColor
|
background-color alpha($ui-button-default--active-backgroundColor, 20%)
|
||||||
|
|
||||||
.folderList-item--active
|
.folderList-item--active
|
||||||
@extend .folderList-item
|
@extend .folderList-item
|
||||||
color $ui-text-color
|
color #1EC38B
|
||||||
background-color $ui-button--active-backgroundColor
|
background-color alpha($ui-button-default--active-backgroundColor, 20%)
|
||||||
&:hover
|
&:hover
|
||||||
color $ui-text-color
|
color #1EC38B;
|
||||||
background-color $ui-button--active-backgroundColor
|
background-color alpha($ui-button-default--active-backgroundColor, 50%)
|
||||||
|
|
||||||
.folderList-item-name
|
.folderList-item-name
|
||||||
display block
|
display block
|
||||||
flex 1
|
flex 1
|
||||||
padding 0 25px
|
padding 0 12px
|
||||||
height 26px
|
height 26px
|
||||||
line-height 26px
|
line-height 26px
|
||||||
border-width 0 0 0 2px
|
border-width 0 0 0 2px
|
||||||
@@ -48,7 +47,7 @@
|
|||||||
float right
|
float right
|
||||||
line-height 26px
|
line-height 26px
|
||||||
padding-right 15px
|
padding-right 15px
|
||||||
font-size 12px
|
font-size 13px
|
||||||
|
|
||||||
.folderList-item-tooltip
|
.folderList-item-tooltip
|
||||||
tooltip()
|
tooltip()
|
||||||
@@ -69,8 +68,28 @@
|
|||||||
|
|
||||||
.folderList-item-name--folded
|
.folderList-item-name--folded
|
||||||
@extend .folderList-item-name
|
@extend .folderList-item-name
|
||||||
padding-left 12px
|
padding-left 17px
|
||||||
|
text
|
||||||
|
display none
|
||||||
|
|
||||||
|
body[data-theme="white"]
|
||||||
|
.folderList-item
|
||||||
|
color $ui-inactive-text-color
|
||||||
|
&:hover
|
||||||
|
color $ui-text-color
|
||||||
|
background-color alpha($ui-button--active-backgroundColor, 20%)
|
||||||
|
transition background-color 0.15s
|
||||||
|
&:active
|
||||||
|
color $ui-text-color
|
||||||
|
background-color $ui-button--active-backgroundColor
|
||||||
|
|
||||||
|
.folderList-item--active
|
||||||
|
@extend .folderList-item
|
||||||
|
color $ui-text-color
|
||||||
|
background-color $ui-button--active-backgroundColor
|
||||||
|
&:hover
|
||||||
|
color $ui-text-color
|
||||||
|
background-color alpha($ui-button--active-backgroundColor, 50%)
|
||||||
|
|
||||||
body[data-theme="dark"]
|
body[data-theme="dark"]
|
||||||
.folderList-item
|
.folderList-item
|
||||||
@@ -86,7 +105,7 @@ body[data-theme="dark"]
|
|||||||
color $ui-dark-text-color
|
color $ui-dark-text-color
|
||||||
background-color $ui-dark-button--active-backgroundColor
|
background-color $ui-dark-button--active-backgroundColor
|
||||||
&:active
|
&:active
|
||||||
background-color $ui-dark-button--active-backgroundColor
|
background-color alpha($ui-dark-button--active-backgroundColor, 50%)
|
||||||
&:hover
|
&:hover
|
||||||
color $ui-dark-text-color
|
color $ui-dark-text-color
|
||||||
background-color $ui-dark-button--active-backgroundColor
|
background-color alpha($ui-dark-button--active-backgroundColor, 50%)
|
||||||
23
browser/components/StorageList.js
Normal file
23
browser/components/StorageList.js
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
/**
|
||||||
|
* @fileoverview Micro component for showing StorageList
|
||||||
|
*/
|
||||||
|
import React, { PropTypes } from 'react'
|
||||||
|
import styles from './StorageList.styl'
|
||||||
|
import CSSModules from 'browser/lib/CSSModules'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {Array} storgaeList
|
||||||
|
*/
|
||||||
|
|
||||||
|
const StorageList = ({storageList}) => (
|
||||||
|
<div styleName='storageList'>
|
||||||
|
{storageList.length > 0 ? storageList : (
|
||||||
|
<div styleName='storgaeList-empty'>No storage mount.</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
|
||||||
|
StorageList.propTypes = {
|
||||||
|
storgaeList: PropTypes.arrayOf(PropTypes.element).isRequired
|
||||||
|
}
|
||||||
|
export default CSSModules(StorageList, styles)
|
||||||
20
browser/components/StorageList.styl
Normal file
20
browser/components/StorageList.styl
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
.storageList
|
||||||
|
absolute left right
|
||||||
|
bottom 37px
|
||||||
|
top 180px
|
||||||
|
overflow-y auto
|
||||||
|
|
||||||
|
.storageList-empty
|
||||||
|
padding 0 10px
|
||||||
|
margin-top 15px
|
||||||
|
line-height 24px
|
||||||
|
color $ui-inactive-text-color
|
||||||
|
|
||||||
|
body[data-theme="dark"]
|
||||||
|
.storageList-empty
|
||||||
|
color $ui-dark-inactive-text-color
|
||||||
|
|
||||||
|
.root-folded
|
||||||
|
.storageList-empty
|
||||||
|
white-space nowrap
|
||||||
|
transform rotate(90deg)
|
||||||
27
browser/components/TagListItem.js
Normal file
27
browser/components/TagListItem.js
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
/**
|
||||||
|
* @fileoverview Micro component for showing TagList.
|
||||||
|
*/
|
||||||
|
import React, { PropTypes } from 'react'
|
||||||
|
import styles from './TagListItem.styl'
|
||||||
|
import CSSModules from 'browser/lib/CSSModules'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {string} name
|
||||||
|
* @param {Function} handleClickTagListItem
|
||||||
|
* @param {bool} isActive
|
||||||
|
*/
|
||||||
|
|
||||||
|
const TagListItem = ({name, handleClickTagListItem, isActive}) => (
|
||||||
|
<button styleName={isActive ? 'tagList-item-active' : 'tagList-item'} onClick={() => handleClickTagListItem(name)}>
|
||||||
|
<span styleName='tagList-item-name'>
|
||||||
|
{`# ${name}`}
|
||||||
|
</span>
|
||||||
|
</button>
|
||||||
|
)
|
||||||
|
|
||||||
|
TagListItem.propTypes = {
|
||||||
|
name: PropTypes.string.isRequired,
|
||||||
|
handleClickTagListItem: PropTypes.func.isRequired
|
||||||
|
}
|
||||||
|
|
||||||
|
export default CSSModules(TagListItem, styles)
|
||||||
84
browser/components/TagListItem.styl
Normal file
84
browser/components/TagListItem.styl
Normal file
@@ -0,0 +1,84 @@
|
|||||||
|
.tagList-item
|
||||||
|
display flex
|
||||||
|
width 100%
|
||||||
|
height 26px
|
||||||
|
background-color transparent
|
||||||
|
color $ui-inactive-text-color
|
||||||
|
padding 0
|
||||||
|
margin-bottom 5px
|
||||||
|
text-align left
|
||||||
|
border none
|
||||||
|
overflow ellipsis
|
||||||
|
font-size 13px
|
||||||
|
&:first-child
|
||||||
|
margin-top 0
|
||||||
|
&:hover
|
||||||
|
color $ui-button-default-color
|
||||||
|
background-color alpha($ui-button-default--active-backgroundColor, 20%)
|
||||||
|
transition background-color 0.15s
|
||||||
|
&:active, &:active:hover
|
||||||
|
color $ui-button-default-color
|
||||||
|
background-color $ui-button-default--active-backgroundColor
|
||||||
|
|
||||||
|
.tagList-item-active
|
||||||
|
background-color $ui-button-default--active-backgroundColor
|
||||||
|
display flex
|
||||||
|
width 100%
|
||||||
|
height 26px
|
||||||
|
padding 0
|
||||||
|
margin-bottom 5px
|
||||||
|
text-align left
|
||||||
|
border none
|
||||||
|
overflow ellipsis
|
||||||
|
font-size 13px
|
||||||
|
color $ui-button-default-color
|
||||||
|
&:hover
|
||||||
|
background-color alpha($ui-button-default--active-backgroundColor, 60%)
|
||||||
|
transition 0.2s
|
||||||
|
|
||||||
|
.tagList-item-name
|
||||||
|
display block
|
||||||
|
flex 1
|
||||||
|
padding 0 15px
|
||||||
|
height 26px
|
||||||
|
line-height 26px
|
||||||
|
border-width 0 0 0 2px
|
||||||
|
border-style solid
|
||||||
|
border-color transparent
|
||||||
|
overflow hidden
|
||||||
|
text-overflow ellipsis
|
||||||
|
|
||||||
|
body[data-theme="white"]
|
||||||
|
.tagList-item
|
||||||
|
color $ui-inactive-text-color
|
||||||
|
&:hover
|
||||||
|
color $ui-text-color
|
||||||
|
background-color alpha($ui-button--active-backgroundColor, 20%)
|
||||||
|
&:active
|
||||||
|
color $ui-text-color
|
||||||
|
background-color $ui-button--active-backgroundColor
|
||||||
|
|
||||||
|
.tagList-item-active
|
||||||
|
background-color $ui-button--active-backgroundColor
|
||||||
|
color $ui-text-color
|
||||||
|
&:hover
|
||||||
|
background-color alpha($ui-button--active-backgroundColor, 60%)
|
||||||
|
|
||||||
|
body[data-theme="dark"]
|
||||||
|
.tagList-item
|
||||||
|
color $ui-dark-inactive-text-color
|
||||||
|
&:hover
|
||||||
|
color $ui-dark-text-color
|
||||||
|
background-color alpha($ui-dark-button--active-backgroundColor, 20%)
|
||||||
|
&:active
|
||||||
|
color $ui-dark-text-color
|
||||||
|
background-color $ui-dark-button--active-backgroundColor
|
||||||
|
|
||||||
|
.tagList-item-active
|
||||||
|
background-color $ui-dark-button--active-backgroundColor
|
||||||
|
color $ui-dark-text-color
|
||||||
|
&:active
|
||||||
|
background-color alpha($ui-dark-button--active-backgroundColor, 50%)
|
||||||
|
&:hover
|
||||||
|
color $ui-dark-text-color
|
||||||
|
background-color alpha($ui-dark-button--active-backgroundColor, 50%)
|
||||||
@@ -1,24 +1,25 @@
|
|||||||
.percentageBar
|
.percentageBar
|
||||||
position absolute
|
position absolute
|
||||||
top 58px
|
top 50px
|
||||||
right: 0px
|
right 0px
|
||||||
left 0px
|
left 0px
|
||||||
background-color #DADFE1
|
background-color #DADFE1
|
||||||
width 100%
|
width 100%
|
||||||
height: 15px
|
height: 17px
|
||||||
font-size: 12px
|
font-size: 12px
|
||||||
z-index 100
|
z-index 100
|
||||||
border-radius 2px
|
border-radius 2px
|
||||||
|
|
||||||
.progressBar
|
.progressBar
|
||||||
background-color: #6C7A89
|
background-color: #1EC38B
|
||||||
height 15px
|
height 17px
|
||||||
border-radius 2px
|
border-radius 2px
|
||||||
transition 0.3s
|
transition 0.4s cubic-bezier(0.4, 0.4, 0, 1)
|
||||||
|
|
||||||
.percentageText
|
.percentageText
|
||||||
color #f4f4f4
|
color #f4f4f4
|
||||||
padding: 2px 43%
|
padding: 2px 43%
|
||||||
|
font-weight 600
|
||||||
|
|
||||||
body[data-theme="dark"]
|
body[data-theme="dark"]
|
||||||
.percentageBar
|
.percentageBar
|
||||||
|
|||||||
@@ -118,7 +118,7 @@ hr
|
|||||||
h1, h2, h3, h4, h5, h6
|
h1, h2, h3, h4, h5, h6
|
||||||
font-weight bold
|
font-weight bold
|
||||||
h1
|
h1
|
||||||
font-size 2.25em
|
font-size 2.55em
|
||||||
padding-bottom 0.3em
|
padding-bottom 0.3em
|
||||||
line-height 1.2em
|
line-height 1.2em
|
||||||
border-bottom solid 1px borderColor
|
border-bottom solid 1px borderColor
|
||||||
@@ -193,6 +193,7 @@ ol
|
|||||||
&>li>ul, &>li>ol
|
&>li>ul, &>li>ol
|
||||||
margin 0
|
margin 0
|
||||||
code
|
code
|
||||||
|
color #CC305F
|
||||||
padding 0.2em 0.4em
|
padding 0.2em 0.4em
|
||||||
background-color #f7f7f7
|
background-color #f7f7f7
|
||||||
border-radius 3px
|
border-radius 3px
|
||||||
@@ -268,6 +269,16 @@ table
|
|||||||
border-color borderColor
|
border-color borderColor
|
||||||
&:last-child
|
&:last-child
|
||||||
border-right solid 1px borderColor
|
border-right solid 1px borderColor
|
||||||
|
kbd
|
||||||
|
background-color #fafbfc
|
||||||
|
border solid 1px borderColor
|
||||||
|
border-bottom-color btnColor
|
||||||
|
border-radius 3px
|
||||||
|
box-shadow inset 0 -1px 0 #959da5
|
||||||
|
display inline-block
|
||||||
|
font-size .8em
|
||||||
|
line-height 1
|
||||||
|
padding 3px 5px
|
||||||
|
|
||||||
themeDarkBackground = darken(#21252B, 10%)
|
themeDarkBackground = darken(#21252B, 10%)
|
||||||
themeDarkText = #f9f9f9
|
themeDarkText = #f9f9f9
|
||||||
@@ -316,3 +327,6 @@ body[data-theme="dark"]
|
|||||||
border-color themeDarkTableBorder
|
border-color themeDarkTableBorder
|
||||||
&:last-child
|
&:last-child
|
||||||
border-right solid 1px themeDarkTableBorder
|
border-right solid 1px themeDarkTableBorder
|
||||||
|
kbd
|
||||||
|
background-color themeDarkBorder
|
||||||
|
color themeDarkText
|
||||||
@@ -64,7 +64,7 @@ $list-width = 250px
|
|||||||
|
|
||||||
.result-nav-storageList
|
.result-nav-storageList
|
||||||
absolute bottom left right
|
absolute bottom left right
|
||||||
top 110px + 32px + 10px + 10px
|
top 110px + 32px + 10px + 10px + 20px
|
||||||
overflow-y auto
|
overflow-y auto
|
||||||
|
|
||||||
.result-list
|
.result-list
|
||||||
|
|||||||
@@ -196,6 +196,7 @@ class NoteDetail extends React.Component {
|
|||||||
lineNumber={config.preview.lineNumber}
|
lineNumber={config.preview.lineNumber}
|
||||||
indentSize={editorIndentSize}
|
indentSize={editorIndentSize}
|
||||||
value={note.content}
|
value={note.content}
|
||||||
|
showCopyNotification={config.ui.showCopyNotification}
|
||||||
storagePath={storage.path}
|
storagePath={storage.path}
|
||||||
/>
|
/>
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -84,6 +84,8 @@ nodeIpc.connectTo(
|
|||||||
const { config } = payload
|
const { config } = payload
|
||||||
if (config.ui.theme === 'dark') {
|
if (config.ui.theme === 'dark') {
|
||||||
document.body.setAttribute('data-theme', 'dark')
|
document.body.setAttribute('data-theme', 'dark')
|
||||||
|
} else if (config.ui.theme === 'white') {
|
||||||
|
document.body.setAttribute('data-theme', 'white')
|
||||||
} else {
|
} else {
|
||||||
document.body.setAttribute('data-theme', 'default')
|
document.body.setAttribute('data-theme', 'default')
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ const themes = fs.readdirSync(themePath)
|
|||||||
.map((themePath) => {
|
.map((themePath) => {
|
||||||
return themePath.substring(0, themePath.lastIndexOf('.'))
|
return themePath.substring(0, themePath.lastIndexOf('.'))
|
||||||
})
|
})
|
||||||
|
themes.splice(themes.indexOf('solarized'), 1, 'solarized dark', 'solarized light')
|
||||||
|
|
||||||
const consts = {
|
const consts = {
|
||||||
FOLDER_COLORS: [
|
FOLDER_COLORS: [
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import emoji from 'markdown-it-emoji'
|
|||||||
import math from '@rokt33r/markdown-it-math'
|
import math from '@rokt33r/markdown-it-math'
|
||||||
import _ from 'lodash'
|
import _ from 'lodash'
|
||||||
|
|
||||||
|
// FIXME We should not depend on global variable.
|
||||||
const katex = window.katex
|
const katex = window.katex
|
||||||
|
|
||||||
function createGutter (str) {
|
function createGutter (str) {
|
||||||
@@ -68,6 +69,9 @@ md.use(require('markdown-it-named-headers'), {
|
|||||||
.replace(/\-+$/, '')
|
.replace(/\-+$/, '')
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
md.use(require('markdown-it-kbd'))
|
||||||
|
md.use(require('markdown-it-plantuml'))
|
||||||
|
|
||||||
// Override task item
|
// Override task item
|
||||||
md.block.ruler.at('paragraph', function (state, startLine/*, endLine */) {
|
md.block.ruler.at('paragraph', function (state, startLine/*, endLine */) {
|
||||||
let content, terminate, i, l, token
|
let content, terminate, i, l, token
|
||||||
@@ -134,37 +138,9 @@ md.renderer.render = function render (tokens, options, env) {
|
|||||||
let result = originalRender.call(md.renderer, tokens, options, env)
|
let result = originalRender.call(md.renderer, tokens, options, env)
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
// FIXME We should not depend on global variable.
|
||||||
window.md = md
|
window.md = md
|
||||||
|
|
||||||
function strip (input) {
|
|
||||||
var output = input
|
|
||||||
try {
|
|
||||||
output = output
|
|
||||||
.replace(/^([\s\t]*)([\*\-\+]|\d\.)\s+/gm, '$1')
|
|
||||||
.replace(/\n={2,}/g, '\n')
|
|
||||||
.replace(/~~/g, '')
|
|
||||||
.replace(/`{3}.*\n/g, '')
|
|
||||||
.replace(/<(.*?)>/g, '$1')
|
|
||||||
.replace(/^[=\-]{2,}\s*$/g, '')
|
|
||||||
.replace(/\[\^.+?\](: .*?$)?/g, '')
|
|
||||||
.replace(/\s{0,2}\[.*?\]: .*?$/g, '')
|
|
||||||
.replace(/!\[.*?\][\[\(].*?[\]\)]/g, '')
|
|
||||||
.replace(/\[(.*?)\][\[\(].*?[\]\)]/g, '$1')
|
|
||||||
.replace(/>/g, '')
|
|
||||||
.replace(/^\s{1,2}\[(.*?)\]: (\S+)( ".*?")?\s*$/g, '')
|
|
||||||
.replace(/^#{1,6}\s*([^#]*)\s*(#{1,6})?/gm, '$1')
|
|
||||||
.replace(/([\*_]{1,3})(\S.*?\S)\1/g, '$2')
|
|
||||||
.replace(/(`{3,})(.*?)\1/gm, '$2')
|
|
||||||
.replace(/^-{3,}\s*$/g, '')
|
|
||||||
.replace(/`(.+?)`/g, '$1')
|
|
||||||
.replace(/\n{2,}/g, '\n\n')
|
|
||||||
} catch (e) {
|
|
||||||
console.error(e)
|
|
||||||
return input
|
|
||||||
}
|
|
||||||
return output
|
|
||||||
}
|
|
||||||
|
|
||||||
function normalizeLinkText (linkText) {
|
function normalizeLinkText (linkText) {
|
||||||
return md.normalizeLinkText(linkText)
|
return md.normalizeLinkText(linkText)
|
||||||
}
|
}
|
||||||
@@ -175,7 +151,7 @@ const markdown = {
|
|||||||
const renderedContent = md.render(content)
|
const renderedContent = md.render(content)
|
||||||
return renderedContent
|
return renderedContent
|
||||||
},
|
},
|
||||||
strip,
|
|
||||||
normalizeLinkText
|
normalizeLinkText
|
||||||
}
|
}
|
||||||
|
|
||||||
export default markdown
|
export default markdown
|
||||||
|
|||||||
39
browser/lib/markdownTextHelper.js
Normal file
39
browser/lib/markdownTextHelper.js
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
/**
|
||||||
|
* @fileoverview Text trimmer for markdown note.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {string} input
|
||||||
|
* @return {string}
|
||||||
|
*/
|
||||||
|
export function strip (input) {
|
||||||
|
let output = input
|
||||||
|
try {
|
||||||
|
output = output
|
||||||
|
.replace(/^([\s\t]*)([\*\-\+]|\d+\.)\s+/gm, '$1')
|
||||||
|
.replace(/\n={2,}/g, '\n')
|
||||||
|
.replace(/~~/g, '')
|
||||||
|
.replace(/`{3}.*\n/g, '')
|
||||||
|
.replace(/<(.*?)>/g, '$1')
|
||||||
|
.replace(/^[=\-]{2,}\s*$/g, '')
|
||||||
|
.replace(/\[\^.+?\](: .*?$)?/g, '')
|
||||||
|
.replace(/\s{0,2}\[.*?\]: .*?$/g, '')
|
||||||
|
.replace(/!\[.*?\][\[\(].*?[\]\)]/g, '')
|
||||||
|
.replace(/\[(.*?)\][\[\(].*?[\]\)]/g, '$1')
|
||||||
|
.replace(/>/g, '')
|
||||||
|
.replace(/^\s{1,2}\[(.*?)\]: (\S+)( ".*?")?\s*$/g, '')
|
||||||
|
.replace(/^#{1,6}\s*([^#]*)\s*(#{1,6})?/gm, '$1')
|
||||||
|
.replace(/(`{3,})(.*?)\1/gm, '$2')
|
||||||
|
.replace(/^-{3,}\s*$/g, '')
|
||||||
|
.replace(/`(.+?)`/g, '$1')
|
||||||
|
.replace(/\n{2,}/g, '\n\n')
|
||||||
|
} catch (e) {
|
||||||
|
console.error(e)
|
||||||
|
return input
|
||||||
|
}
|
||||||
|
return output
|
||||||
|
}
|
||||||
|
|
||||||
|
export default {
|
||||||
|
strip
|
||||||
|
}
|
||||||
@@ -2,15 +2,16 @@ import _ from 'lodash'
|
|||||||
|
|
||||||
export default function searchFromNotes (notes, search) {
|
export default function searchFromNotes (notes, search) {
|
||||||
if (search.trim().length === 0) return []
|
if (search.trim().length === 0) return []
|
||||||
let searchBlocks = search.split(' ')
|
const searchBlocks = search.split(' ').filter(block => { return block !== '' })
|
||||||
|
|
||||||
|
let foundNotes = findByWord(notes, searchBlocks[0])
|
||||||
searchBlocks.forEach((block) => {
|
searchBlocks.forEach((block) => {
|
||||||
|
foundNotes = findByWord(foundNotes, block)
|
||||||
if (block.match(/^#.+/)) {
|
if (block.match(/^#.+/)) {
|
||||||
notes = findByTag(notes, block)
|
foundNotes = foundNotes.concat(findByTag(notes, block))
|
||||||
} else {
|
|
||||||
notes = findByWord(notes, block)
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
return notes
|
return foundNotes
|
||||||
}
|
}
|
||||||
|
|
||||||
function findByTag (notes, block) {
|
function findByTag (notes, block) {
|
||||||
|
|||||||
@@ -1,5 +1,8 @@
|
|||||||
.root
|
.root
|
||||||
absolute top bottom right
|
absolute top bottom right
|
||||||
|
display flex
|
||||||
|
align-items center
|
||||||
|
justify-content center
|
||||||
|
|
||||||
.empty
|
.empty
|
||||||
height 320px
|
height 320px
|
||||||
@@ -8,8 +11,9 @@
|
|||||||
|
|
||||||
.empty-message
|
.empty-message
|
||||||
width 100%
|
width 100%
|
||||||
font-size 42px
|
font-size 36px
|
||||||
line-height 72px
|
font-weight 600
|
||||||
|
line-height 56px
|
||||||
text-align center
|
text-align center
|
||||||
color $ui-inactive-text-color
|
color $ui-inactive-text-color
|
||||||
|
|
||||||
|
|||||||
@@ -3,7 +3,9 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
// Margin on the left side and the right side for NoteDetail component.
|
// Margin on the left side and the right side for NoteDetail component.
|
||||||
$note-detail-left-margin = 25px
|
$note-detail-left-margin = 100px
|
||||||
$note-detail-right-margin = 25px
|
$note-detail-right-margin = 120px
|
||||||
|
$snippet-note-detail-left-margin = 60px
|
||||||
|
$snippet-note-detail-right-margin = 80px
|
||||||
|
|
||||||
$note-detail-box-shadow = 2px 0 15px -8px #b1b1b1 inset
|
$note-detail-box-shadow = 2px 0 15px -8px #b1b1b1 inset
|
||||||
|
|||||||
@@ -259,12 +259,11 @@ class FolderSelect extends React.Component {
|
|||||||
{optionList}
|
{optionList}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
: <div styleName='idle'>
|
: <div styleName='idle' style={{color: currentOption.folder.color}}>
|
||||||
<div styleName='idle-label'>
|
<div styleName='idle-label'>
|
||||||
<span styleName='idle-label-name'
|
<i className='fa fa-folder' />
|
||||||
style={{color: currentOption.folder.color}}
|
<span styleName='idle-label-name'>
|
||||||
>
|
{currentOption.folder.name}
|
||||||
{currentOption.folder.name} /
|
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,21 +1,22 @@
|
|||||||
.root
|
.root
|
||||||
position relative
|
position relative
|
||||||
border solid 1px transparent
|
border solid 1px transparent
|
||||||
line-height 26px
|
|
||||||
vertical-align middle
|
vertical-align middle
|
||||||
border-radius 2px
|
border-radius 2px
|
||||||
transition 0.15s
|
transition 0.15s
|
||||||
user-select none
|
user-select none
|
||||||
|
margin-right 10px
|
||||||
&:hover
|
&:hover
|
||||||
background-color $ui-button--hover-backgroundColor
|
background-color $ui-button--hover-backgroundColor
|
||||||
|
|
||||||
.root--search, .root--focus
|
.root--search, .root--focus
|
||||||
@extend .root
|
@extend .root
|
||||||
background-color $ui-noteDetail-backgroundColor = #F4F4F4
|
background-color $ui-noteDetail-backgroundColor = #fff
|
||||||
border-color $ui-input--focus-borderColor
|
border-color $ui-input--focus-borderColor
|
||||||
width 100px
|
width 154px
|
||||||
|
height 30px
|
||||||
&:hover
|
&:hover
|
||||||
border-color $ui-input--focus-borderColor
|
border-color $ui-input--focus-borderColor = #fff
|
||||||
|
|
||||||
.idle
|
.idle
|
||||||
position relative
|
position relative
|
||||||
@@ -24,13 +25,16 @@
|
|||||||
.idle-label
|
.idle-label
|
||||||
right 20px
|
right 20px
|
||||||
overflow ellipsis
|
overflow ellipsis
|
||||||
|
display flex
|
||||||
|
align-items center
|
||||||
|
|
||||||
.idle-label-name
|
.idle-label-name
|
||||||
font-size 14px
|
font-size 13px
|
||||||
padding 2px
|
font-weight 600
|
||||||
|
margin-left 4px
|
||||||
|
|
||||||
.idle-label-name-surfix
|
.idle-label-name-surfix
|
||||||
font-size 10px
|
font-size 15px
|
||||||
color $ui-inactive-text-color
|
color $ui-inactive-text-color
|
||||||
margin-left 5px
|
margin-left 5px
|
||||||
.idle-caret
|
.idle-caret
|
||||||
@@ -39,35 +43,37 @@
|
|||||||
width 20px
|
width 20px
|
||||||
line-height 34px
|
line-height 34px
|
||||||
|
|
||||||
.search
|
|
||||||
absolute top left right bottom
|
|
||||||
line-height 34px
|
|
||||||
|
|
||||||
.search-input
|
.search-input
|
||||||
vertical-align middle
|
vertical-align middle
|
||||||
position relative
|
position relative
|
||||||
top -2px
|
top 0
|
||||||
|
font-size 14px
|
||||||
outline none
|
outline none
|
||||||
border none
|
border none
|
||||||
height 20px
|
width 100%
|
||||||
line-height 20px
|
|
||||||
background-color transparent
|
background-color transparent
|
||||||
padding 0 10px
|
padding 0 10px
|
||||||
|
|
||||||
.search-optionList
|
.search-optionList
|
||||||
position fixed
|
position absolute
|
||||||
|
top 30px
|
||||||
max-height 450px
|
max-height 450px
|
||||||
|
min-width 150px
|
||||||
overflow auto
|
overflow auto
|
||||||
z-index 200
|
z-index 200
|
||||||
border $ui-border
|
border $ui-border
|
||||||
background-color white
|
background-color white
|
||||||
border-radius 2px
|
border-radius 2px
|
||||||
|
padding 10px 6px
|
||||||
|
|
||||||
.search-optionList-item
|
.search-optionList-item
|
||||||
|
width 140px
|
||||||
height 34px
|
height 34px
|
||||||
width 250px
|
display flex
|
||||||
|
align-items center
|
||||||
box-sizing border-box
|
box-sizing border-box
|
||||||
padding 0 5px
|
padding 0
|
||||||
|
margin-bottom 10px
|
||||||
overflow ellipsis
|
overflow ellipsis
|
||||||
cursor pointer
|
cursor pointer
|
||||||
&:hover
|
&:hover
|
||||||
@@ -81,13 +87,17 @@
|
|||||||
background-color $ui-button--active-backgroundColor
|
background-color $ui-button--active-backgroundColor
|
||||||
color $ui-button--active-color
|
color $ui-button--active-color
|
||||||
.search-optionList-item-name
|
.search-optionList-item-name
|
||||||
border-left solid 2px transparent
|
border-left solid 3px transparent
|
||||||
padding 2px 5px
|
padding 6px
|
||||||
.search-optionList-item-name-surfix
|
.search-optionList-item-name-surfix
|
||||||
font-size 10px
|
font-size 10px
|
||||||
color $ui-inactive-text-color
|
color $ui-inactive-text-color
|
||||||
margin-left 5px
|
margin-left 5px
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
body[data-theme="dark"]
|
body[data-theme="dark"]
|
||||||
.root
|
.root
|
||||||
color $ui-dark-text-color
|
color $ui-dark-text-color
|
||||||
|
|||||||
@@ -6,9 +6,9 @@ const InfoButton = ({
|
|||||||
onClick
|
onClick
|
||||||
}) => (
|
}) => (
|
||||||
<button styleName='control-infoButton'
|
<button styleName='control-infoButton'
|
||||||
onClick={onClick}
|
onClick={(e) => onClick(e)}
|
||||||
>
|
>
|
||||||
<i className='fa fa-info infoButton' styleName='info-button' />
|
<img className='infoButton' src='../resources/icon/icon-info.svg' />
|
||||||
</button>
|
</button>
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -1,20 +1,10 @@
|
|||||||
.control-infoButton
|
.control-infoButton
|
||||||
float right
|
top 10px
|
||||||
|
margin-bottom 10px
|
||||||
topBarButtonLight()
|
topBarButtonLight()
|
||||||
|
|
||||||
.control-infoPanel
|
|
||||||
position fixed
|
|
||||||
pointer-events none
|
|
||||||
top 50px
|
|
||||||
z-index 200
|
|
||||||
line-height normal
|
|
||||||
border-radius 2px
|
|
||||||
opacity 0
|
|
||||||
transition 0.1s
|
|
||||||
|
|
||||||
.infoButton
|
.infoButton
|
||||||
padding 0px
|
padding 0px
|
||||||
margin 15px 0
|
|
||||||
|
|
||||||
body[data-theme="dark"]
|
body[data-theme="dark"]
|
||||||
.control-infoButton
|
.control-infoButton
|
||||||
|
|||||||
@@ -3,71 +3,57 @@ import CSSModules from 'browser/lib/CSSModules'
|
|||||||
import styles from './InfoPanel.styl'
|
import styles from './InfoPanel.styl'
|
||||||
|
|
||||||
const InfoPanel = ({
|
const InfoPanel = ({
|
||||||
storageName, folderName, noteLink, updatedAt, createdAt, exportAsMd, exportAsTxt, wordCount, letterCount, type
|
storageName, folderName, noteLink, updatedAt, createdAt, exportAsMd, exportAsTxt, wordCount, letterCount, type, print
|
||||||
}) => (
|
}) => (
|
||||||
<div className='infoPanel' styleName='control-infoButton-panel' style={{display: 'none'}}>
|
<div className='infoPanel' styleName='control-infoButton-panel' style={{display: 'none'}}>
|
||||||
<div styleName='group-section'>
|
<div>
|
||||||
<div styleName='group-section-label'>
|
<p styleName='modification-date'>{updatedAt}</p>
|
||||||
Storage
|
<p styleName='modification-date-desc'>MODIFICATION DATE</p>
|
||||||
</div>
|
|
||||||
<div styleName='group-section-control'>
|
|
||||||
{storageName}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div styleName='group-section'>
|
|
||||||
<div styleName='group-section-label'>
|
|
||||||
Folder
|
|
||||||
</div>
|
|
||||||
<div styleName='group-section-control'>
|
|
||||||
{folderName}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div styleName='group-section'>
|
|
||||||
<div styleName='group-section-label'>
|
|
||||||
Created
|
|
||||||
</div>
|
|
||||||
<div styleName='group-section-control'>
|
|
||||||
{createdAt}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div styleName='group-section'>
|
|
||||||
<div styleName='group-section-label'>
|
|
||||||
Updated
|
|
||||||
</div>
|
|
||||||
<div styleName='group-section-control'>
|
|
||||||
{updatedAt}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div styleName='group-section'>
|
|
||||||
<div styleName='group-section-label'>
|
|
||||||
Note Link
|
|
||||||
</div>
|
|
||||||
<div styleName='group-section-control'>
|
|
||||||
<input value={noteLink} onClick={(e) => { e.target.select() }} />
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<hr />
|
||||||
|
|
||||||
{type === 'SNIPPET_NOTE'
|
{type === 'SNIPPET_NOTE'
|
||||||
? ''
|
? ''
|
||||||
: <div>
|
: <div styleName='count-wrap'>
|
||||||
<div styleName='group-section'>
|
<div styleName='count-number'>
|
||||||
<div styleName='group-section-label'>
|
<p styleName='infoPanel-defaul-count'>{wordCount}</p>
|
||||||
Words
|
<p styleName='infoPanel-sub-count'>Words</p>
|
||||||
</div>
|
|
||||||
<div styleName='group-section-control'>
|
|
||||||
{wordCount}
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
<div styleName='group-section'>
|
<div styleName='count-number'>
|
||||||
<div styleName='group-section-label'>
|
<p styleName='infoPanel-defaul-count'>{letterCount}</p>
|
||||||
Letters
|
<p styleName='infoPanel-sub-count'>Letters</p>
|
||||||
</div>
|
|
||||||
<div styleName='group-section-control'>
|
|
||||||
{letterCount}
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
{type === 'SNIPPET_NOTE'
|
||||||
|
? ''
|
||||||
|
: <hr />
|
||||||
|
}
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<p styleName='infoPanel-default'>{storageName}</p>
|
||||||
|
<p styleName='infoPanel-sub'>STORAGE</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<p styleName='infoPanel-default'>{folderName}</p>
|
||||||
|
<p styleName='infoPanel-sub'>FOLDER</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<p styleName='infoPanel-default'>{createdAt}</p>
|
||||||
|
<p styleName='infoPanel-sub'>CREATION DATE</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<input styleName='infoPanel-noteLink' value={noteLink} onClick={(e) => { e.target.select() }} />
|
||||||
|
<p styleName='infoPanel-sub'>NOTE LINK</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<hr />
|
||||||
|
|
||||||
<div id='export-wrap'>
|
<div id='export-wrap'>
|
||||||
<button styleName='export--enable' onClick={(e) => exportAsMd(e)}>
|
<button styleName='export--enable' onClick={(e) => exportAsMd(e)}>
|
||||||
<i className='fa fa-file-code-o fa-fw' />
|
<i className='fa fa-file-code-o fa-fw' />
|
||||||
@@ -79,9 +65,9 @@ const InfoPanel = ({
|
|||||||
<p>.txt</p>
|
<p>.txt</p>
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
<button styleName='export--unable'>
|
<button styleName='export--enable' onClick={(e) => print(e)}>
|
||||||
<i className='fa fa-file-pdf-o fa-fw' />
|
<i className='fa fa-print fa-fw' />
|
||||||
<p>.pdf</p>
|
<p>Print</p>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -97,7 +83,8 @@ InfoPanel.propTypes = {
|
|||||||
exportAsTxt: PropTypes.func.isRequired,
|
exportAsTxt: PropTypes.func.isRequired,
|
||||||
wordCount: PropTypes.number,
|
wordCount: PropTypes.number,
|
||||||
letterCount: PropTypes.number,
|
letterCount: PropTypes.number,
|
||||||
type: PropTypes.string.isRequired
|
type: PropTypes.string.isRequired,
|
||||||
|
print: PropTypes.func.isRequired
|
||||||
}
|
}
|
||||||
|
|
||||||
export default CSSModules(InfoPanel, styles)
|
export default CSSModules(InfoPanel, styles)
|
||||||
|
|||||||
@@ -10,52 +10,81 @@
|
|||||||
|
|
||||||
.control-infoButton-panel
|
.control-infoButton-panel
|
||||||
z-index 200
|
z-index 200
|
||||||
margin-top 45px
|
margin-top 0px
|
||||||
margin-left -210px
|
right 0
|
||||||
position absolute
|
position absolute
|
||||||
padding 20px 20px 0 20px
|
padding 20px 25px 0 25px
|
||||||
width 340px
|
width 300px
|
||||||
|
height 350px
|
||||||
|
overflow auto
|
||||||
background-color $ui-noteList-backgroundColor
|
background-color $ui-noteList-backgroundColor
|
||||||
border 1px solid $border-color
|
box-shadow 2px 12px 15px 2px rgba(0, 0, 0, 0.1), 2px 1px 50px 2px rgba(0, 0, 0, 0.1)
|
||||||
|
border-radius 2px
|
||||||
|
|
||||||
|
.modification-date
|
||||||
|
font-size 18px
|
||||||
|
line-height 30px
|
||||||
|
color $ui-text-color
|
||||||
|
|
||||||
|
.modification-date-desc
|
||||||
|
font-size 18px
|
||||||
|
color $ui-inactive-text-color
|
||||||
|
|
||||||
.control-infoButton-panel-trash
|
.control-infoButton-panel-trash
|
||||||
z-index 200
|
z-index 200
|
||||||
margin-top 45px
|
margin-top 0px
|
||||||
margin-left -230px
|
right 0px
|
||||||
position absolute
|
position absolute
|
||||||
padding 20px 20px 0 20px
|
padding 20px 25px 0 25px
|
||||||
width 320px
|
width 300px
|
||||||
background-color $ui-noteList-backgroundColor
|
background-color $ui-noteList-backgroundColor
|
||||||
border 1px solid $border-color
|
box-shadow 2px 12px 15px 2px rgba(0, 0, 0, 0.1), 2px 1px 50px 2px rgba(0, 0, 0, 0.1)
|
||||||
|
border-radius 2px
|
||||||
|
|
||||||
.group-section
|
.count-wrap
|
||||||
display flex
|
display flex
|
||||||
|
position relative
|
||||||
|
width 100%
|
||||||
|
|
||||||
|
.count-number
|
||||||
|
position relative
|
||||||
|
display block
|
||||||
|
width 50%
|
||||||
|
overflow hidden
|
||||||
|
margin 0
|
||||||
|
padding 0
|
||||||
|
|
||||||
|
.infoPanel-defaul-count
|
||||||
|
font-size 16px
|
||||||
line-height 30px
|
line-height 30px
|
||||||
font-size 13px
|
|
||||||
|
|
||||||
.group-section-label
|
|
||||||
width 70px
|
|
||||||
height 20px
|
|
||||||
text-align left
|
|
||||||
margin-right 50px
|
|
||||||
font-size 13px
|
|
||||||
color $ui-inactive-text-color
|
|
||||||
|
|
||||||
.group-section-control
|
|
||||||
flex 1
|
|
||||||
font-size 13px
|
|
||||||
color $ui-text-color
|
color $ui-text-color
|
||||||
|
|
||||||
.group-section-control input
|
.infoPanel-sub-count
|
||||||
width 160px
|
font-size 16px
|
||||||
height 25px
|
color $ui-inactive-text-color
|
||||||
|
padding-bottom 8px
|
||||||
|
|
||||||
.group-section-control text
|
.infoPanel-default
|
||||||
|
font-size 14px
|
||||||
|
line-height 30px
|
||||||
|
color $ui-text-color
|
||||||
|
|
||||||
|
.infoPanel-sub
|
||||||
|
font-size 14px
|
||||||
|
color $ui-inactive-text-color
|
||||||
|
padding-bottom 8px
|
||||||
|
|
||||||
|
.infoPanel-noteLink
|
||||||
|
padding-right 5px
|
||||||
|
width 200px
|
||||||
|
height 25px
|
||||||
|
margin-bottom 6px
|
||||||
|
|
||||||
|
.infoPanel-trash
|
||||||
color #EA4447
|
color #EA4447
|
||||||
font-weight 600
|
font-weight 600
|
||||||
font-size 14px
|
font-size 14px
|
||||||
width 70px
|
width 70px
|
||||||
height 25px
|
|
||||||
background-color rgba(226,33,113,0.1)
|
background-color rgba(226,33,113,0.1)
|
||||||
border none
|
border none
|
||||||
outline none
|
outline none
|
||||||
@@ -96,20 +125,30 @@
|
|||||||
body[data-theme="dark"]
|
body[data-theme="dark"]
|
||||||
.control-infoButton-panel
|
.control-infoButton-panel
|
||||||
background-color $ui-dark-noteList-backgroundColor
|
background-color $ui-dark-noteList-backgroundColor
|
||||||
border 1px solid $ui-dark-borderColor
|
|
||||||
|
|
||||||
.control-infoButton-panel-trash
|
.control-infoButton-panel-trash
|
||||||
background-color $ui-dark-noteList-backgroundColor
|
background-color $ui-dark-noteList-backgroundColor
|
||||||
border 1px solid $ui-dark-borderColor
|
|
||||||
|
|
||||||
.group-section-label
|
.modification-date
|
||||||
color $ui-inactive-text-color
|
|
||||||
|
|
||||||
.group-section-control
|
|
||||||
color $ui-dark-text-color
|
color $ui-dark-text-color
|
||||||
|
|
||||||
.group-section-control input
|
.modification-date-desc
|
||||||
background-color alpha($ui-dark-borderColor, 80%)
|
color $ui-inactive-text-color
|
||||||
|
|
||||||
|
.infoPanel-defaul-count
|
||||||
|
color $ui-dark-text-color
|
||||||
|
|
||||||
|
.infoPanel-sub-count
|
||||||
|
color $ui-inactive-text-color
|
||||||
|
|
||||||
|
.infoPanel-default
|
||||||
|
color $ui-dark-text-color
|
||||||
|
|
||||||
|
.infoPanel-sub
|
||||||
|
color $ui-inactive-text-color
|
||||||
|
|
||||||
|
.infoPanel-noteLink
|
||||||
|
background-color alpha($ui-dark-borderColor, 60%)
|
||||||
color $ui-dark-text-color
|
color $ui-dark-text-color
|
||||||
|
|
||||||
[id=export-wrap]
|
[id=export-wrap]
|
||||||
|
|||||||
@@ -6,37 +6,26 @@ const InfoPanelTrashed = ({
|
|||||||
storageName, folderName, updatedAt, createdAt, exportAsMd, exportAsTxt
|
storageName, folderName, updatedAt, createdAt, exportAsMd, exportAsTxt
|
||||||
}) => (
|
}) => (
|
||||||
<div className='infoPanel' styleName='control-infoButton-panel-trash' style={{display: 'none'}}>
|
<div className='infoPanel' styleName='control-infoButton-panel-trash' style={{display: 'none'}}>
|
||||||
<div styleName='group-section'>
|
<div>
|
||||||
<div styleName='group-section-label'>
|
<p styleName='modification-date'>{updatedAt}</p>
|
||||||
Storage
|
<p styleName='modification-date-desc'>MODIFICATION DATE</p>
|
||||||
</div>
|
|
||||||
<div styleName='group-section-control'>
|
|
||||||
{storageName}
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
<div styleName='group-section'>
|
|
||||||
<div styleName='group-section-label'>
|
<hr />
|
||||||
Folder
|
|
||||||
</div>
|
<div>
|
||||||
<div styleName='group-section-control'>
|
<p styleName='infoPanel-default'>{storageName}</p>
|
||||||
<text>Trash</text>{folderName}
|
<p styleName='infoPanel-sub'>STORAGE</p>
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
<div styleName='group-section'>
|
|
||||||
<div styleName='group-section-label'>
|
<div>
|
||||||
Created
|
<p styleName='infoPanel-default'><text styleName='infoPanel-trash'>Trash</text>{folderName}</p>
|
||||||
</div>
|
<p styleName='infoPanel-sub'>FOLDER</p>
|
||||||
<div styleName='group-section-control'>
|
|
||||||
{createdAt}
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
<div styleName='group-section'>
|
|
||||||
<div styleName='group-section-label'>
|
<div>
|
||||||
Updated
|
<p styleName='infoPanel-default'>{createdAt}</p>
|
||||||
</div>
|
<p styleName='infoPanel-sub'>CREATION DATE</p>
|
||||||
<div styleName='group-section-control'>
|
|
||||||
{updatedAt}
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div id='export-wrap'>
|
<div id='export-wrap'>
|
||||||
|
|||||||
@@ -9,12 +9,13 @@ import FolderSelect from './FolderSelect'
|
|||||||
import dataApi from 'browser/main/lib/dataApi'
|
import dataApi from 'browser/main/lib/dataApi'
|
||||||
import { hashHistory } from 'react-router'
|
import { hashHistory } from 'react-router'
|
||||||
import ee from 'browser/main/lib/eventEmitter'
|
import ee from 'browser/main/lib/eventEmitter'
|
||||||
import markdown from 'browser/lib/markdown'
|
import markdown from 'browser/lib/markdownTextHelper'
|
||||||
import StatusBar from '../StatusBar'
|
import StatusBar from '../StatusBar'
|
||||||
import _ from 'lodash'
|
import _ from 'lodash'
|
||||||
import { findNoteTitle } from 'browser/lib/findNoteTitle'
|
import { findNoteTitle } from 'browser/lib/findNoteTitle'
|
||||||
import AwsMobileAnalyticsConfig from 'browser/main/lib/AwsMobileAnalyticsConfig'
|
import AwsMobileAnalyticsConfig from 'browser/main/lib/AwsMobileAnalyticsConfig'
|
||||||
import TrashButton from './TrashButton'
|
import TrashButton from './TrashButton'
|
||||||
|
import PermanentDeleteButton from './PermanentDeleteButton'
|
||||||
import InfoButton from './InfoButton'
|
import InfoButton from './InfoButton'
|
||||||
import InfoPanel from './InfoPanel'
|
import InfoPanel from './InfoPanel'
|
||||||
import InfoPanelTrashed from './InfoPanelTrashed'
|
import InfoPanelTrashed from './InfoPanelTrashed'
|
||||||
@@ -231,7 +232,7 @@ class MarkdownNoteDetail extends React.Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
getToggleLockButton () {
|
getToggleLockButton () {
|
||||||
return this.state.isLocked ? 'fa-lock' : 'fa-unlock'
|
return this.state.isLocked ? '../resources/icon/icon-lock.svg' : '../resources/icon/icon-unlock.svg'
|
||||||
}
|
}
|
||||||
|
|
||||||
handleDeleteKeyDown (e) {
|
handleDeleteKeyDown (e) {
|
||||||
@@ -256,6 +257,10 @@ class MarkdownNoteDetail extends React.Component {
|
|||||||
if (infoPanel.style) infoPanel.style.display = infoPanel.style.display === 'none' ? 'inline' : 'none'
|
if (infoPanel.style) infoPanel.style.display = infoPanel.style.display === 'none' ? 'inline' : 'none'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
print (e) {
|
||||||
|
ee.emit('print')
|
||||||
|
}
|
||||||
|
|
||||||
render () {
|
render () {
|
||||||
let { data, config, location } = this.props
|
let { data, config, location } = this.props
|
||||||
let { note } = this.state
|
let { note } = this.state
|
||||||
@@ -281,7 +286,7 @@ class MarkdownNoteDetail extends React.Component {
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div styleName='info-right'>
|
<div styleName='info-right'>
|
||||||
<TrashButton onClick={(e) => this.handleTrashButtonClick(e)} />
|
<PermanentDeleteButton onClick={(e) => this.handleTrashButtonClick(e)} />
|
||||||
<InfoButton
|
<InfoButton
|
||||||
onClick={(e) => this.handleInfoButtonClick(e)}
|
onClick={(e) => this.handleInfoButtonClick(e)}
|
||||||
/>
|
/>
|
||||||
@@ -298,10 +303,6 @@ class MarkdownNoteDetail extends React.Component {
|
|||||||
|
|
||||||
const detailTopBar = <div styleName='info'>
|
const detailTopBar = <div styleName='info'>
|
||||||
<div styleName='info-left'>
|
<div styleName='info-left'>
|
||||||
<StarButton styleName='info-left-button'
|
|
||||||
onClick={(e) => this.handleStarButtonClick(e)}
|
|
||||||
isActive={note.isStarred}
|
|
||||||
/>
|
|
||||||
<div styleName='info-left-top'>
|
<div styleName='info-left-top'>
|
||||||
<FolderSelect styleName='info-left-top-folderSelect'
|
<FolderSelect styleName='info-left-top-folderSelect'
|
||||||
value={this.state.note.storage + '-' + this.state.note.folder}
|
value={this.state.note.storage + '-' + this.state.note.folder}
|
||||||
@@ -321,31 +322,38 @@ class MarkdownNoteDetail extends React.Component {
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div styleName='info-right'>
|
<div styleName='info-right'>
|
||||||
|
<InfoButton
|
||||||
|
onClick={(e) => this.handleInfoButtonClick(e)}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<StarButton
|
||||||
|
onClick={(e) => this.handleStarButtonClick(e)}
|
||||||
|
isActive={note.isStarred}
|
||||||
|
/>
|
||||||
|
|
||||||
{(() => {
|
{(() => {
|
||||||
const faClassName = `fa ${this.getToggleLockButton()}`
|
const imgSrc = `${this.getToggleLockButton()}`
|
||||||
const lockButtonComponent =
|
const lockButtonComponent =
|
||||||
<button styleName='control-lockButton'
|
<button styleName='control-lockButton'
|
||||||
onFocus={(e) => this.handleFocus(e)}
|
onFocus={(e) => this.handleFocus(e)}
|
||||||
onMouseDown={(e) => this.handleLockButtonMouseDown(e)}
|
onMouseDown={(e) => this.handleLockButtonMouseDown(e)}
|
||||||
>
|
>
|
||||||
<i className={faClassName} styleName='lock-button' />
|
<img styleName='iconInfo' src={imgSrc} />
|
||||||
<span styleName='control-lockButton-tooltip'>
|
|
||||||
{this.state.isLocked ? 'Unlock' : 'Lock'}
|
|
||||||
</span>
|
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
return (
|
return (
|
||||||
this.state.isLockButtonShown ? lockButtonComponent : ''
|
this.state.isLockButtonShown ? lockButtonComponent : ''
|
||||||
)
|
)
|
||||||
})()}
|
})()}
|
||||||
<TrashButton onClick={(e) => this.handleTrashButtonClick(e)} />
|
|
||||||
<button styleName='control-fullScreenButton'
|
<button styleName='control-fullScreenButton'
|
||||||
onMouseDown={(e) => this.handleFullScreenButton(e)}
|
onMouseDown={(e) => this.handleFullScreenButton(e)}
|
||||||
>
|
>
|
||||||
<i className='fa fa-window-maximize' styleName='fullScreen-button' />
|
<img styleName='iconInfo' src='../resources/icon/icon-sidebar.svg' />
|
||||||
</button>
|
</button>
|
||||||
<InfoButton
|
|
||||||
onClick={(e) => this.handleInfoButtonClick(e)}
|
<TrashButton onClick={(e) => this.handleTrashButtonClick(e)} />
|
||||||
/>
|
|
||||||
<InfoPanel
|
<InfoPanel
|
||||||
storageName={currentOption.storage.name}
|
storageName={currentOption.storage.name}
|
||||||
folderName={currentOption.folder.name}
|
folderName={currentOption.folder.name}
|
||||||
@@ -357,6 +365,7 @@ class MarkdownNoteDetail extends React.Component {
|
|||||||
wordCount={note.content.split(' ').length}
|
wordCount={note.content.split(' ').length}
|
||||||
letterCount={note.content.replace(/\r?\n/g, '').length}
|
letterCount={note.content.replace(/\r?\n/g, '').length}
|
||||||
type={note.type}
|
type={note.type}
|
||||||
|
print={this.print}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -3,50 +3,48 @@
|
|||||||
|
|
||||||
.root
|
.root
|
||||||
absolute top right bottom
|
absolute top right bottom
|
||||||
border-width 0 0 1px
|
border-left 1px solid alpha(#DEDEDE, 60%)
|
||||||
border-style solid
|
|
||||||
border-color $ui-borderColor
|
|
||||||
background-color $ui-noteDetail-backgroundColor
|
background-color $ui-noteDetail-backgroundColor
|
||||||
box-shadow $note-detail-box-shadow
|
box-shadow none
|
||||||
|
padding 20px 40px
|
||||||
|
|
||||||
.lock-button
|
.lock-button
|
||||||
padding-bottom 3px
|
padding-bottom 3px
|
||||||
|
|
||||||
.control-lockButton
|
.control-lockButton
|
||||||
|
top 160px
|
||||||
|
margin-bottom 10px
|
||||||
topBarButtonLight()
|
topBarButtonLight()
|
||||||
|
|
||||||
.control-lockButton-tooltip
|
.trashed-infopanel
|
||||||
tooltip()
|
top 40px
|
||||||
position fixed
|
position relative
|
||||||
pointer-events none
|
|
||||||
top 50px
|
|
||||||
z-index 200
|
|
||||||
padding 5px
|
|
||||||
line-height normal
|
|
||||||
border-radius 2px
|
|
||||||
opacity 0
|
|
||||||
transition 0.1s
|
|
||||||
|
|
||||||
.control-fullScreenButton
|
.control-fullScreenButton
|
||||||
float right
|
top 80px
|
||||||
padding 0 0 2px 0
|
|
||||||
topBarButtonLight()
|
topBarButtonLight()
|
||||||
|
|
||||||
.body
|
.body
|
||||||
absolute left right
|
absolute left right
|
||||||
left $note-detail-left-margin
|
left 0
|
||||||
right $note-detail-right-margin
|
right 0
|
||||||
top $info-height + $info-margin-under-border
|
top $info-height + $info-margin-under-border
|
||||||
bottom $statusBar-height
|
bottom $statusBar-height
|
||||||
|
max-width 600px
|
||||||
|
margin 0 auto
|
||||||
.body-noteEditor
|
.body-noteEditor
|
||||||
absolute top bottom left right
|
absolute top bottom left right
|
||||||
|
|
||||||
|
body[data-theme="white"]
|
||||||
|
.root
|
||||||
|
box-shadow $note-detail-box-shadow
|
||||||
|
border none
|
||||||
|
|
||||||
body[data-theme="dark"]
|
body[data-theme="dark"]
|
||||||
.root
|
.root
|
||||||
border-color $ui-dark-borderColor
|
|
||||||
background-color $ui-dark-noteDetail-backgroundColor
|
background-color $ui-dark-noteDetail-backgroundColor
|
||||||
box-shadow none
|
box-shadow none
|
||||||
|
border none
|
||||||
|
|
||||||
.control-lockButton
|
.control-lockButton
|
||||||
topBarButtonDark()
|
topBarButtonDark()
|
||||||
|
|||||||
@@ -1,33 +1,31 @@
|
|||||||
@import('DetailVars')
|
@import('DetailVars')
|
||||||
|
|
||||||
$info-height = 60px
|
$info-height = 50px
|
||||||
$info-margin-under-border = 27px
|
$info-margin-under-border = 30px
|
||||||
|
|
||||||
.info
|
.info
|
||||||
absolute top left right
|
absolute top left right
|
||||||
left $note-detail-left-margin
|
left 0
|
||||||
right $note-detail-right-margin
|
right 0
|
||||||
height $info-height
|
height $info-height
|
||||||
border-bottom $ui-border
|
border-bottom 1px solid #eee
|
||||||
background-color $ui-noteDetail-backgroundColor
|
background-color $ui-noteDetail-backgroundColor
|
||||||
|
width 100%
|
||||||
|
display flex
|
||||||
|
align-items center
|
||||||
|
|
||||||
.info-left
|
.info-left
|
||||||
float left
|
padding 0 10px
|
||||||
padding 0 5px
|
width 100%
|
||||||
margin 0px 2px
|
display flex
|
||||||
.info-left-top
|
align-items center
|
||||||
display inline-block
|
|
||||||
height $info-height
|
|
||||||
line-height $info-height
|
|
||||||
|
|
||||||
.info-left-top-folderSelect
|
.info-left-top-folderSelect
|
||||||
padding 0 3px
|
|
||||||
height 34px
|
|
||||||
line-height 26px
|
|
||||||
display flex
|
display flex
|
||||||
align-items center
|
align-items center
|
||||||
justify-content center
|
justify-content center
|
||||||
border-radius 3px
|
|
||||||
.info-left-button
|
.info-left-button
|
||||||
width 34px
|
width 34px
|
||||||
height 34px
|
height 34px
|
||||||
@@ -48,18 +46,18 @@ $info-margin-under-border = 27px
|
|||||||
|
|
||||||
.info-right
|
.info-right
|
||||||
position absolute
|
position absolute
|
||||||
right 0
|
right 40px
|
||||||
top 0
|
top 60px
|
||||||
background $ui-noteDetail-backgroundColor
|
|
||||||
bottom 1px
|
bottom 1px
|
||||||
padding-left 30px
|
padding-left 30px
|
||||||
|
z-index 101
|
||||||
|
|
||||||
.undo-button
|
.undo-button
|
||||||
width 34px
|
width 34px
|
||||||
height 34px
|
height 34px
|
||||||
border-radius 17px
|
border-radius 17px
|
||||||
font-size 14px
|
font-size 14px
|
||||||
margin 15px 7px
|
margin 5px 0px
|
||||||
border none
|
border none
|
||||||
color $ui-button-color
|
color $ui-button-color
|
||||||
display flex
|
display flex
|
||||||
@@ -72,6 +70,7 @@ $info-margin-under-border = 27px
|
|||||||
border-color $ui-button--active-backgroundColor
|
border-color $ui-button--active-backgroundColor
|
||||||
&:hover
|
&:hover
|
||||||
background-color alpha($ui-button--hover-backgroundColor, 60%)
|
background-color alpha($ui-button--hover-backgroundColor, 60%)
|
||||||
|
transition 0.2s
|
||||||
.control-lockButton-tooltip
|
.control-lockButton-tooltip
|
||||||
opacity 1
|
opacity 1
|
||||||
|
|
||||||
|
|||||||
19
browser/main/Detail/PermanentDeleteButton.js
Normal file
19
browser/main/Detail/PermanentDeleteButton.js
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
import React, { PropTypes } from 'react'
|
||||||
|
import CSSModules from 'browser/lib/CSSModules'
|
||||||
|
import styles from './TrashButton.styl'
|
||||||
|
|
||||||
|
const PermanentDeleteButton = ({
|
||||||
|
onClick
|
||||||
|
}) => (
|
||||||
|
<button styleName='control-trashButton--in-trash'
|
||||||
|
onClick={(e) => onClick(e)}
|
||||||
|
>
|
||||||
|
<img styleName='iconInfo' src='../resources/icon/icon-trash.svg' />
|
||||||
|
</button>
|
||||||
|
)
|
||||||
|
|
||||||
|
PermanentDeleteButton.propTypes = {
|
||||||
|
onClick: PropTypes.func.isRequired
|
||||||
|
}
|
||||||
|
|
||||||
|
export default CSSModules(PermanentDeleteButton, styles)
|
||||||
@@ -18,6 +18,7 @@ import _ from 'lodash'
|
|||||||
import { findNoteTitle } from 'browser/lib/findNoteTitle'
|
import { findNoteTitle } from 'browser/lib/findNoteTitle'
|
||||||
import AwsMobileAnalyticsConfig from 'browser/main/lib/AwsMobileAnalyticsConfig'
|
import AwsMobileAnalyticsConfig from 'browser/main/lib/AwsMobileAnalyticsConfig'
|
||||||
import TrashButton from './TrashButton'
|
import TrashButton from './TrashButton'
|
||||||
|
import PermanentDeleteButton from './PermanentDeleteButton'
|
||||||
import InfoButton from './InfoButton'
|
import InfoButton from './InfoButton'
|
||||||
import InfoPanel from './InfoPanel'
|
import InfoPanel from './InfoPanel'
|
||||||
import InfoPanelTrashed from './InfoPanelTrashed'
|
import InfoPanelTrashed from './InfoPanelTrashed'
|
||||||
@@ -266,11 +267,16 @@ class SnippetNoteDetail extends React.Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
renameSnippetByIndex (index, name) {
|
renameSnippetByIndex (index, name) {
|
||||||
let snippets = this.state.note.snippets.slice()
|
const snippets = this.state.note.snippets.slice()
|
||||||
snippets[index].name = name
|
snippets[index].name = name
|
||||||
let syntax = CodeMirror.findModeByFileName(name.trim())
|
const syntax = CodeMirror.findModeByFileName(name.trim())
|
||||||
let mode = syntax != null ? syntax.name : null
|
const mode = syntax != null ? syntax.name : null
|
||||||
if (mode != null) snippets[index].mode = mode
|
if (mode != null) {
|
||||||
|
snippets[index].mode = mode
|
||||||
|
AwsMobileAnalyticsConfig.recordDynamicCustomEvent('SNIPPET_LANG', {
|
||||||
|
name: mode
|
||||||
|
})
|
||||||
|
}
|
||||||
this.setState({note: Object.assign(this.state.note, {snippets: snippets})})
|
this.setState({note: Object.assign(this.state.note, {snippets: snippets})})
|
||||||
|
|
||||||
this.setState({
|
this.setState({
|
||||||
@@ -291,6 +297,10 @@ class SnippetNoteDetail extends React.Component {
|
|||||||
}, () => {
|
}, () => {
|
||||||
this.save()
|
this.save()
|
||||||
})
|
})
|
||||||
|
|
||||||
|
AwsMobileAnalyticsConfig.recordDynamicCustomEvent('SELECT_LANG', {
|
||||||
|
name
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -557,7 +567,7 @@ class SnippetNoteDetail extends React.Component {
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div styleName='info-right'>
|
<div styleName='info-right'>
|
||||||
<TrashButton onClick={(e) => this.handleTrashButtonClick(e)} />
|
<PermanentDeleteButton onClick={(e) => this.handleTrashButtonClick(e)} />
|
||||||
<InfoButton
|
<InfoButton
|
||||||
onClick={(e) => this.handleInfoButtonClick(e)}
|
onClick={(e) => this.handleInfoButtonClick(e)}
|
||||||
/>
|
/>
|
||||||
@@ -574,10 +584,6 @@ class SnippetNoteDetail extends React.Component {
|
|||||||
|
|
||||||
const detailTopBar = <div styleName='info'>
|
const detailTopBar = <div styleName='info'>
|
||||||
<div styleName='info-left'>
|
<div styleName='info-left'>
|
||||||
<StarButton styleName='info-left-button'
|
|
||||||
onClick={(e) => this.handleStarButtonClick(e)}
|
|
||||||
isActive={note.isStarred}
|
|
||||||
/>
|
|
||||||
<div styleName='info-left-top'>
|
<div styleName='info-left-top'>
|
||||||
<FolderSelect styleName='info-left-top-folderSelect'
|
<FolderSelect styleName='info-left-top-folderSelect'
|
||||||
value={this.state.note.storage + '-' + this.state.note.folder}
|
value={this.state.note.storage + '-' + this.state.note.folder}
|
||||||
@@ -594,15 +600,21 @@ class SnippetNoteDetail extends React.Component {
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div styleName='info-right'>
|
<div styleName='info-right'>
|
||||||
<TrashButton onClick={(e) => this.handleTrashButtonClick(e)} />
|
|
||||||
<button styleName='control-fullScreenButton'
|
|
||||||
onMouseDown={(e) => this.handleFullScreenButton(e)}
|
|
||||||
>
|
|
||||||
<i className='fa fa-window-maximize' styleName='fullScreen-button' />
|
|
||||||
</button>
|
|
||||||
<InfoButton
|
<InfoButton
|
||||||
onClick={(e) => this.handleInfoButtonClick(e)}
|
onClick={(e) => this.handleInfoButtonClick(e)}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
<StarButton
|
||||||
|
onClick={(e) => this.handleStarButtonClick(e)}
|
||||||
|
isActive={note.isStarred}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<button styleName='control-fullScreenButton'
|
||||||
|
onMouseDown={(e) => this.handleFullScreenButton(e)}>
|
||||||
|
<img styleName='iconInfo' src='../resources/icon/icon-sidebar.svg' />
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<TrashButton onClick={(e) => this.handleTrashButtonClick(e)} />
|
||||||
<InfoPanel
|
<InfoPanel
|
||||||
storageName={currentOption.storage.name}
|
storageName={currentOption.storage.name}
|
||||||
folderName={currentOption.folder.name}
|
folderName={currentOption.folder.name}
|
||||||
|
|||||||
@@ -3,16 +3,14 @@
|
|||||||
|
|
||||||
.root
|
.root
|
||||||
absolute top bottom right
|
absolute top bottom right
|
||||||
border-width 0 0 1px
|
border-left 1px solid alpha(#DEDEDE, 60%)
|
||||||
border-style solid
|
|
||||||
border-color $ui-borderColor
|
|
||||||
background-color $ui-noteDetail-backgroundColor
|
background-color $ui-noteDetail-backgroundColor
|
||||||
box-shadow $note-detail-box-shadow
|
box-shadow none
|
||||||
|
|
||||||
.body
|
.body
|
||||||
absolute left right
|
absolute left right
|
||||||
left $note-detail-left-margin
|
left $snippet-note-detail-left-margin
|
||||||
right $note-detail-right-margin
|
right $snippet-note-detail-right-margin
|
||||||
top $info-height + $info-margin-under-border
|
top $info-height + $info-margin-under-border
|
||||||
bottom $statusBar-height
|
bottom $statusBar-height
|
||||||
background-color $ui-noteDetail-backgroundColor
|
background-color $ui-noteDetail-backgroundColor
|
||||||
@@ -45,7 +43,7 @@
|
|||||||
overflow hidden
|
overflow hidden
|
||||||
|
|
||||||
.tabList .plusButton
|
.tabList .plusButton
|
||||||
navButtonColor()
|
navWhiteButtonColor()
|
||||||
width 30px
|
width 30px
|
||||||
|
|
||||||
.tabView
|
.tabView
|
||||||
@@ -57,24 +55,30 @@
|
|||||||
|
|
||||||
.override
|
.override
|
||||||
absolute bottom left
|
absolute bottom left
|
||||||
bottom 30px
|
bottom 1px
|
||||||
left 60px
|
left 60px
|
||||||
height 23px
|
|
||||||
z-index 101
|
z-index 101
|
||||||
button
|
button
|
||||||
navButtonColor()
|
navButtonColor()
|
||||||
height 24px
|
padding 0 6px
|
||||||
|
&:hover
|
||||||
|
color $ui-active-color
|
||||||
&:active .update-icon
|
&:active .update-icon
|
||||||
color white
|
color $ui-active-color
|
||||||
|
|
||||||
.control-fullScreenButton
|
.control-fullScreenButton
|
||||||
float right
|
top 80px
|
||||||
padding 0 0 2px 0
|
margin-bottom 10px
|
||||||
topBarButtonLight()
|
topBarButtonLight()
|
||||||
|
|
||||||
|
body[data-theme="white"]
|
||||||
|
.root
|
||||||
|
box-shadow $note-detail-box-shadow
|
||||||
|
border none
|
||||||
|
|
||||||
body[data-theme="dark"]
|
body[data-theme="dark"]
|
||||||
.root
|
.root
|
||||||
border-color $ui-dark-borderColor
|
border none
|
||||||
background-color $ui-dark-noteDetail-backgroundColor
|
background-color $ui-dark-noteDetail-backgroundColor
|
||||||
box-shadow none
|
box-shadow none
|
||||||
|
|
||||||
|
|||||||
@@ -47,10 +47,10 @@ class StarButton extends React.Component {
|
|||||||
onMouseLeave={(e) => this.handleMouseLeave(e)}
|
onMouseLeave={(e) => this.handleMouseLeave(e)}
|
||||||
onClick={this.props.onClick}
|
onClick={this.props.onClick}
|
||||||
>
|
>
|
||||||
<i styleName='icon'
|
<img styleName='icon'
|
||||||
className={this.state.isActive || this.props.isActive
|
src={this.state.isActive || this.props.isActive
|
||||||
? 'fa fa-star'
|
? '../resources/icon/icon-starred.svg'
|
||||||
: 'fa fa-star-o'
|
: '../resources/icon/icon-star.svg'
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
</button>
|
</button>
|
||||||
|
|||||||
@@ -1,47 +1,24 @@
|
|||||||
.root
|
.root
|
||||||
left 7px
|
top 45px
|
||||||
top 0
|
topBarButtonLight()
|
||||||
padding 0
|
|
||||||
color alpha($ui-favorite-star-button-color, 60%)
|
|
||||||
&:hover
|
&:hover
|
||||||
transition 0.15s
|
transition 0.2s
|
||||||
background-color alpha($ui-button--active-backgroundColor, 40%)
|
color alpha($ui-favorite-star-button-color, 0.6)
|
||||||
color $ui-favorite-star-button-color
|
|
||||||
&:active
|
|
||||||
transition 0.15s
|
|
||||||
background-color alpha($ui-button--active-backgroundColor, 40%)
|
|
||||||
color $ui-favorite-star-button-color
|
|
||||||
|
|
||||||
.root--active
|
.root--active
|
||||||
@extend .root
|
@extend .root
|
||||||
|
transition 0.15s
|
||||||
color $ui-favorite-star-button-color
|
color $ui-favorite-star-button-color
|
||||||
&:hover
|
&:hover
|
||||||
transition 0.15s
|
transition 0.2s
|
||||||
color $ui-favorite-star-button-color
|
color alpha($ui-favorite-star-button-color, 0.6)
|
||||||
background-color alpha($ui-button--active-backgroundColor, 40%)
|
|
||||||
&:active
|
|
||||||
transition 0.15s
|
|
||||||
color $ui-favorite-star-button-color
|
|
||||||
background-color alpha($ui-button--active-backgroundColor, 40%)
|
|
||||||
|
|
||||||
.icon
|
.icon
|
||||||
transition transform 0.15s
|
transition transform 0.15s
|
||||||
|
|
||||||
body[data-theme="dark"]
|
body[data-theme="dark"]
|
||||||
.root
|
.root
|
||||||
|
topBarButtonDark()
|
||||||
&:hover
|
&:hover
|
||||||
transition 0.15s
|
transition 0.2s
|
||||||
background-color alpha($ui-dark-button--active-backgroundColor, 20%)
|
color alpha($ui-favorite-star-button-color, 0.6)
|
||||||
color $ui-favorite-star-button-color
|
|
||||||
&:active
|
|
||||||
transition 0.15s
|
|
||||||
background-color alpha($ui-dark-button--active-backgroundColor, 20%)
|
|
||||||
color $ui-favorite-star-button-color
|
|
||||||
|
|
||||||
.root--active
|
|
||||||
@extend .root
|
|
||||||
color $ui-favorite-star-button-color
|
|
||||||
&:hover
|
|
||||||
transition 0.15s
|
|
||||||
color $ui-favorite-star-button-color
|
|
||||||
background-color alpha($ui-dark-button--active-backgroundColor, 20%)
|
|
||||||
@@ -113,7 +113,7 @@ class TagSelect extends React.Component {
|
|||||||
<button styleName='tag-removeButton'
|
<button styleName='tag-removeButton'
|
||||||
onClick={(e) => this.handleTagRemoveButtonClick(tag)(e)}
|
onClick={(e) => this.handleTagRemoveButtonClick(tag)(e)}
|
||||||
>
|
>
|
||||||
<i className='fa fa-times fa-fw tag-removeButton-icon' />
|
<img className='tag-removeButton-icon' src='../resources/icon/icon-x.svg' width='8px' />
|
||||||
</button>
|
</button>
|
||||||
</span>
|
</span>
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
.root
|
.root
|
||||||
display inline-block
|
display flex
|
||||||
|
align-items center
|
||||||
user-select none
|
user-select none
|
||||||
height 23px
|
|
||||||
vertical-align middle
|
vertical-align middle
|
||||||
width 300px
|
width 100%
|
||||||
overflow-x scroll
|
overflow-x scroll
|
||||||
white-space nowrap
|
white-space nowrap
|
||||||
|
|
||||||
@@ -11,51 +11,42 @@
|
|||||||
display none
|
display none
|
||||||
|
|
||||||
.tag
|
.tag
|
||||||
display inline-block
|
display flex
|
||||||
margin 1px 3px
|
align-items center
|
||||||
padding 0
|
margin 0px 2px
|
||||||
height 20px
|
padding 2px 4px
|
||||||
background-color alpha($ui-tag-backgroundColor, 10%)
|
background-color alpha($ui-tag-backgroundColor, 3%)
|
||||||
border-radius 3px
|
border-radius 4px
|
||||||
overflow hidden
|
position relative
|
||||||
clearfix()
|
clearfix()
|
||||||
|
|
||||||
.tag-removeButton
|
.tag-removeButton
|
||||||
float right
|
|
||||||
height 20px
|
|
||||||
width 18px
|
|
||||||
margin 0
|
margin 0
|
||||||
padding 0
|
padding 0
|
||||||
border-style solid
|
border-style solid
|
||||||
border-width 0
|
border-width 0
|
||||||
border-radius 20px
|
border-radius 20px
|
||||||
line-height 18px
|
|
||||||
background-color transparent
|
background-color transparent
|
||||||
color $ui-button-color
|
color $ui-button-color
|
||||||
|
position absolute
|
||||||
|
right 6px
|
||||||
|
|
||||||
.tag-removeButton-icon
|
.tag-removeButton-icon
|
||||||
width 5px
|
width 5px
|
||||||
padding-right 4px
|
padding-right 4px
|
||||||
|
|
||||||
.tag-label
|
.tag-label
|
||||||
font-size 11px
|
font-size 13px
|
||||||
font-weight 600
|
color: $ui-text-color
|
||||||
color: alpha($ui-text-color, 80%)
|
padding 4px 16px 4px 8px
|
||||||
float left
|
|
||||||
height 20px
|
|
||||||
line-height 20px
|
|
||||||
padding 0 6px
|
|
||||||
|
|
||||||
.newTag
|
.newTag
|
||||||
display inline-block
|
box-sizing border-box
|
||||||
margin 2px 0 15px 2px
|
|
||||||
vertical-align middle
|
|
||||||
height 18px
|
|
||||||
box-sizing borde-box
|
|
||||||
border none
|
border none
|
||||||
background-color transparent
|
background-color transparent
|
||||||
outline none
|
outline none
|
||||||
padding 0 4px
|
padding 0 4px
|
||||||
|
font-size 13px
|
||||||
|
|
||||||
body[data-theme="dark"]
|
body[data-theme="dark"]
|
||||||
.tag
|
.tag
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ const TrashButton = ({
|
|||||||
<button styleName='control-trashButton'
|
<button styleName='control-trashButton'
|
||||||
onClick={(e) => onClick(e)}
|
onClick={(e) => onClick(e)}
|
||||||
>
|
>
|
||||||
<i className='fa fa-trash trashButton' styleName='info-button' />
|
<img styleName='iconInfo' src='../resources/icon/icon-trash.svg' />
|
||||||
</button>
|
</button>
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -1,10 +1,14 @@
|
|||||||
.control-trashButton
|
.control-trashButton
|
||||||
float right
|
top 120px
|
||||||
|
margin-bottom 10px
|
||||||
|
topBarButtonLight()
|
||||||
|
|
||||||
|
.control-trashButton--in-trash
|
||||||
|
top 60px
|
||||||
topBarButtonLight()
|
topBarButtonLight()
|
||||||
|
|
||||||
.trashButton
|
.trashButton
|
||||||
padding 0px
|
padding 0px
|
||||||
margin 15px 0
|
|
||||||
|
|
||||||
body[data-theme="dark"]
|
body[data-theme="dark"]
|
||||||
.control-trashButton
|
.control-trashButton
|
||||||
|
|||||||
@@ -11,16 +11,11 @@ import _ from 'lodash'
|
|||||||
import ConfigManager from 'browser/main/lib/ConfigManager'
|
import ConfigManager from 'browser/main/lib/ConfigManager'
|
||||||
import modal from 'browser/main/lib/modal'
|
import modal from 'browser/main/lib/modal'
|
||||||
import InitModal from 'browser/main/modals/InitModal'
|
import InitModal from 'browser/main/modals/InitModal'
|
||||||
import mixpanel from 'browser/main/lib/mixpanel'
|
|
||||||
import mobileAnalytics from 'browser/main/lib/AwsMobileAnalyticsConfig'
|
import mobileAnalytics from 'browser/main/lib/AwsMobileAnalyticsConfig'
|
||||||
import eventEmitter from 'browser/main/lib/eventEmitter'
|
import eventEmitter from 'browser/main/lib/eventEmitter'
|
||||||
import RealtimeNotification from 'browser/components/RealtimeNotification'
|
|
||||||
|
|
||||||
function focused () {
|
|
||||||
mixpanel.track('MAIN_FOCUSED')
|
|
||||||
}
|
|
||||||
|
|
||||||
class Main extends React.Component {
|
class Main extends React.Component {
|
||||||
|
|
||||||
constructor (props) {
|
constructor (props) {
|
||||||
super(props)
|
super(props)
|
||||||
|
|
||||||
@@ -57,6 +52,8 @@ class Main extends React.Component {
|
|||||||
|
|
||||||
if (config.ui.theme === 'dark') {
|
if (config.ui.theme === 'dark') {
|
||||||
document.body.setAttribute('data-theme', 'dark')
|
document.body.setAttribute('data-theme', 'dark')
|
||||||
|
} else if (config.ui.theme === 'white') {
|
||||||
|
document.body.setAttribute('data-theme', 'white')
|
||||||
} else {
|
} else {
|
||||||
document.body.setAttribute('data-theme', 'default')
|
document.body.setAttribute('data-theme', 'default')
|
||||||
}
|
}
|
||||||
@@ -76,11 +73,9 @@ class Main extends React.Component {
|
|||||||
})
|
})
|
||||||
|
|
||||||
eventEmitter.on('editor:fullscreen', this.toggleFullScreen)
|
eventEmitter.on('editor:fullscreen', this.toggleFullScreen)
|
||||||
window.addEventListener('focus', focused)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
componentWillUnmount () {
|
componentWillUnmount () {
|
||||||
window.removeEventListener('focus', focused)
|
|
||||||
eventEmitter.off('editor:fullscreen', this.toggleFullScreen)
|
eventEmitter.off('editor:fullscreen', this.toggleFullScreen)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -189,6 +184,9 @@ class Main extends React.Component {
|
|||||||
render () {
|
render () {
|
||||||
let { config } = this.props
|
let { config } = this.props
|
||||||
|
|
||||||
|
// the width of the navigation bar when it is folded/collapsed
|
||||||
|
const foldedNavigationWidth = 44
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
className='Main'
|
className='Main'
|
||||||
@@ -217,7 +215,7 @@ class Main extends React.Component {
|
|||||||
<div styleName={config.isSideNavFolded ? 'body--expanded' : 'body'}
|
<div styleName={config.isSideNavFolded ? 'body--expanded' : 'body'}
|
||||||
id='main-body'
|
id='main-body'
|
||||||
ref='body'
|
ref='body'
|
||||||
style={{left: config.isSideNavFolded ? 44 : this.state.navWidth}}
|
style={{left: config.isSideNavFolded ? foldedNavigationWidth : this.state.navWidth}}
|
||||||
>
|
>
|
||||||
<TopBar style={{width: this.state.listWidth}}
|
<TopBar style={{width: this.state.listWidth}}
|
||||||
{..._.pick(this.props, [
|
{..._.pick(this.props, [
|
||||||
@@ -256,7 +254,6 @@ class Main extends React.Component {
|
|||||||
ignorePreviewPointerEvents={this.state.isRightSliderFocused}
|
ignorePreviewPointerEvents={this.state.isRightSliderFocused}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<RealtimeNotification />
|
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,7 +4,6 @@
|
|||||||
height $topBar-height - 1
|
height $topBar-height - 1
|
||||||
margin-left: auto;
|
margin-left: auto;
|
||||||
width: 64px;
|
width: 64px;
|
||||||
margin-right: -15px;
|
|
||||||
|
|
||||||
.root--expanded
|
.root--expanded
|
||||||
@extend .root
|
@extend .root
|
||||||
@@ -14,10 +13,8 @@ $control-height = 34px
|
|||||||
.control
|
.control
|
||||||
position absolute
|
position absolute
|
||||||
top 13px
|
top 13px
|
||||||
left 8px
|
right 7px
|
||||||
right 8px
|
|
||||||
height $control-height
|
height $control-height
|
||||||
overflow hidden
|
|
||||||
display flex
|
display flex
|
||||||
|
|
||||||
.control-newNoteButton
|
.control-newNoteButton
|
||||||
@@ -35,10 +32,11 @@ $control-height = 34px
|
|||||||
|
|
||||||
.control-newNoteButton-tooltip
|
.control-newNoteButton-tooltip
|
||||||
tooltip()
|
tooltip()
|
||||||
position fixed
|
position absolute
|
||||||
pointer-events none
|
pointer-events none
|
||||||
top 50px
|
top 26px
|
||||||
left 433px
|
right -43px
|
||||||
|
width 124px
|
||||||
z-index 200
|
z-index 200
|
||||||
padding 5px
|
padding 5px
|
||||||
line-height normal
|
line-height normal
|
||||||
@@ -46,6 +44,13 @@ $control-height = 34px
|
|||||||
opacity 0
|
opacity 0
|
||||||
transition 0.1s
|
transition 0.1s
|
||||||
|
|
||||||
|
body[data-theme="white"]
|
||||||
|
.root, .root--expanded
|
||||||
|
background-color $ui-white-noteList-backgroundColor
|
||||||
|
|
||||||
|
.control-newNoteButton
|
||||||
|
background-color $ui-white-noteList-backgroundColor
|
||||||
|
|
||||||
body[data-theme="dark"]
|
body[data-theme="dark"]
|
||||||
.root, .root--expanded
|
.root, .root--expanded
|
||||||
background-color $ui-dark-noteList-backgroundColor
|
background-color $ui-dark-noteList-backgroundColor
|
||||||
|
|||||||
@@ -85,7 +85,7 @@ class NewNoteButton extends React.Component {
|
|||||||
<div styleName='control'>
|
<div styleName='control'>
|
||||||
<button styleName='control-newNoteButton'
|
<button styleName='control-newNoteButton'
|
||||||
onClick={(e) => this.handleNewNoteButtonClick(e)}>
|
onClick={(e) => this.handleNewNoteButtonClick(e)}>
|
||||||
<i className='fa fa-pencil-square-o' />
|
<img styleName='iconTag' src='../resources/icon/icon-newnote.svg' />
|
||||||
<span styleName='control-newNoteButton-tooltip'>
|
<span styleName='control-newNoteButton-tooltip'>
|
||||||
Make a Note {OSX ? '⌘' : '^'} + n
|
Make a Note {OSX ? '⌘' : '^'} + n
|
||||||
</span>
|
</span>
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ $control-height = 30px
|
|||||||
|
|
||||||
.root
|
.root
|
||||||
absolute left bottom
|
absolute left bottom
|
||||||
bottom 30px
|
|
||||||
top $topBar-height - 1
|
top $topBar-height - 1
|
||||||
background-color $ui-noteList-backgroundColor
|
background-color $ui-noteList-backgroundColor
|
||||||
|
|
||||||
@@ -22,14 +21,14 @@ $control-height = 30px
|
|||||||
|
|
||||||
.control-sortBy-select
|
.control-sortBy-select
|
||||||
appearance: none;
|
appearance: none;
|
||||||
margin-left 3px
|
margin-left 5px
|
||||||
color $ui-inactive-text-color
|
color $ui-inactive-text-color
|
||||||
padding 0
|
padding 0
|
||||||
border none
|
border none
|
||||||
background-color transparent
|
background-color transparent
|
||||||
outline none
|
outline none
|
||||||
cursor pointer
|
cursor pointer
|
||||||
font-size 11px
|
font-size 12px
|
||||||
&:hover
|
&:hover
|
||||||
transition 0.2s
|
transition 0.2s
|
||||||
color $ui-text-color
|
color $ui-text-color
|
||||||
@@ -60,6 +59,13 @@ $control-height = 30px
|
|||||||
top $control-height
|
top $control-height
|
||||||
overflow auto
|
overflow auto
|
||||||
|
|
||||||
|
body[data-theme="white"]
|
||||||
|
.root
|
||||||
|
background-color $ui-white-noteList-backgroundColor
|
||||||
|
|
||||||
|
.control
|
||||||
|
background-color $ui-white-noteList-backgroundColor
|
||||||
|
|
||||||
body[data-theme="dark"]
|
body[data-theme="dark"]
|
||||||
.root
|
.root
|
||||||
border-color $ui-dark-borderColor
|
border-color $ui-dark-borderColor
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ import { hashHistory } from 'react-router'
|
|||||||
import markdown from 'browser/lib/markdown'
|
import markdown from 'browser/lib/markdown'
|
||||||
import { findNoteTitle } from 'browser/lib/findNoteTitle'
|
import { findNoteTitle } from 'browser/lib/findNoteTitle'
|
||||||
import stripgtags from 'striptags'
|
import stripgtags from 'striptags'
|
||||||
|
import store from 'browser/main/store'
|
||||||
|
|
||||||
const { remote } = require('electron')
|
const { remote } = require('electron')
|
||||||
const { Menu, MenuItem, dialog } = remote
|
const { Menu, MenuItem, dialog } = remote
|
||||||
@@ -52,6 +53,8 @@ class NoteList extends React.Component {
|
|||||||
|
|
||||||
this.state = {
|
this.state = {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.contextNotes = []
|
||||||
}
|
}
|
||||||
|
|
||||||
componentDidMount () {
|
componentDidMount () {
|
||||||
@@ -90,6 +93,7 @@ class NoteList extends React.Component {
|
|||||||
|
|
||||||
if (this.notes.length > 0 && location.query.key == null) {
|
if (this.notes.length > 0 && location.query.key == null) {
|
||||||
let { router } = this.context
|
let { router } = this.context
|
||||||
|
if (!location.pathname.match(/\/searched/)) this.contextNotes = this.getContextNotes()
|
||||||
router.replace({
|
router.replace({
|
||||||
pathname: location.pathname,
|
pathname: location.pathname,
|
||||||
query: {
|
query: {
|
||||||
@@ -101,9 +105,7 @@ class NoteList extends React.Component {
|
|||||||
|
|
||||||
// Auto scroll
|
// Auto scroll
|
||||||
if (_.isString(location.query.key) && prevProps.location.query.key === location.query.key) {
|
if (_.isString(location.query.key) && prevProps.location.query.key === location.query.key) {
|
||||||
let targetIndex = _.findIndex(this.notes, (note) => {
|
const targetIndex = this.getTargetIndex()
|
||||||
return note != null && note.storage + '-' + note.key === location.query.key
|
|
||||||
})
|
|
||||||
if (targetIndex > -1) {
|
if (targetIndex > -1) {
|
||||||
let list = this.refs.list
|
let list = this.refs.list
|
||||||
let item = list.childNodes[targetIndex]
|
let item = list.childNodes[targetIndex]
|
||||||
@@ -129,9 +131,7 @@ class NoteList extends React.Component {
|
|||||||
let { router } = this.context
|
let { router } = this.context
|
||||||
let { location } = this.props
|
let { location } = this.props
|
||||||
|
|
||||||
let targetIndex = _.findIndex(this.notes, (note) => {
|
let targetIndex = this.getTargetIndex()
|
||||||
return note.storage + '-' + note.key === location.query.key
|
|
||||||
})
|
|
||||||
|
|
||||||
if (targetIndex === 0) {
|
if (targetIndex === 0) {
|
||||||
return
|
return
|
||||||
@@ -154,9 +154,7 @@ class NoteList extends React.Component {
|
|||||||
let { router } = this.context
|
let { router } = this.context
|
||||||
let { location } = this.props
|
let { location } = this.props
|
||||||
|
|
||||||
let targetIndex = _.findIndex(this.notes, (note) => {
|
let targetIndex = this.getTargetIndex()
|
||||||
return note.storage + '-' + note.key === location.query.key
|
|
||||||
})
|
|
||||||
|
|
||||||
if (targetIndex === this.notes.length - 1) {
|
if (targetIndex === this.notes.length - 1) {
|
||||||
targetIndex = 0
|
targetIndex = 0
|
||||||
@@ -184,9 +182,7 @@ class NoteList extends React.Component {
|
|||||||
const { router } = this.context
|
const { router } = this.context
|
||||||
const { location } = this.props
|
const { location } = this.props
|
||||||
|
|
||||||
let targetIndex = _.findIndex(this.notes, (note) => {
|
let targetIndex = this.getTargetIndex()
|
||||||
return note.storage + '-' + note.key === noteHash
|
|
||||||
})
|
|
||||||
|
|
||||||
if (targetIndex < 0) targetIndex = 0
|
if (targetIndex < 0) targetIndex = 0
|
||||||
|
|
||||||
@@ -233,49 +229,74 @@ class NoteList extends React.Component {
|
|||||||
let { data, params, location } = this.props
|
let { data, params, location } = this.props
|
||||||
let { router } = this.context
|
let { router } = this.context
|
||||||
|
|
||||||
if (location.pathname.match(/\/home/)) {
|
if (location.pathname.match(/\/home/) || location.pathname.match(/\alltags/)) {
|
||||||
return data.noteMap.map((note) => note)
|
const allNotes = data.noteMap.map((note) => note)
|
||||||
|
this.contextNotes = allNotes
|
||||||
|
return allNotes
|
||||||
}
|
}
|
||||||
|
|
||||||
if (location.pathname.match(/\/starred/)) {
|
if (location.pathname.match(/\/starred/)) {
|
||||||
return data.starredSet.toJS()
|
const starredNotes = data.starredSet.toJS().map((uniqueKey) => data.noteMap.get(uniqueKey))
|
||||||
.map((uniqueKey) => data.noteMap.get(uniqueKey))
|
this.contextNotes = starredNotes
|
||||||
|
return starredNotes
|
||||||
}
|
}
|
||||||
|
|
||||||
if (location.pathname.match(/\/searched/)) {
|
if (location.pathname.match(/\/searched/)) {
|
||||||
const searchInputText = document.getElementsByClassName('searchInput')[0].value
|
const searchInputText = document.getElementsByClassName('searchInput')[0].value
|
||||||
if (searchInputText === '') {
|
if (searchInputText === '') {
|
||||||
router.push('/home')
|
return this.sortByPin(this.contextNotes)
|
||||||
}
|
}
|
||||||
return searchFromNotes(this.notes, searchInputText)
|
return searchFromNotes(this.contextNotes, searchInputText)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (location.pathname.match(/\/trashed/)) {
|
if (location.pathname.match(/\/trashed/)) {
|
||||||
return data.trashedSet.toJS()
|
const trashedNotes = data.trashedSet.toJS().map((uniqueKey) => data.noteMap.get(uniqueKey))
|
||||||
.map((uniqueKey) => data.noteMap.get(uniqueKey))
|
this.contextNotes = trashedNotes
|
||||||
|
return trashedNotes
|
||||||
}
|
}
|
||||||
|
|
||||||
let storageKey = params.storageKey
|
if (location.pathname.match(/\/tags/)) {
|
||||||
let folderKey = params.folderKey
|
return data.noteMap.map(note => {
|
||||||
let storage = data.storageMap.get(storageKey)
|
return note
|
||||||
if (storage == null) return []
|
}).filter(note => {
|
||||||
|
return note.tags.includes(params.tagname)
|
||||||
let folder = _.find(storage.folders, {key: folderKey})
|
})
|
||||||
if (folder == null) {
|
|
||||||
let storageNoteSet = data.storageNoteMap
|
|
||||||
.get(storage.key)
|
|
||||||
if (storageNoteSet == null) storageNoteSet = []
|
|
||||||
return storageNoteSet
|
|
||||||
.map((uniqueKey) => data.noteMap.get(uniqueKey))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let folderNoteKeyList = data.folderNoteMap
|
return this.getContextNotes()
|
||||||
.get(storage.key + '-' + folder.key)
|
}
|
||||||
|
|
||||||
return folderNoteKeyList != null
|
// get notes in the current folder
|
||||||
? folderNoteKeyList
|
getContextNotes () {
|
||||||
.map((uniqueKey) => data.noteMap.get(uniqueKey))
|
const { data, params } = this.props
|
||||||
: []
|
const storageKey = params.storageKey
|
||||||
|
const folderKey = params.folderKey
|
||||||
|
const storage = data.storageMap.get(storageKey)
|
||||||
|
if (storage === undefined) return []
|
||||||
|
|
||||||
|
const folder = _.find(storage.folders, {key: folderKey})
|
||||||
|
if (folder === undefined) {
|
||||||
|
const storageNoteSet = data.storageNoteMap.get(storage.key) || []
|
||||||
|
return storageNoteSet.map((uniqueKey) => data.noteMap.get(uniqueKey))
|
||||||
|
}
|
||||||
|
|
||||||
|
const folderNoteKeyList = data.folderNoteMap.get(`${storage.key}-${folder.key}`) || []
|
||||||
|
return folderNoteKeyList.map((uniqueKey) => data.noteMap.get(uniqueKey))
|
||||||
|
}
|
||||||
|
|
||||||
|
sortByPin (unorderedNotes) {
|
||||||
|
const pinnedNotes = []
|
||||||
|
const unpinnedNotes = []
|
||||||
|
|
||||||
|
unorderedNotes.forEach((note) => {
|
||||||
|
if (note.isPinned) {
|
||||||
|
pinnedNotes.push(note)
|
||||||
|
} else {
|
||||||
|
unpinnedNotes.push(note)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
return pinnedNotes.concat(unpinnedNotes)
|
||||||
}
|
}
|
||||||
|
|
||||||
handleNoteClick (e, uniqueKey) {
|
handleNoteClick (e, uniqueKey) {
|
||||||
@@ -319,10 +340,7 @@ class NoteList extends React.Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
alertIfSnippet () {
|
alertIfSnippet () {
|
||||||
let { location } = this.props
|
const targetIndex = this.getTargetIndex()
|
||||||
const targetIndex = _.findIndex(this.notes, (note) => {
|
|
||||||
return `${note.storage}-${note.key}` === location.query.key
|
|
||||||
})
|
|
||||||
if (this.notes[targetIndex].type === 'SNIPPET_NOTE') {
|
if (this.notes[targetIndex].type === 'SNIPPET_NOTE') {
|
||||||
dialog.showMessageBox(remote.getCurrentWindow(), {
|
dialog.showMessageBox(remote.getCurrentWindow(), {
|
||||||
type: 'warning',
|
type: 'warning',
|
||||||
@@ -338,6 +356,58 @@ class NoteList extends React.Component {
|
|||||||
e.dataTransfer.setData('note', noteData)
|
e.dataTransfer.setData('note', noteData)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
handleNoteContextMenu (e, uniqueKey) {
|
||||||
|
const { location } = this.props
|
||||||
|
const note = this.notes.find((note) => {
|
||||||
|
const noteKey = `${note.storage}-${note.key}`
|
||||||
|
return noteKey === uniqueKey
|
||||||
|
})
|
||||||
|
|
||||||
|
const pinLabel = note.isPinned ? 'Remove pin' : 'Pin to Top'
|
||||||
|
const deleteLabel = 'Delete Note'
|
||||||
|
|
||||||
|
const menu = new Menu()
|
||||||
|
if (!location.pathname.match(/\/home|\/starred|\/trash/)) {
|
||||||
|
menu.append(new MenuItem({
|
||||||
|
label: pinLabel,
|
||||||
|
click: (e) => this.pinToTop(e, uniqueKey)
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
menu.append(new MenuItem({
|
||||||
|
label: deleteLabel,
|
||||||
|
click: (e) => this.deleteNote(e, uniqueKey)
|
||||||
|
}))
|
||||||
|
menu.popup()
|
||||||
|
}
|
||||||
|
|
||||||
|
pinToTop (e, uniqueKey) {
|
||||||
|
const { data, params } = this.props
|
||||||
|
const storageKey = params.storageKey
|
||||||
|
const folderKey = params.folderKey
|
||||||
|
|
||||||
|
const currentStorage = data.storageMap.get(storageKey)
|
||||||
|
const currentFolder = _.find(currentStorage.folders, {key: folderKey})
|
||||||
|
|
||||||
|
this.handleNoteClick(e, uniqueKey)
|
||||||
|
const targetIndex = this.getTargetIndex()
|
||||||
|
let note = this.notes[targetIndex]
|
||||||
|
note.isPinned = !note.isPinned
|
||||||
|
|
||||||
|
dataApi
|
||||||
|
.updateNote(note.storage, note.key, note)
|
||||||
|
.then((note) => {
|
||||||
|
store.dispatch({
|
||||||
|
type: 'UPDATE_NOTE',
|
||||||
|
note: note
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
deleteNote (e, uniqueKey) {
|
||||||
|
this.handleNoteClick(e, uniqueKey)
|
||||||
|
ee.emit('detail:delete')
|
||||||
|
}
|
||||||
|
|
||||||
importFromFile () {
|
importFromFile () {
|
||||||
const { dispatch, location } = this.props
|
const { dispatch, location } = this.props
|
||||||
|
|
||||||
@@ -363,13 +433,7 @@ class NoteList extends React.Component {
|
|||||||
// Add notes to the current folder
|
// Add notes to the current folder
|
||||||
addNotesFromFiles (filepaths) {
|
addNotesFromFiles (filepaths) {
|
||||||
const { dispatch, location } = this.props
|
const { dispatch, location } = this.props
|
||||||
|
const { storage, folder } = this.resolveTargetFolder()
|
||||||
const targetIndex = _.findIndex(this.notes, (note) => {
|
|
||||||
return note !== null && `${note.storage}-${note.key}` === location.query.key
|
|
||||||
})
|
|
||||||
|
|
||||||
const storageKey = this.notes[targetIndex].storage
|
|
||||||
const folderKey = this.notes[targetIndex].folder
|
|
||||||
|
|
||||||
if (filepaths === undefined) return
|
if (filepaths === undefined) return
|
||||||
filepaths.forEach((filepath) => {
|
filepaths.forEach((filepath) => {
|
||||||
@@ -378,11 +442,11 @@ class NoteList extends React.Component {
|
|||||||
const content = data.toString()
|
const content = data.toString()
|
||||||
const newNote = {
|
const newNote = {
|
||||||
content: content,
|
content: content,
|
||||||
folder: folderKey,
|
folder: folder.key,
|
||||||
title: markdown.strip(findNoteTitle(content)),
|
title: markdown.strip(findNoteTitle(content)),
|
||||||
type: 'MARKDOWN_NOTE'
|
type: 'MARKDOWN_NOTE'
|
||||||
}
|
}
|
||||||
dataApi.createNote(storageKey, newNote)
|
dataApi.createNote(storage.key, newNote)
|
||||||
.then((note) => {
|
.then((note) => {
|
||||||
dispatch({
|
dispatch({
|
||||||
type: 'UPDATE_NOTE',
|
type: 'UPDATE_NOTE',
|
||||||
@@ -397,6 +461,44 @@ class NoteList extends React.Component {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getTargetIndex () {
|
||||||
|
const { location } = this.props
|
||||||
|
const targetIndex = _.findIndex(this.notes, (note) => {
|
||||||
|
return `${note.storage}-${note.key}` === location.query.key
|
||||||
|
})
|
||||||
|
return targetIndex
|
||||||
|
}
|
||||||
|
|
||||||
|
resolveTargetFolder () {
|
||||||
|
const { data, params } = this.props
|
||||||
|
let storage = data.storageMap.get(params.storageKey)
|
||||||
|
|
||||||
|
// Find first storage
|
||||||
|
if (storage == null) {
|
||||||
|
for (let kv of data.storageMap) {
|
||||||
|
storage = kv[1]
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (storage == null) this.showMessageBox('No storage for importing note(s)')
|
||||||
|
const folder = _.find(storage.folders, {key: params.folderKey}) || storage.folders[0]
|
||||||
|
if (folder == null) this.showMessageBox('No folder for importing note(s)')
|
||||||
|
|
||||||
|
return {
|
||||||
|
storage,
|
||||||
|
folder
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
showMessageBox (message) {
|
||||||
|
dialog.showMessageBox(remote.getCurrentWindow(), {
|
||||||
|
type: 'warning',
|
||||||
|
message: message,
|
||||||
|
buttons: ['OK']
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
render () {
|
render () {
|
||||||
let { location, notes, config, dispatch } = this.props
|
let { location, notes, config, dispatch } = this.props
|
||||||
let sortFunc = config.sortBy === 'CREATED_AT'
|
let sortFunc = config.sortBy === 'CREATED_AT'
|
||||||
@@ -404,12 +506,32 @@ class NoteList extends React.Component {
|
|||||||
: config.sortBy === 'ALPHABETICAL'
|
: config.sortBy === 'ALPHABETICAL'
|
||||||
? sortByAlphabetical
|
? sortByAlphabetical
|
||||||
: sortByUpdatedAt
|
: sortByUpdatedAt
|
||||||
this.notes = notes = this.getNotes()
|
const sortedNotes = location.pathname.match(/\/home|\/starred|\/trash/)
|
||||||
.sort(sortFunc)
|
? this.getNotes().sort(sortFunc)
|
||||||
.filter((note) => {
|
: this.sortByPin(this.getNotes().sort(sortFunc))
|
||||||
// this is for the trash box
|
this.notes = notes = sortedNotes.filter((note) => {
|
||||||
if (note.isTrashed !== true || location.pathname === '/trashed') return true
|
// this is for the trash box
|
||||||
})
|
if (note.isTrashed !== true || location.pathname === '/trashed') return true
|
||||||
|
})
|
||||||
|
|
||||||
|
moment.locale('en', {
|
||||||
|
relativeTime: {
|
||||||
|
future: 'in %s',
|
||||||
|
past: '%s ago',
|
||||||
|
s: '%ds',
|
||||||
|
ss: '%ss',
|
||||||
|
m: '1m',
|
||||||
|
mm: '%dm',
|
||||||
|
h: 'an hour',
|
||||||
|
hh: '%dh',
|
||||||
|
d: '1d',
|
||||||
|
dd: '%dd',
|
||||||
|
M: '1M',
|
||||||
|
MM: '%dM',
|
||||||
|
y: '1Y',
|
||||||
|
yy: '%dY'
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
let noteList = notes
|
let noteList = notes
|
||||||
.map(note => {
|
.map(note => {
|
||||||
@@ -422,7 +544,7 @@ class NoteList extends React.Component {
|
|||||||
const dateDisplay = moment(
|
const dateDisplay = moment(
|
||||||
config.sortBy === 'CREATED_AT'
|
config.sortBy === 'CREATED_AT'
|
||||||
? note.createdAt : note.updatedAt
|
? note.createdAt : note.updatedAt
|
||||||
).fromNow()
|
).fromNow('D')
|
||||||
const key = `${note.storage}-${note.key}`
|
const key = `${note.storage}-${note.key}`
|
||||||
|
|
||||||
if (isDefault) {
|
if (isDefault) {
|
||||||
@@ -432,8 +554,10 @@ class NoteList extends React.Component {
|
|||||||
note={note}
|
note={note}
|
||||||
dateDisplay={dateDisplay}
|
dateDisplay={dateDisplay}
|
||||||
key={key}
|
key={key}
|
||||||
|
handleNoteContextMenu={this.handleNoteContextMenu.bind(this)}
|
||||||
handleNoteClick={this.handleNoteClick.bind(this)}
|
handleNoteClick={this.handleNoteClick.bind(this)}
|
||||||
handleDragStart={this.handleDragStart.bind(this)}
|
handleDragStart={this.handleDragStart.bind(this)}
|
||||||
|
pathname={location.pathname}
|
||||||
/>
|
/>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -443,6 +567,7 @@ class NoteList extends React.Component {
|
|||||||
isActive={isActive}
|
isActive={isActive}
|
||||||
note={note}
|
note={note}
|
||||||
key={key}
|
key={key}
|
||||||
|
handleNoteContextMenu={this.handleNoteContextMenu.bind(this)}
|
||||||
handleNoteClick={this.handleNoteClick.bind(this)}
|
handleNoteClick={this.handleNoteClick.bind(this)}
|
||||||
handleDragStart={this.handleDragStart.bind(this)}
|
handleDragStart={this.handleDragStart.bind(this)}
|
||||||
/>
|
/>
|
||||||
@@ -457,13 +582,13 @@ class NoteList extends React.Component {
|
|||||||
>
|
>
|
||||||
<div styleName='control'>
|
<div styleName='control'>
|
||||||
<div styleName='control-sortBy'>
|
<div styleName='control-sortBy'>
|
||||||
<i className='fa fa-bolt' />
|
<i className='fa fa-angle-down' />
|
||||||
<select styleName='control-sortBy-select'
|
<select styleName='control-sortBy-select'
|
||||||
value={config.sortBy}
|
value={config.sortBy}
|
||||||
onChange={(e) => this.handleSortByChange(e)}
|
onChange={(e) => this.handleSortByChange(e)}
|
||||||
>
|
>
|
||||||
<option value='UPDATED_AT'>Last Updated</option>
|
<option value='UPDATED_AT'>Updated</option>
|
||||||
<option value='CREATED_AT'>Creation Time</option>
|
<option value='CREATED_AT'>Created</option>
|
||||||
<option value='ALPHABETICAL'>Alphabetically</option>
|
<option value='ALPHABETICAL'>Alphabetically</option>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
@@ -474,7 +599,7 @@ class NoteList extends React.Component {
|
|||||||
}
|
}
|
||||||
onClick={(e) => this.handleListStyleButtonClick(e, 'DEFAULT')}
|
onClick={(e) => this.handleListStyleButtonClick(e, 'DEFAULT')}
|
||||||
>
|
>
|
||||||
<i className='fa fa-th-large' />
|
<img styleName='iconTag' src='../resources/icon/icon-column.svg' />
|
||||||
</button>
|
</button>
|
||||||
<button styleName={config.listStyle === 'SMALL'
|
<button styleName={config.listStyle === 'SMALL'
|
||||||
? 'control-button--active'
|
? 'control-button--active'
|
||||||
@@ -482,7 +607,7 @@ class NoteList extends React.Component {
|
|||||||
}
|
}
|
||||||
onClick={(e) => this.handleListStyleButtonClick(e, 'SMALL')}
|
onClick={(e) => this.handleListStyleButtonClick(e, 'SMALL')}
|
||||||
>
|
>
|
||||||
<i className='fa fa-list-ul' />
|
<img styleName='iconTag' src='../resources/icon/icon-column-list.svg' />
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,62 +1,84 @@
|
|||||||
.root
|
.root
|
||||||
absolute top left bottom
|
absolute top left bottom
|
||||||
width $sideNav-width
|
width $sideNav-width
|
||||||
background-color #f9f9f9
|
background-color #2E3235
|
||||||
user-select none
|
user-select none
|
||||||
color $ui-text-color
|
color $ui-text-color
|
||||||
|
height: 100vh
|
||||||
|
display: flex
|
||||||
|
flex-direction column
|
||||||
|
|
||||||
.top
|
.top
|
||||||
height $topBar-height
|
padding-bottom 15px
|
||||||
|
|
||||||
.top-menu
|
.top-menu-preference
|
||||||
navButtonColor()
|
navButtonColor()
|
||||||
height $topBar-height
|
position absolute
|
||||||
padding 0 15px
|
top 22px
|
||||||
font-size 12px
|
right 10px
|
||||||
width 100%
|
width 2em
|
||||||
text-align left
|
background-color transparent
|
||||||
&:hover
|
&:hover
|
||||||
color $ui-text-color
|
color $ui-button-default--active-backgroundColor
|
||||||
|
background-color transparent
|
||||||
&:active, &:active:hover
|
&:active, &:active:hover
|
||||||
color $ui-text-color
|
color $ui-button-default--active-backgroundColor
|
||||||
background-color alpha($ui-button--active-backgroundColor, 20%)
|
|
||||||
|
.switch-buttons
|
||||||
|
background-color transparent
|
||||||
|
border 0
|
||||||
|
margin 24px auto 4px 14px
|
||||||
|
display flex
|
||||||
|
text-align center
|
||||||
|
|
||||||
|
.non-active-button
|
||||||
|
color $ui-inactive-text-color
|
||||||
|
font-size 16px
|
||||||
|
border 0
|
||||||
|
background-color transparent
|
||||||
|
transition 0.2s
|
||||||
|
display flex
|
||||||
|
text-align center
|
||||||
|
margin-right 4px;
|
||||||
|
&:hover
|
||||||
|
color alpha(#239F86, 60%)
|
||||||
|
|
||||||
|
.active-button
|
||||||
|
@extend .non-active-button
|
||||||
|
color $ui-button-default--active-backgroundColor
|
||||||
|
|
||||||
.top-menu-label
|
.top-menu-label
|
||||||
margin-left 5px
|
margin-left 5px
|
||||||
overflow ellipsis
|
overflow ellipsis
|
||||||
|
opacity 0
|
||||||
|
|
||||||
.storageList
|
.tabBody
|
||||||
absolute left right
|
flex 1
|
||||||
bottom 37px
|
display flex
|
||||||
top 160px
|
flex-direction column
|
||||||
|
|
||||||
|
.tag-title
|
||||||
|
padding-left 15px
|
||||||
|
padding-bottom 13px
|
||||||
|
p
|
||||||
|
color $ui-button-default-color
|
||||||
|
|
||||||
|
.tagList
|
||||||
overflow-y auto
|
overflow-y auto
|
||||||
|
flex: 1
|
||||||
.storageList-empty
|
|
||||||
padding 0 10px
|
|
||||||
margin-top 15px
|
|
||||||
line-height 24px
|
|
||||||
color $ui-inactive-text-color
|
|
||||||
|
|
||||||
.navToggle
|
|
||||||
navButtonColor()
|
|
||||||
display block
|
|
||||||
position absolute
|
|
||||||
right 5px
|
|
||||||
bottom 5px
|
|
||||||
border-radius 16.5px
|
|
||||||
height 34px
|
|
||||||
width 34px
|
|
||||||
line-height 32px
|
|
||||||
padding 0
|
|
||||||
|
|
||||||
.root--folded
|
.root--folded
|
||||||
@extend .root
|
height 100vh
|
||||||
width 44px
|
width $sideNav--folded-width
|
||||||
.storageList-empty
|
background-color #2E3235
|
||||||
white-space nowrap
|
.switch-buttons
|
||||||
transform rotate(90deg)
|
display none
|
||||||
|
.top
|
||||||
|
height 60px
|
||||||
.top-menu
|
.top-menu
|
||||||
width 44px - 1
|
position static
|
||||||
|
width $sideNav--folded-width
|
||||||
|
height 60px
|
||||||
text-align center
|
text-align center
|
||||||
&:hover .top-menu-label
|
&:hover .top-menu-label
|
||||||
transition opacity 0.15s
|
transition opacity 0.15s
|
||||||
@@ -65,44 +87,54 @@
|
|||||||
position fixed
|
position fixed
|
||||||
display inline-block
|
display inline-block
|
||||||
height 30px
|
height 30px
|
||||||
left 32px
|
left $sideNav--folded-width
|
||||||
padding 0 10px
|
padding 0 10px
|
||||||
margin-top -8px
|
margin-top -8px
|
||||||
opacity 0
|
opacity 0
|
||||||
margin-left 0
|
margin-left 0
|
||||||
overflow hidden
|
overflow hidden
|
||||||
background-color $ui-tooltip-backgroundColor
|
|
||||||
z-index 10
|
z-index 10
|
||||||
color white
|
color white
|
||||||
line-height 30px
|
line-height 30px
|
||||||
border-top-right-radius 2px
|
border-top-right-radius 2px
|
||||||
border-bottom-right-radius 2px
|
border-bottom-right-radius 2px
|
||||||
pointer-events none
|
pointer-events none
|
||||||
font-size 12px
|
font-size 13px
|
||||||
.menu-button, .menu-button--active
|
.top-menu-preference
|
||||||
text-align center
|
position absolute
|
||||||
&:hover .menu-button-label
|
left 11px
|
||||||
transition opacity 0.15s
|
|
||||||
opacity 1
|
|
||||||
|
|
||||||
.menu-button-label
|
body[data-theme="white"]
|
||||||
position fixed
|
.root, .root--folded
|
||||||
display inline-block
|
background-color #f9f9f9
|
||||||
height 32px
|
color $ui-text-color
|
||||||
left 44px
|
|
||||||
padding 0 10px
|
.top-menu-preference
|
||||||
margin-top -8px
|
navWhiteButtonColor()
|
||||||
margin-left 0
|
background-color transparent
|
||||||
overflow ellipsis
|
&:hover
|
||||||
background-color $ui-tooltip-backgroundColor
|
color #0B99F1
|
||||||
z-index 10
|
background-color transparent
|
||||||
color white
|
&:active, &:active:hover
|
||||||
line-height 32px
|
color #0B99F1
|
||||||
border-top-right-radius 2px
|
background-color transparent
|
||||||
border-bottom-right-radius 2px
|
|
||||||
pointer-events none
|
.non-active-button
|
||||||
opacity 0
|
color $ui-inactive-text-color
|
||||||
font-size 12px
|
&:hover
|
||||||
|
color alpha(#0B99F1, 60%)
|
||||||
|
|
||||||
|
.tag-title
|
||||||
|
p
|
||||||
|
color $ui-text-color
|
||||||
|
|
||||||
|
.non-active-button
|
||||||
|
&:hover
|
||||||
|
color alpha(#0B99F1, 60%)
|
||||||
|
|
||||||
|
.active-button
|
||||||
|
@extend .non-active-button
|
||||||
|
color #0B99F1
|
||||||
|
|
||||||
body[data-theme="dark"]
|
body[data-theme="dark"]
|
||||||
.root, .root--folded
|
.root, .root--folded
|
||||||
@@ -113,18 +145,21 @@ body[data-theme="dark"]
|
|||||||
.top
|
.top
|
||||||
border-color $ui-dark-borderColor
|
border-color $ui-dark-borderColor
|
||||||
|
|
||||||
.top-menu
|
.top-menu-preference
|
||||||
navDarkButtonColor()
|
navDarkButtonColor()
|
||||||
|
background-color transparent
|
||||||
&:active
|
&:active
|
||||||
background-color alpha($ui-dark-button--active-backgroundColor, 20%)
|
background-color alpha($ui-dark-button--active-backgroundColor, 20%)
|
||||||
|
background-color transparent
|
||||||
&:hover
|
&:hover
|
||||||
background-color alpha($ui-dark-button--active-backgroundColor, 20%)
|
background-color alpha($ui-dark-button--active-backgroundColor, 20%)
|
||||||
|
background-color transparent
|
||||||
|
|
||||||
.storageList-empty
|
.non-active-button
|
||||||
color $ui-dark-inactive-text-color
|
color alpha($ui-dark-text-color, 60%)
|
||||||
|
|
||||||
.navToggle
|
|
||||||
&:hover
|
&:hover
|
||||||
background-color alpha($ui-dark-button--active-backgroundColor, 20%)
|
color alpha(#0B99F1, 60%)
|
||||||
transition 0.15s
|
|
||||||
color $ui-dark-text-color
|
.tag-title
|
||||||
|
p
|
||||||
|
color alpha($ui-dark-text-color, 60%)
|
||||||
|
|||||||
@@ -226,9 +226,9 @@ class StorageItem extends React.Component {
|
|||||||
<button styleName='header-toggleButton'
|
<button styleName='header-toggleButton'
|
||||||
onMouseDown={(e) => this.handleToggleButtonClick(e)}
|
onMouseDown={(e) => this.handleToggleButtonClick(e)}
|
||||||
>
|
>
|
||||||
<i className={this.state.isOpen
|
<img src={this.state.isOpen
|
||||||
? 'fa fa-caret-down'
|
? '../resources/icon/icon-down.svg'
|
||||||
: 'fa fa-caret-right'
|
: '../resources/icon/icon-right.svg'
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
</button>
|
</button>
|
||||||
@@ -237,7 +237,7 @@ class StorageItem extends React.Component {
|
|||||||
<button styleName='header-addFolderButton'
|
<button styleName='header-addFolderButton'
|
||||||
onClick={(e) => this.handleAddFolderButtonClick(e)}
|
onClick={(e) => this.handleAddFolderButtonClick(e)}
|
||||||
>
|
>
|
||||||
<i className='fa fa-plus' />
|
<img styleName='iconTag' src='../resources/icon/icon-plus.svg' />
|
||||||
</button>
|
</button>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -5,27 +5,23 @@
|
|||||||
|
|
||||||
.header
|
.header
|
||||||
position relative
|
position relative
|
||||||
height 25px
|
height 36px
|
||||||
width 100%
|
width 100%
|
||||||
margin-bottom 5px
|
margin-bottom 5px
|
||||||
transition 0.15s
|
transition 0.15s
|
||||||
|
display flex
|
||||||
|
align-items center
|
||||||
|
|
||||||
.header--active
|
.header--active
|
||||||
margin-bottom 5px
|
margin-bottom 5px
|
||||||
background-color $ui-button--active-backgroundColor
|
background-color alpha($ui-button-default--active-backgroundColor, 20%)
|
||||||
transition color background-color 0.15s
|
transition color background-color 0.15s
|
||||||
|
display flex
|
||||||
.header--active
|
align-items center
|
||||||
.header-toggleButton
|
.header-toggleButton
|
||||||
color $ui-text-color
|
|
||||||
|
|
||||||
.header--active
|
|
||||||
.header-info
|
.header-info
|
||||||
color $ui-text-color
|
|
||||||
|
|
||||||
.header--active
|
|
||||||
.header-addFolderButton
|
.header-addFolderButton
|
||||||
color $ui-text-color
|
color #1EC38B
|
||||||
|
|
||||||
.header-toggleButton
|
.header-toggleButton
|
||||||
navButtonColor()
|
navButtonColor()
|
||||||
@@ -38,23 +34,31 @@
|
|||||||
border-radius 50%
|
border-radius 50%
|
||||||
&:hover
|
&:hover
|
||||||
transition 0.2s
|
transition 0.2s
|
||||||
background-color alpha($ui-button--active-backgroundColor, 40%)
|
background-color alpha($ui-button-default--hover-backgroundColor, 40%)
|
||||||
color $ui-text-color
|
color $ui-text-color
|
||||||
|
|
||||||
.header-info
|
.header-info
|
||||||
navButtonColor()
|
navButtonColor()
|
||||||
display block
|
display block
|
||||||
width 100%
|
width 100%
|
||||||
height 25px
|
height 36px
|
||||||
padding-left 23px
|
padding-left 25px
|
||||||
padding-right 10px
|
padding-right 15px
|
||||||
line-height 22px
|
line-height 22px
|
||||||
cursor pointer
|
cursor pointer
|
||||||
font-size 13px
|
font-size 14px
|
||||||
border none
|
border none
|
||||||
overflow ellipsis
|
overflow ellipsis
|
||||||
text-align left
|
text-align left
|
||||||
background-color alpha($ui-button--active-backgroundColor, 20%)
|
font-weight 600;
|
||||||
|
background-color transparent
|
||||||
|
&:hover
|
||||||
|
color #1EC38B
|
||||||
|
background-color alpha($ui-button-default--active-backgroundColor, 20%)
|
||||||
|
transition background-color 0.15s
|
||||||
|
&:active, &:active:hover
|
||||||
|
color #1EC38B
|
||||||
|
background-color alpha($ui-button-default--active-backgroundColor, 20%)
|
||||||
|
|
||||||
.header-info-path
|
.header-info-path
|
||||||
font-size 10px
|
font-size 10px
|
||||||
@@ -63,17 +67,14 @@
|
|||||||
.header-addFolderButton
|
.header-addFolderButton
|
||||||
navButtonColor()
|
navButtonColor()
|
||||||
position absolute
|
position absolute
|
||||||
right 0
|
right 7px
|
||||||
width 25px
|
width 25px
|
||||||
height 25px
|
height 25px
|
||||||
padding 0
|
padding 0
|
||||||
border none
|
border none
|
||||||
margin-right 5px
|
|
||||||
border-radius 50%
|
border-radius 50%
|
||||||
&:hover
|
&:hover
|
||||||
transition 0.2s
|
transition 0.2s
|
||||||
background-color alpha($ui-button--active-backgroundColor, 40%)
|
|
||||||
color $ui-text-color
|
|
||||||
|
|
||||||
.root--folded
|
.root--folded
|
||||||
@extend .root
|
@extend .root
|
||||||
@@ -102,6 +103,33 @@
|
|||||||
font-size 10px
|
font-size 10px
|
||||||
margin 0 5px
|
margin 0 5px
|
||||||
|
|
||||||
|
body[data-theme="white"]
|
||||||
|
.header--active
|
||||||
|
background-color $ui-button--active-backgroundColor
|
||||||
|
transition color background-color 0.15s
|
||||||
|
.header-toggleButton
|
||||||
|
color $ui-text-color
|
||||||
|
.header-info
|
||||||
|
color $ui-text-color
|
||||||
|
.header-addFolderButton
|
||||||
|
color $ui-text-color
|
||||||
|
|
||||||
|
.header-toggleButton
|
||||||
|
navWhiteButtonColor()
|
||||||
|
&:hover
|
||||||
|
background-color alpha($ui-button--active-backgroundColor, 40%)
|
||||||
|
color $ui-text-color
|
||||||
|
|
||||||
|
.header-info
|
||||||
|
navWhiteButtonColor()
|
||||||
|
background-color alpha($ui-button--active-backgroundColor, 20%)
|
||||||
|
|
||||||
|
.header-addFolderButton
|
||||||
|
navWhiteButtonColor()
|
||||||
|
&:hover
|
||||||
|
background-color alpha($ui-button--active-backgroundColor, 40%)
|
||||||
|
color $ui-text-color
|
||||||
|
|
||||||
body[data-theme="dark"]
|
body[data-theme="dark"]
|
||||||
.header--active
|
.header--active
|
||||||
background-color $ui-dark-button--active-backgroundColor
|
background-color $ui-dark-button--active-backgroundColor
|
||||||
|
|||||||
@@ -5,10 +5,23 @@ import { openModal } from 'browser/main/lib/modal'
|
|||||||
import PreferencesModal from '../modals/PreferencesModal'
|
import PreferencesModal from '../modals/PreferencesModal'
|
||||||
import ConfigManager from 'browser/main/lib/ConfigManager'
|
import ConfigManager from 'browser/main/lib/ConfigManager'
|
||||||
import StorageItem from './StorageItem'
|
import StorageItem from './StorageItem'
|
||||||
|
import TagListItem from 'browser/components/TagListItem'
|
||||||
import SideNavFilter from 'browser/components/SideNavFilter'
|
import SideNavFilter from 'browser/components/SideNavFilter'
|
||||||
|
import StorageList from 'browser/components/StorageList'
|
||||||
|
import NavToggleButton from 'browser/components/NavToggleButton'
|
||||||
|
import EventEmitter from 'browser/main/lib/eventEmitter'
|
||||||
|
|
||||||
class SideNav extends React.Component {
|
class SideNav extends React.Component {
|
||||||
// TODO: should not use electron stuff v0.7
|
// TODO: should not use electron stuff v0.7
|
||||||
|
|
||||||
|
componentDidMount () {
|
||||||
|
EventEmitter.on('side:preferences', this.handleMenuButtonClick)
|
||||||
|
}
|
||||||
|
|
||||||
|
componentWillUnmount () {
|
||||||
|
EventEmitter.off('side:preferences', this.handleMenuButtonClick)
|
||||||
|
}
|
||||||
|
|
||||||
handleMenuButtonClick (e) {
|
handleMenuButtonClick (e) {
|
||||||
openModal(PreferencesModal)
|
openModal(PreferencesModal)
|
||||||
}
|
}
|
||||||
@@ -38,13 +51,94 @@ class SideNav extends React.Component {
|
|||||||
router.push('/trashed')
|
router.push('/trashed')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
handleSwitchFoldersButtonClick () {
|
||||||
|
const { router } = this.context
|
||||||
|
router.push('/home')
|
||||||
|
}
|
||||||
|
|
||||||
|
handleSwitchTagsButtonClick () {
|
||||||
|
const { router } = this.context
|
||||||
|
router.push('/alltags')
|
||||||
|
}
|
||||||
|
|
||||||
|
SideNavComponent (isFolded, storageList) {
|
||||||
|
let { location, data } = this.props
|
||||||
|
|
||||||
|
const isHomeActive = !!location.pathname.match(/^\/home$/)
|
||||||
|
const isStarredActive = !!location.pathname.match(/^\/starred$/)
|
||||||
|
const isTrashedActive = !!location.pathname.match(/^\/trashed$/)
|
||||||
|
|
||||||
|
let component
|
||||||
|
|
||||||
|
// TagsMode is not selected
|
||||||
|
if (!location.pathname.match('/tags') && !location.pathname.match('/alltags')) {
|
||||||
|
component = (
|
||||||
|
<div>
|
||||||
|
<SideNavFilter
|
||||||
|
isFolded={isFolded}
|
||||||
|
isHomeActive={isHomeActive}
|
||||||
|
handleAllNotesButtonClick={(e) => this.handleHomeButtonClick(e)}
|
||||||
|
isStarredActive={isStarredActive}
|
||||||
|
isTrashedActive={isTrashedActive}
|
||||||
|
handleStarredButtonClick={(e) => this.handleStarredButtonClick(e)}
|
||||||
|
handleTrashedButtonClick={(e) => this.handleTrashedButtonClick(e)}
|
||||||
|
counterTotalNote={data.noteMap._map.size}
|
||||||
|
counterStarredNote={data.starredSet._set.size}
|
||||||
|
counterDelNote={data.trashedSet._set.size}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<StorageList storageList={storageList} />
|
||||||
|
<NavToggleButton isFolded={isFolded} handleToggleButtonClick={this.handleToggleButtonClick.bind(this)} />
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
component = (
|
||||||
|
<div styleName='tabBody'>
|
||||||
|
<div styleName='tag-title'>
|
||||||
|
<p>Tags</p>
|
||||||
|
</div>
|
||||||
|
<div styleName='tagList'>
|
||||||
|
{this.tagListComponent(data)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
return component
|
||||||
|
}
|
||||||
|
|
||||||
|
tagListComponent () {
|
||||||
|
const { data, location } = this.props
|
||||||
|
let tagList = data.tagNoteMap.map((tag, key) => {
|
||||||
|
return key
|
||||||
|
})
|
||||||
|
return (
|
||||||
|
tagList.map(tag => (
|
||||||
|
<TagListItem
|
||||||
|
name={tag}
|
||||||
|
handleClickTagListItem={this.handleClickTagListItem.bind(this)}
|
||||||
|
isActive={this.getTagActive(location.pathname, tag)}
|
||||||
|
key={tag}
|
||||||
|
/>
|
||||||
|
))
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
getTagActive (path, tag) {
|
||||||
|
const pathSegments = path.split('/')
|
||||||
|
const pathTag = pathSegments[pathSegments.length - 1]
|
||||||
|
return pathTag === tag
|
||||||
|
}
|
||||||
|
|
||||||
|
handleClickTagListItem (name) {
|
||||||
|
const { router } = this.context
|
||||||
|
router.push(`/tags/${name}`)
|
||||||
|
}
|
||||||
|
|
||||||
render () {
|
render () {
|
||||||
let { data, location, config, dispatch } = this.props
|
let { data, location, config, dispatch } = this.props
|
||||||
|
|
||||||
let isFolded = config.isSideNavFolded
|
let isFolded = config.isSideNavFolded
|
||||||
let isHomeActive = !!location.pathname.match(/^\/home$/)
|
|
||||||
let isStarredActive = !!location.pathname.match(/^\/starred$/)
|
|
||||||
let isTrashedActive = !!location.pathname.match(/^\/trashed$/)
|
|
||||||
|
|
||||||
let storageList = data.storageMap.map((storage, key) => {
|
let storageList = data.storageMap.map((storage, key) => {
|
||||||
return <StorageItem
|
return <StorageItem
|
||||||
@@ -58,6 +152,7 @@ class SideNav extends React.Component {
|
|||||||
})
|
})
|
||||||
let style = {}
|
let style = {}
|
||||||
if (!isFolded) style.width = this.props.width
|
if (!isFolded) style.width = this.props.width
|
||||||
|
const isTagActive = location.pathname.match(/tag/)
|
||||||
return (
|
return (
|
||||||
<div className='SideNav'
|
<div className='SideNav'
|
||||||
styleName={isFolded ? 'root--folded' : 'root'}
|
styleName={isFolded ? 'root--folded' : 'root'}
|
||||||
@@ -65,37 +160,31 @@ class SideNav extends React.Component {
|
|||||||
style={style}
|
style={style}
|
||||||
>
|
>
|
||||||
<div styleName='top'>
|
<div styleName='top'>
|
||||||
<button styleName='top-menu'
|
<div styleName='switch-buttons'>
|
||||||
onClick={(e) => this.handleMenuButtonClick(e)}
|
<button styleName={isTagActive ? 'non-active-button' : 'active-button'} onClick={this.handleSwitchFoldersButtonClick.bind(this)}>
|
||||||
>
|
<img src={isTagActive
|
||||||
<i className='fa fa-wrench fa-fw' />
|
? '../resources/icon/icon-list.svg'
|
||||||
<span styleName='top-menu-label'>Preferences</span>
|
: '../resources/icon/icon-list-active.svg'
|
||||||
</button>
|
}
|
||||||
|
/>
|
||||||
|
</button>
|
||||||
|
<button styleName={isTagActive ? 'active-button' : 'non-active-button'} onClick={this.handleSwitchTagsButtonClick.bind(this)}>
|
||||||
|
<img src={isTagActive
|
||||||
|
? '../resources/icon/icon-tag-active.svg'
|
||||||
|
: '../resources/icon/icon-tag.svg'
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<button styleName='top-menu-preference'
|
||||||
|
onClick={(e) => this.handleMenuButtonClick(e)}
|
||||||
|
>
|
||||||
|
<img styleName='iconTag' src='../resources/icon/icon-setting.svg' />
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
{this.SideNavComponent(isFolded, storageList)}
|
||||||
<SideNavFilter
|
|
||||||
isFolded={isFolded}
|
|
||||||
isHomeActive={isHomeActive}
|
|
||||||
handleAllNotesButtonClick={(e) => this.handleHomeButtonClick(e)}
|
|
||||||
isStarredActive={isStarredActive}
|
|
||||||
isTrashedActive={isTrashedActive}
|
|
||||||
handleStarredButtonClick={(e) => this.handleStarredButtonClick(e)}
|
|
||||||
handleTrashedButtonClick={(e) => this.handleTrashedButtonClick(e)}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<div styleName='storageList'>
|
|
||||||
{storageList.length > 0 ? storageList : (
|
|
||||||
<div styleName='storageList-empty'>No storage mount.</div>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
<button styleName='navToggle'
|
|
||||||
onClick={(e) => this.handleToggleButtonClick(e)}
|
|
||||||
>
|
|
||||||
{isFolded
|
|
||||||
? <i className='fa fa-angle-double-right' />
|
|
||||||
: <i className='fa fa-angle-double-left' />
|
|
||||||
}
|
|
||||||
</button>
|
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,11 +1,10 @@
|
|||||||
@import('../Detail/DetailVars')
|
@import('../Detail/DetailVars')
|
||||||
|
|
||||||
.root
|
.root
|
||||||
absolute bottom left right
|
position absolute
|
||||||
height $statusBar-height
|
bottom 10px
|
||||||
bottom 16px
|
right 10px
|
||||||
z-index 100
|
z-index 100
|
||||||
background-color $ui-noteDetail-backgroundColor
|
|
||||||
display flex
|
display flex
|
||||||
|
|
||||||
.blank
|
.blank
|
||||||
@@ -23,7 +22,18 @@
|
|||||||
|
|
||||||
.zoom
|
.zoom
|
||||||
navButtonColor()
|
navButtonColor()
|
||||||
height 24px
|
color rgba(0,0,0,.54)
|
||||||
|
height 20px
|
||||||
|
display flex
|
||||||
|
padding 0
|
||||||
|
align-items center
|
||||||
|
background-color transparent
|
||||||
|
&:hover
|
||||||
|
color $ui-active-color
|
||||||
|
&:active
|
||||||
|
color $ui-active-color
|
||||||
|
span
|
||||||
|
margin-left 5px
|
||||||
|
|
||||||
.update
|
.update
|
||||||
navButtonColor()
|
navButtonColor()
|
||||||
@@ -39,14 +49,14 @@
|
|||||||
|
|
||||||
body[data-theme="dark"]
|
body[data-theme="dark"]
|
||||||
.root
|
.root
|
||||||
background-color $ui-dark-noteDetail-backgroundColor
|
|
||||||
border-color $ui-dark-borderColor
|
border-color $ui-dark-borderColor
|
||||||
box-shadow none
|
box-shadow none
|
||||||
|
|
||||||
.zoom
|
.zoom
|
||||||
border-color $ui-dark-borderColor
|
border-color $ui-dark-borderColor
|
||||||
|
background-color transparent
|
||||||
|
color #f9f9f9
|
||||||
&:hover
|
&:hover
|
||||||
background-color alpha($ui-dark-button--active-backgroundColor, 20%)
|
|
||||||
transition 0.15s
|
transition 0.15s
|
||||||
color $ui-dark-text-color
|
color $ui-dark-text-color
|
||||||
|
|
||||||
|
|||||||
@@ -55,8 +55,8 @@ class StatusBar extends React.Component {
|
|||||||
<button styleName='zoom'
|
<button styleName='zoom'
|
||||||
onClick={(e) => this.handleZoomButtonClick(e)}
|
onClick={(e) => this.handleZoomButtonClick(e)}
|
||||||
>
|
>
|
||||||
<i className='fa fa-search-plus' />
|
<img src='../resources/icon/icon-zoom.svg' />
|
||||||
{Math.floor(config.zoom * 100)}%
|
<span>{Math.floor(config.zoom * 100)}%</span>
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
{status.updateReady
|
{status.updateReady
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ $control-height = 34px
|
|||||||
outline none
|
outline none
|
||||||
border none
|
border none
|
||||||
color $ui-text-color
|
color $ui-text-color
|
||||||
font-size 16px
|
font-size 18px
|
||||||
padding-bottom 2px
|
padding-bottom 2px
|
||||||
background-color $ui-noteList-backgroundColor
|
background-color $ui-noteList-backgroundColor
|
||||||
|
|
||||||
@@ -112,6 +112,21 @@ $control-height = 34px
|
|||||||
opacity 0
|
opacity 0
|
||||||
transition 0.1s
|
transition 0.1s
|
||||||
|
|
||||||
|
body[data-theme="white"]
|
||||||
|
.root, .root--expanded
|
||||||
|
background-color $ui-white-noteList-backgroundColor
|
||||||
|
|
||||||
|
.control
|
||||||
|
border-color $ui-dark-borderColor
|
||||||
|
|
||||||
|
.control-search
|
||||||
|
background-color $ui-white-noteList-backgroundColor
|
||||||
|
|
||||||
|
.control-search-input
|
||||||
|
background-color $ui-white-noteList-backgroundColor
|
||||||
|
input
|
||||||
|
background-color $ui-white-noteList-backgroundColor
|
||||||
|
|
||||||
body[data-theme="dark"]
|
body[data-theme="dark"]
|
||||||
.root, .root--expanded
|
.root, .root--expanded
|
||||||
background-color $ui-dark-noteList-backgroundColor
|
background-color $ui-dark-noteList-backgroundColor
|
||||||
|
|||||||
@@ -18,7 +18,10 @@ class TopBar extends React.Component {
|
|||||||
this.state = {
|
this.state = {
|
||||||
search: '',
|
search: '',
|
||||||
searchOptions: [],
|
searchOptions: [],
|
||||||
isSearching: false
|
isSearching: false,
|
||||||
|
isAlphabet: false,
|
||||||
|
isIME: false,
|
||||||
|
isConfirmTranslation: false
|
||||||
}
|
}
|
||||||
|
|
||||||
this.focusSearchHandler = () => {
|
this.focusSearchHandler = () => {
|
||||||
@@ -34,9 +37,52 @@ class TopBar extends React.Component {
|
|||||||
ee.off('top:focus-search', this.focusSearchHandler)
|
ee.off('top:focus-search', this.focusSearchHandler)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
handleKeyDown (e) {
|
||||||
|
// reset states
|
||||||
|
this.setState({
|
||||||
|
isAlphabet: false,
|
||||||
|
isIME: false
|
||||||
|
})
|
||||||
|
|
||||||
|
// When the key is an alphabet, del, enter or ctr
|
||||||
|
if (e.keyCode <= 90 || e.keyCode >= 186 && e.keyCode <= 222) {
|
||||||
|
this.setState({
|
||||||
|
isAlphabet: true
|
||||||
|
})
|
||||||
|
// When the key is an IME input (Japanese, Chinese)
|
||||||
|
} else if (e.keyCode === 229) {
|
||||||
|
this.setState({
|
||||||
|
isIME: true
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
handleKeyUp (e) {
|
||||||
|
const { router } = this.context
|
||||||
|
// reset states
|
||||||
|
this.setState({
|
||||||
|
isConfirmTranslation: false
|
||||||
|
})
|
||||||
|
|
||||||
|
// When the key is translation confirmation (Enter, Space)
|
||||||
|
if (this.state.isIME && (e.keyCode === 32 || e.keyCode === 13)) {
|
||||||
|
this.setState({
|
||||||
|
isConfirmTranslation: true
|
||||||
|
})
|
||||||
|
router.push('/searched')
|
||||||
|
this.setState({
|
||||||
|
search: this.refs.searchInput.value
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
handleSearchChange (e) {
|
handleSearchChange (e) {
|
||||||
let { router } = this.context
|
const { router } = this.context
|
||||||
router.push('/searched')
|
if (this.state.isAlphabet || this.state.isConfirmTranslation) {
|
||||||
|
router.push('/searched')
|
||||||
|
} else {
|
||||||
|
e.preventDefault()
|
||||||
|
}
|
||||||
this.setState({
|
this.setState({
|
||||||
search: this.refs.searchInput.value
|
search: this.refs.searchInput.value
|
||||||
})
|
})
|
||||||
@@ -93,6 +139,8 @@ class TopBar extends React.Component {
|
|||||||
ref='searchInput'
|
ref='searchInput'
|
||||||
value={this.state.search}
|
value={this.state.search}
|
||||||
onChange={(e) => this.handleSearchChange(e)}
|
onChange={(e) => this.handleSearchChange(e)}
|
||||||
|
onKeyDown={(e) => this.handleKeyDown(e)}
|
||||||
|
onKeyUp={(e) => this.handleKeyUp(e)}
|
||||||
placeholder='Search'
|
placeholder='Search'
|
||||||
type='text'
|
type='text'
|
||||||
className='searchInput'
|
className='searchInput'
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ body
|
|||||||
color textColor
|
color textColor
|
||||||
font-size fontSize
|
font-size fontSize
|
||||||
font-weight 200
|
font-weight 200
|
||||||
|
-webkit-font-smoothing antialiased
|
||||||
|
|
||||||
button, input, select, textarea
|
button, input, select, textarea
|
||||||
font-family DEFAULT_FONTS
|
font-family DEFAULT_FONTS
|
||||||
@@ -102,3 +103,10 @@ body[data-theme="dark"]
|
|||||||
background #B1D7FE
|
background #B1D7FE
|
||||||
::selection
|
::selection
|
||||||
background #B1D7FE
|
background #B1D7FE
|
||||||
|
|
||||||
|
.sortableItemHelper
|
||||||
|
z-index modalZIndex + 5
|
||||||
|
|
||||||
|
body[data-theme="dark"]
|
||||||
|
.sortableItemHelper
|
||||||
|
color: $ui-dark-text-color
|
||||||
|
|||||||
@@ -27,7 +27,10 @@ document.addEventListener('click', function (e) {
|
|||||||
const className = e.target.className
|
const className = e.target.className
|
||||||
if (!className && typeof (className) !== 'string') return
|
if (!className && typeof (className) !== 'string') return
|
||||||
const isInfoButton = className.includes('infoButton')
|
const isInfoButton = className.includes('infoButton')
|
||||||
const isInfoPanel = e.target.offsetParent.className.includes('infoPanel')
|
const offsetParent = e.target.offsetParent
|
||||||
|
const isInfoPanel = offsetParent !== null
|
||||||
|
? offsetParent.className.includes('infoPanel')
|
||||||
|
: false
|
||||||
if (isInfoButton || isInfoPanel) return
|
if (isInfoButton || isInfoPanel) return
|
||||||
const infoPanel = document.querySelector('.infoPanel')
|
const infoPanel = document.querySelector('.infoPanel')
|
||||||
if (infoPanel) infoPanel.style.display = 'none'
|
if (infoPanel) infoPanel.style.display = 'none'
|
||||||
@@ -62,6 +65,11 @@ ReactDOM.render((
|
|||||||
<Route path='starred' />
|
<Route path='starred' />
|
||||||
<Route path='searched' />
|
<Route path='searched' />
|
||||||
<Route path='trashed' />
|
<Route path='trashed' />
|
||||||
|
<Route path='alltags' />
|
||||||
|
<Route path='tags'>
|
||||||
|
<IndexRedirect to='/alltags' />
|
||||||
|
<Route path=':tagname' />
|
||||||
|
</Route>
|
||||||
<Route path='storages'>
|
<Route path='storages'>
|
||||||
<IndexRedirect to='/home' />
|
<IndexRedirect to='/home' />
|
||||||
<Route path=':storageKey'>
|
<Route path=':storageKey'>
|
||||||
|
|||||||
@@ -2,17 +2,37 @@ const AWS = require('aws-sdk')
|
|||||||
const AMA = require('aws-sdk-mobile-analytics')
|
const AMA = require('aws-sdk-mobile-analytics')
|
||||||
const ConfigManager = require('browser/main/lib/ConfigManager')
|
const ConfigManager = require('browser/main/lib/ConfigManager')
|
||||||
|
|
||||||
|
const remote = require('electron').remote
|
||||||
|
const os = require('os')
|
||||||
|
|
||||||
AWS.config.region = 'us-east-1'
|
AWS.config.region = 'us-east-1'
|
||||||
if (process.env.NODE_ENV === 'production' && ConfigManager.default.get().amaEnabled) {
|
if (process.env.NODE_ENV === 'production' && ConfigManager.default.get().amaEnabled) {
|
||||||
AWS.config.credentials = new AWS.CognitoIdentityCredentials({
|
AWS.config.credentials = new AWS.CognitoIdentityCredentials({
|
||||||
IdentityPoolId: 'us-east-1:xxxxxxxxxxxxxxxxxxxxxxxxx'
|
IdentityPoolId: 'us-east-1:xxxxxxxxxxxxxxxxxxxxxxxxx'
|
||||||
})
|
})
|
||||||
|
|
||||||
|
const validPlatformName = convertPlatformName(os.platform())
|
||||||
|
|
||||||
const mobileAnalyticsClient = new AMA.Manager({
|
const mobileAnalyticsClient = new AMA.Manager({
|
||||||
appId: 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxx',
|
appId: 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxx',
|
||||||
appTitle: 'xxxxxxxxxx'
|
appTitle: 'xxxxxxxxxx',
|
||||||
|
appVersionName: remote.app.getVersion().toString(),
|
||||||
|
platform: validPlatformName
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function convertPlatformName (platformName) {
|
||||||
|
if (platformName === 'darwin') {
|
||||||
|
return 'MacOS'
|
||||||
|
} else if (platformName === 'win32') {
|
||||||
|
return 'Windows'
|
||||||
|
} else if (platformName === 'linux') {
|
||||||
|
return 'Linux'
|
||||||
|
} else {
|
||||||
|
return ''
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function initAwsMobileAnalytics () {
|
function initAwsMobileAnalytics () {
|
||||||
if (process.env.NODE_ENV !== 'production' || !ConfigManager.default.get().amaEnabled) return
|
if (process.env.NODE_ENV !== 'production' || !ConfigManager.default.get().amaEnabled) return
|
||||||
AWS.config.credentials.get((err) => {
|
AWS.config.credentials.get((err) => {
|
||||||
@@ -24,16 +44,28 @@ function initAwsMobileAnalytics () {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
function recordDynamicCustomEvent (type) {
|
function recordDynamicCustomEvent (type, options = {}) {
|
||||||
if (process.env.NODE_ENV !== 'production' || !ConfigManager.default.get().amaEnabled) return
|
if (process.env.NODE_ENV !== 'production' || !ConfigManager.default.get().amaEnabled) return
|
||||||
mobileAnalyticsClient.recordEvent(type)
|
try {
|
||||||
|
mobileAnalyticsClient.recordEvent(type, options)
|
||||||
|
} catch (analyticsError) {
|
||||||
|
if (analyticsError instanceof ReferenceError) {
|
||||||
|
console.log(analyticsError.name + ': ' + analyticsError.message)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function recordStaticCustomEvent () {
|
function recordStaticCustomEvent () {
|
||||||
if (process.env.NODE_ENV !== 'production' || !ConfigManager.default.get().amaEnabled) return
|
if (process.env.NODE_ENV !== 'production' || !ConfigManager.default.get().amaEnabled) return
|
||||||
mobileAnalyticsClient.recordEvent('UI_COLOR_THEME', {
|
try {
|
||||||
uiColorTheme: ConfigManager.default.get().ui.theme
|
mobileAnalyticsClient.recordEvent('UI_COLOR_THEME', {
|
||||||
})
|
uiColorTheme: ConfigManager.default.get().ui.theme
|
||||||
|
})
|
||||||
|
} catch (analyticsError) {
|
||||||
|
if (analyticsError instanceof ReferenceError) {
|
||||||
|
console.log(analyticsError.name + ': ' + analyticsError.message)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ export const DEFAULT_CONFIG = {
|
|||||||
},
|
},
|
||||||
ui: {
|
ui: {
|
||||||
theme: 'default',
|
theme: 'default',
|
||||||
|
showCopyNotification: true,
|
||||||
disableDirectWrite: false,
|
disableDirectWrite: false,
|
||||||
defaultNote: 'ALWAYS_ASK' // 'ALWAYS_ASK', 'SNIPPET_NOTE', 'MARKDOWN_NOTE'
|
defaultNote: 'ALWAYS_ASK' // 'ALWAYS_ASK', 'SNIPPET_NOTE', 'MARKDOWN_NOTE'
|
||||||
},
|
},
|
||||||
@@ -90,7 +91,11 @@ function get () {
|
|||||||
: 'default'
|
: 'default'
|
||||||
|
|
||||||
if (config.editor.theme !== 'default') {
|
if (config.editor.theme !== 'default') {
|
||||||
editorTheme.setAttribute('href', '../node_modules/codemirror/theme/' + config.editor.theme + '.css')
|
if (config.editor.theme.startsWith('solarized')) {
|
||||||
|
editorTheme.setAttribute('href', '../node_modules/codemirror/theme/solarized.css')
|
||||||
|
} else {
|
||||||
|
editorTheme.setAttribute('href', '../node_modules/codemirror/theme/' + config.editor.theme + '.css')
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -105,6 +110,8 @@ function set (updates) {
|
|||||||
|
|
||||||
if (newConfig.ui.theme === 'dark') {
|
if (newConfig.ui.theme === 'dark') {
|
||||||
document.body.setAttribute('data-theme', 'dark')
|
document.body.setAttribute('data-theme', 'dark')
|
||||||
|
} else if (newConfig.ui.theme === 'white') {
|
||||||
|
document.body.setAttribute('data-theme', 'white')
|
||||||
} else {
|
} else {
|
||||||
document.body.setAttribute('data-theme', 'default')
|
document.body.setAttribute('data-theme', 'default')
|
||||||
}
|
}
|
||||||
@@ -121,7 +128,11 @@ function set (updates) {
|
|||||||
: 'default'
|
: 'default'
|
||||||
|
|
||||||
if (newTheme !== 'default') {
|
if (newTheme !== 'default') {
|
||||||
editorTheme.setAttribute('href', '../node_modules/codemirror/theme/' + newTheme + '.css')
|
if (newTheme.startsWith('solarized')) {
|
||||||
|
editorTheme.setAttribute('href', '../node_modules/codemirror/theme/solarized.css')
|
||||||
|
} else {
|
||||||
|
editorTheme.setAttribute('href', '../node_modules/codemirror/theme/' + newTheme + '.css')
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ipcRenderer.send('config-renew', {
|
ipcRenderer.send('config-renew', {
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ const dataApi = {
|
|||||||
createFolder: require('./createFolder'),
|
createFolder: require('./createFolder'),
|
||||||
updateFolder: require('./updateFolder'),
|
updateFolder: require('./updateFolder'),
|
||||||
deleteFolder: require('./deleteFolder'),
|
deleteFolder: require('./deleteFolder'),
|
||||||
|
reorderFolder: require('./reorderFolder'),
|
||||||
createNote: require('./createNote'),
|
createNote: require('./createNote'),
|
||||||
updateNote: require('./updateNote'),
|
updateNote: require('./updateNote'),
|
||||||
deleteNote: require('./deleteNote'),
|
deleteNote: require('./deleteNote'),
|
||||||
|
|||||||
43
browser/main/lib/dataApi/reorderFolder.js
Normal file
43
browser/main/lib/dataApi/reorderFolder.js
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
const _ = require('lodash')
|
||||||
|
_.move = require('lodash-move').default
|
||||||
|
const path = require('path')
|
||||||
|
const resolveStorageData = require('./resolveStorageData')
|
||||||
|
const CSON = require('@rokt33r/season')
|
||||||
|
const { findStorage } = require('browser/lib/findStorage')
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {String} storageKey
|
||||||
|
* @param {number} oldIndex
|
||||||
|
* @param {number} newIndex
|
||||||
|
*
|
||||||
|
* @return {Object}
|
||||||
|
* ```
|
||||||
|
* {
|
||||||
|
* storage: Object
|
||||||
|
* }
|
||||||
|
* ```
|
||||||
|
*/
|
||||||
|
function reorderFolder (storageKey, oldIndex, newIndex) {
|
||||||
|
let rawStorages
|
||||||
|
let targetStorage
|
||||||
|
try {
|
||||||
|
if (!_.isNumber(oldIndex)) throw new Error('oldIndex must be a number.')
|
||||||
|
if (!_.isNumber(newIndex)) throw new Error('newIndex must be a number.')
|
||||||
|
|
||||||
|
targetStorage = findStorage(storageKey)
|
||||||
|
} catch (e) {
|
||||||
|
return Promise.reject(e)
|
||||||
|
}
|
||||||
|
|
||||||
|
return resolveStorageData(targetStorage)
|
||||||
|
.then(function reorderFolder (storage) {
|
||||||
|
storage.folders = _.move(storage.folders, oldIndex, newIndex)
|
||||||
|
CSON.writeFileSync(path.join(storage.path, 'boostnote.json'), _.pick(storage, ['folders', 'version']))
|
||||||
|
|
||||||
|
return {
|
||||||
|
storage
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = reorderFolder
|
||||||
@@ -2,6 +2,7 @@ const _ = require('lodash')
|
|||||||
const path = require('path')
|
const path = require('path')
|
||||||
const resolveStorageData = require('./resolveStorageData')
|
const resolveStorageData = require('./resolveStorageData')
|
||||||
const CSON = require('@rokt33r/season')
|
const CSON = require('@rokt33r/season')
|
||||||
|
const { findStorage } = require('browser/lib/findStorage')
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {String} storageKey
|
* @param {String} storageKey
|
||||||
@@ -29,11 +30,7 @@ function updateFolder (storageKey, folderKey, input) {
|
|||||||
if (!_.isString(input.name)) throw new Error('Name must be a string.')
|
if (!_.isString(input.name)) throw new Error('Name must be a string.')
|
||||||
if (!_.isString(input.color)) throw new Error('Color must be a string.')
|
if (!_.isString(input.color)) throw new Error('Color must be a string.')
|
||||||
|
|
||||||
rawStorages = JSON.parse(localStorage.getItem('storages'))
|
targetStorage = findStorage(storageKey)
|
||||||
if (!_.isArray(rawStorages)) throw new Error('Target storage doesn\'t exist.')
|
|
||||||
|
|
||||||
targetStorage = _.find(rawStorages, {key: storageKey})
|
|
||||||
if (targetStorage == null) throw new Error('Target storage doesn\'t exist.')
|
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
return Promise.reject(e)
|
return Promise.reject(e)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -26,6 +26,10 @@ function validateInput (input) {
|
|||||||
validatedInput.isTrashed = !!input.isTrashed
|
validatedInput.isTrashed = !!input.isTrashed
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (input.isPinned !== undefined) {
|
||||||
|
validatedInput.isPinned = !!input.isPinned
|
||||||
|
}
|
||||||
|
|
||||||
validatedInput.type = input.type
|
validatedInput.type = input.type
|
||||||
switch (input.type) {
|
switch (input.type) {
|
||||||
case 'MARKDOWN_NOTE':
|
case 'MARKDOWN_NOTE':
|
||||||
@@ -104,6 +108,7 @@ function updateNote (storageKey, noteKey, input) {
|
|||||||
noteData.isStarred = false
|
noteData.isStarred = false
|
||||||
noteData.isTrashed = false
|
noteData.isTrashed = false
|
||||||
noteData.tags = []
|
noteData.tags = []
|
||||||
|
noteData.isPinned = false
|
||||||
}
|
}
|
||||||
|
|
||||||
if (noteData.type === 'SNIPPET_NOTE') {
|
if (noteData.type === 'SNIPPET_NOTE') {
|
||||||
|
|||||||
@@ -1,121 +0,0 @@
|
|||||||
import store from 'browser/main/store'
|
|
||||||
|
|
||||||
const _ = require('lodash')
|
|
||||||
const keygen = require('browser/lib/keygen')
|
|
||||||
const Mixpanel = require('mixpanel')
|
|
||||||
const mixpanel = Mixpanel.init('7a0aca437d72dfd07cbcbf58d3b61f27', {key: 'fde4fd23f4d550f1b646bcd7d4374b1f'})
|
|
||||||
const moment = require('moment')
|
|
||||||
const electron = require('electron')
|
|
||||||
|
|
||||||
function _getClientKey () {
|
|
||||||
let clientKey = localStorage.getItem('clientKey')
|
|
||||||
if (!_.isString(clientKey) || clientKey.length !== 40) {
|
|
||||||
clientKey = keygen(20)
|
|
||||||
_setClientKey(clientKey)
|
|
||||||
}
|
|
||||||
|
|
||||||
return clientKey
|
|
||||||
}
|
|
||||||
|
|
||||||
function _setClientKey (newKey) {
|
|
||||||
localStorage.setItem('clientKey', newKey)
|
|
||||||
}
|
|
||||||
|
|
||||||
function _fetch () {
|
|
||||||
let events
|
|
||||||
try {
|
|
||||||
events = JSON.parse(localStorage.getItem('events'))
|
|
||||||
if (!_.isArray(events)) throw new Error('events is not an array.')
|
|
||||||
} catch (err) {
|
|
||||||
console.warn(err)
|
|
||||||
events = []
|
|
||||||
localStorage.setItem('events', JSON.stringify(events))
|
|
||||||
console.info('Events cache initialzed')
|
|
||||||
}
|
|
||||||
return events
|
|
||||||
}
|
|
||||||
|
|
||||||
function _keep (name, properties) {
|
|
||||||
let events = _fetch()
|
|
||||||
properties.time = new Date()
|
|
||||||
events.push({
|
|
||||||
name,
|
|
||||||
properties
|
|
||||||
})
|
|
||||||
localStorage.setItem('events', JSON.stringify(events))
|
|
||||||
}
|
|
||||||
|
|
||||||
function _keepUnique (name, properties) {
|
|
||||||
let events = _fetch()
|
|
||||||
properties.time = new Date()
|
|
||||||
events = events.filter((event) => event.name !== name)
|
|
||||||
events.push({
|
|
||||||
name,
|
|
||||||
properties
|
|
||||||
})
|
|
||||||
localStorage.setItem('events', JSON.stringify(events))
|
|
||||||
}
|
|
||||||
|
|
||||||
function _flush () {
|
|
||||||
let events = _fetch()
|
|
||||||
let spliced = events.splice(0, 50)
|
|
||||||
localStorage.setItem('events', JSON.stringify(events))
|
|
||||||
|
|
||||||
if (spliced.length > 0) {
|
|
||||||
let parsedEvents = spliced
|
|
||||||
.filter((event) => {
|
|
||||||
if (!_.isObject(event)) return false
|
|
||||||
if (!_.isString(event.name)) return false
|
|
||||||
if (!_.isObject(event.properties)) return false
|
|
||||||
if (!moment(event.properties.time).isValid()) return false
|
|
||||||
if (new Date() - moment(event.properties.time).toDate() > 1000 * 3600 * 24 * 3) return false
|
|
||||||
return true
|
|
||||||
})
|
|
||||||
.map((event) => {
|
|
||||||
return {
|
|
||||||
event: event.name,
|
|
||||||
properties: event.properties
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
mixpanel.import_batch(parsedEvents, {}, (errs) => {
|
|
||||||
if (errs.length > 0) {
|
|
||||||
let events = _fetch()
|
|
||||||
events = events.concat(spliced)
|
|
||||||
localStorage.setItem('events', JSON.stringify(events))
|
|
||||||
} else {
|
|
||||||
_flush()
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
let state = store.getState()
|
|
||||||
mixpanel.people.set(_getClientKey(), {
|
|
||||||
storage_count: state.data.storageMap.size,
|
|
||||||
note_count: state.data.noteMap.size,
|
|
||||||
version: electron.remote.app.getVersion()
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
setInterval(_flush, 1000 * 60 * 60)
|
|
||||||
|
|
||||||
function track (name, properties) {
|
|
||||||
switch (name) {
|
|
||||||
case 'MAIN_FOCUSED':
|
|
||||||
properties = Object.assign({}, properties, {
|
|
||||||
distinct_id: _getClientKey()
|
|
||||||
})
|
|
||||||
_keepUnique(name, properties)
|
|
||||||
break
|
|
||||||
default:
|
|
||||||
properties = Object.assign({}, properties, {
|
|
||||||
distinct_id: _getClientKey()
|
|
||||||
})
|
|
||||||
_keep(name, properties)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
_mp: mixpanel,
|
|
||||||
track
|
|
||||||
}
|
|
||||||
@@ -152,7 +152,7 @@ class InitModal extends React.Component {
|
|||||||
type: 'MARKDOWN_NOTE',
|
type: 'MARKDOWN_NOTE',
|
||||||
folder: data.storage.folders[0].key,
|
folder: data.storage.folders[0].key,
|
||||||
title: 'Welcome to Boostnote!',
|
title: 'Welcome to Boostnote!',
|
||||||
content: '# Welcome to Boostnote! \n### _Click to edit this note._\n\n---\n\nBoostnote is an *open source* note-taking app. \nRepository is published on [GitHub](https://github.com/BoostIO/Boostnote), and tweeting everyday on [@Boostnoteapp](https://twitter.com/boostnoteapp)!\n\n## Features \n- [x] No Internet and Registration Required. \n- [ ] Quick search and copy the content of note. `macOS: Cmd + Alt + S / windows: Ctrl + Alt + S` \n- [ ] Markdown & Snippet note. \n- [ ] Available for `vim` and `emacs` mode. \n- [ ] Choose your favorite theme on UI, Editor and Code Block! \n--- \n\n- Copy Codeblock on Markdown Preview.\n```javascript\nvar boostnote = document.getElementById(\'enjoy\').innerHTML\n\nconsole.log(boostnote)\n```'
|
content: '# Welcome to Boostnote!\n## Click here to edit markdown :wave:\n\n<iframe width="560" height="315" src="https://www.youtube.com/embed/L0qNPLsvmyM" frameborder="0" allowfullscreen></iframe>\n\n## Docs :memo:\n- [Boostnote | Boost your happiness, productivity and creativity.](https://hackernoon.com/boostnote-boost-your-happiness-productivity-and-creativity-315034efeebe)\n- [Cloud Syncing & Backups](https://github.com/BoostIO/Boostnote/wiki/Cloud-Syncing-and-Backup)\n- [How to sync your data across Desktop and Mobile apps](https://github.com/BoostIO/Boostnote/wiki/Sync-Data-Across-Desktop-and-Mobile-apps)\n- [Convert data from **Evernote** to Boostnote.](https://github.com/BoostIO/Boostnote/wiki/Evernote)\n- [Keyboard Shortcuts](https://github.com/BoostIO/Boostnote/wiki/Keyboard-Shortcuts)\n- [Keymaps in Editor mode](https://github.com/BoostIO/Boostnote/wiki/Keymaps-in-Editor-mode)\n- [How to set syntax highlight in Snippet note](https://github.com/BoostIO/Boostnote/wiki/Syntax-Highlighting)\n\n---\n\n## Article Archive :books:\n- [Reddit English](http://bit.ly/2mOJPu7)\n- [Reddit Spanish](https://www.reddit.com/r/boostnote_es/)\n- [Reddit Chinese](https://www.reddit.com/r/boostnote_cn/)\n- [Reddit Japanese](https://www.reddit.com/r/boostnote_jp/)\n\n---\n\n## Community :beers:\n- [GitHub](http://bit.ly/2AWWzkD)\n- [Twitter](http://bit.ly/2z8BUJZ)\n- [Facebook Group](http://bit.ly/2jcca8t)'
|
||||||
})
|
})
|
||||||
.then((note) => {
|
.then((note) => {
|
||||||
store.dispatch({
|
store.dispatch({
|
||||||
@@ -194,13 +194,13 @@ class InitModal extends React.Component {
|
|||||||
return (
|
return (
|
||||||
<div styleName='root'
|
<div styleName='root'
|
||||||
tabIndex='-1'
|
tabIndex='-1'
|
||||||
onKeyDown={(e) => this.handleKeyDown(e)}
|
onKeyDown={this.props.close}
|
||||||
>
|
>
|
||||||
|
|
||||||
<div styleName='header'>
|
<div styleName='header'>
|
||||||
<div styleName='header-title'>Initialize Storage</div>
|
<div styleName='header-title'>Initialize Storage</div>
|
||||||
</div>
|
</div>
|
||||||
<ModalEscButton handleEscButtonClick={(e) => this.handleCloseButtonClick(e)} />
|
<ModalEscButton handleEscButtonClick={this.props.close} />
|
||||||
<div styleName='body'>
|
<div styleName='body'>
|
||||||
<div styleName='body-welcome'>
|
<div styleName='body-welcome'>
|
||||||
Welcome!
|
Welcome!
|
||||||
|
|||||||
@@ -67,10 +67,17 @@
|
|||||||
text-align right
|
text-align right
|
||||||
:global
|
:global
|
||||||
.alert
|
.alert
|
||||||
font-size 12px
|
display inline-block
|
||||||
line-height 30px
|
position absolute
|
||||||
padding 0 5px
|
top 60px
|
||||||
float right
|
right 15px
|
||||||
|
font-size 14px
|
||||||
|
.success
|
||||||
|
color #1EC38B
|
||||||
|
.error
|
||||||
|
color red
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
.group-control-leftButton
|
.group-control-leftButton
|
||||||
colorDefaultButton()
|
colorDefaultButton()
|
||||||
@@ -108,7 +115,6 @@
|
|||||||
line-height 1.2
|
line-height 1.2
|
||||||
|
|
||||||
.note-for-keymap
|
.note-for-keymap
|
||||||
margin-left: 10px
|
|
||||||
font-size: 12px
|
font-size: 12px
|
||||||
|
|
||||||
.code-mirror
|
.code-mirror
|
||||||
|
|||||||
49
browser/main/modals/PreferencesModal/Crowdfunding.js
Normal file
49
browser/main/modals/PreferencesModal/Crowdfunding.js
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
import React from 'react'
|
||||||
|
import CSSModules from 'browser/lib/CSSModules'
|
||||||
|
import styles from './Crowdfunding.styl'
|
||||||
|
|
||||||
|
const electron = require('electron')
|
||||||
|
const { shell } = electron
|
||||||
|
|
||||||
|
class Crowdfunding extends React.Component {
|
||||||
|
constructor (props) {
|
||||||
|
super(props)
|
||||||
|
|
||||||
|
this.state = {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
handleLinkClick (e) {
|
||||||
|
shell.openExternal(e.currentTarget.href)
|
||||||
|
e.preventDefault()
|
||||||
|
}
|
||||||
|
|
||||||
|
render () {
|
||||||
|
return (
|
||||||
|
<div styleName='root'>
|
||||||
|
<div styleName='header'>Crowdfunding</div>
|
||||||
|
<p>Dear all,</p>
|
||||||
|
<br />
|
||||||
|
<p>Thanks for your using!</p>
|
||||||
|
<p>Boostnote is used in about 200 countries and regions, it is a awesome developer community.</p>
|
||||||
|
<br />
|
||||||
|
<p>To continue supporting this growth, and to satisfy community expectations,</p>
|
||||||
|
<p>we would like to invest more time in this project.</p>
|
||||||
|
<br />
|
||||||
|
<p>If you like this project and see its potential, you can help!</p>
|
||||||
|
<br />
|
||||||
|
<p>Thanks,</p>
|
||||||
|
<p>Boostnote maintainers.</p>
|
||||||
|
<br />
|
||||||
|
<button styleName='cf-link'>
|
||||||
|
<a href='https://opencollective.com/boostnoteio' onClick={(e) => this.handleLinkClick(e)}>Support via OpenCollective</a>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Crowdfunding.propTypes = {
|
||||||
|
}
|
||||||
|
|
||||||
|
export default CSSModules(Crowdfunding, styles)
|
||||||
30
browser/main/modals/PreferencesModal/Crowdfunding.styl
Normal file
30
browser/main/modals/PreferencesModal/Crowdfunding.styl
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
@import('./Tab')
|
||||||
|
|
||||||
|
.root
|
||||||
|
padding 15px
|
||||||
|
white-space pre
|
||||||
|
line-height 1.4
|
||||||
|
color alpha($ui-text-color, 90%)
|
||||||
|
width 100%
|
||||||
|
font-size 14px
|
||||||
|
p
|
||||||
|
font-size 16px
|
||||||
|
|
||||||
|
.cf-link
|
||||||
|
width 250px
|
||||||
|
height 35px
|
||||||
|
border-radius 2px
|
||||||
|
border none
|
||||||
|
background-color alpha(#1EC38B, 90%)
|
||||||
|
&:hover
|
||||||
|
background-color #1EC38B
|
||||||
|
transition 0.2s
|
||||||
|
a
|
||||||
|
text-decoration none
|
||||||
|
color white
|
||||||
|
font-weight 600
|
||||||
|
font-size 16px
|
||||||
|
|
||||||
|
body[data-theme="dark"]
|
||||||
|
p
|
||||||
|
color $ui-dark-text-color
|
||||||
303
browser/main/modals/PreferencesModal/FolderItem.js
Normal file
303
browser/main/modals/PreferencesModal/FolderItem.js
Normal file
@@ -0,0 +1,303 @@
|
|||||||
|
import React, { PropTypes } from 'react'
|
||||||
|
import CSSModules from 'browser/lib/CSSModules'
|
||||||
|
import ReactDOM from 'react-dom'
|
||||||
|
import styles from './FolderItem.styl'
|
||||||
|
import dataApi from 'browser/main/lib/dataApi'
|
||||||
|
import store from 'browser/main/store'
|
||||||
|
import { SketchPicker } from 'react-color'
|
||||||
|
import { SortableElement, SortableHandle } from 'react-sortable-hoc'
|
||||||
|
|
||||||
|
class FolderItem extends React.Component {
|
||||||
|
constructor (props) {
|
||||||
|
super(props)
|
||||||
|
|
||||||
|
this.state = {
|
||||||
|
status: 'IDLE',
|
||||||
|
folder: {
|
||||||
|
showColumnPicker: false,
|
||||||
|
colorPickerPos: { left: 0, top: 0 },
|
||||||
|
color: props.color,
|
||||||
|
name: props.name
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
handleEditChange (e) {
|
||||||
|
let { folder } = this.state
|
||||||
|
|
||||||
|
folder.name = this.refs.nameInput.value
|
||||||
|
this.setState({
|
||||||
|
folder
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
handleConfirmButtonClick (e) {
|
||||||
|
this.confirm()
|
||||||
|
}
|
||||||
|
|
||||||
|
confirm () {
|
||||||
|
let { storage, folder } = this.props
|
||||||
|
dataApi
|
||||||
|
.updateFolder(storage.key, folder.key, {
|
||||||
|
color: this.state.folder.color,
|
||||||
|
name: this.state.folder.name
|
||||||
|
})
|
||||||
|
.then((data) => {
|
||||||
|
store.dispatch({
|
||||||
|
type: 'UPDATE_FOLDER',
|
||||||
|
storage: data.storage
|
||||||
|
})
|
||||||
|
this.setState({
|
||||||
|
status: 'IDLE'
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
handleColorButtonClick (e) {
|
||||||
|
const folder = Object.assign({}, this.state.folder, { showColumnPicker: true, colorPickerPos: { left: 0, top: 0 } })
|
||||||
|
this.setState({ folder }, function () {
|
||||||
|
// After the color picker has been painted, re-calculate its position
|
||||||
|
// by comparing its dimensions to the host dimensions.
|
||||||
|
const { hostBoundingBox } = this.props
|
||||||
|
const colorPickerNode = ReactDOM.findDOMNode(this.refs.colorPicker)
|
||||||
|
const colorPickerBox = colorPickerNode.getBoundingClientRect()
|
||||||
|
const offsetTop = hostBoundingBox.bottom - colorPickerBox.bottom
|
||||||
|
const folder = Object.assign({}, this.state.folder, {
|
||||||
|
colorPickerPos: {
|
||||||
|
left: 25,
|
||||||
|
top: offsetTop < 0 ? offsetTop - 5 : 0 // subtract 5px for aestetics
|
||||||
|
}
|
||||||
|
})
|
||||||
|
this.setState({ folder })
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
handleColorChange (color) {
|
||||||
|
const folder = Object.assign({}, this.state.folder, { color: color.hex })
|
||||||
|
this.setState({ folder })
|
||||||
|
}
|
||||||
|
|
||||||
|
handleColorPickerClose (event) {
|
||||||
|
const folder = Object.assign({}, this.state.folder, { showColumnPicker: false })
|
||||||
|
this.setState({ folder })
|
||||||
|
}
|
||||||
|
|
||||||
|
handleCancelButtonClick (e) {
|
||||||
|
this.setState({
|
||||||
|
status: 'IDLE'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
handleFolderItemBlur (e) {
|
||||||
|
let el = e.relatedTarget
|
||||||
|
while (el != null) {
|
||||||
|
if (el === this.refs.root) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
el = el.parentNode
|
||||||
|
}
|
||||||
|
this.confirm()
|
||||||
|
}
|
||||||
|
|
||||||
|
renderEdit (e) {
|
||||||
|
const popover = { position: 'absolute', zIndex: 2 }
|
||||||
|
const cover = {
|
||||||
|
position: 'fixed',
|
||||||
|
top: 0,
|
||||||
|
right: 0,
|
||||||
|
bottom: 0,
|
||||||
|
left: 0
|
||||||
|
}
|
||||||
|
const pickerStyle = Object.assign({}, {
|
||||||
|
position: 'absolute'
|
||||||
|
}, this.state.folder.colorPickerPos)
|
||||||
|
return (
|
||||||
|
<div styleName='folderItem'
|
||||||
|
onBlur={(e) => this.handleFolderItemBlur(e)}
|
||||||
|
tabIndex='-1'
|
||||||
|
ref='root'
|
||||||
|
>
|
||||||
|
<div styleName='folderItem-left'>
|
||||||
|
<button styleName='folderItem-left-colorButton' style={{color: this.state.folder.color}}
|
||||||
|
onClick={(e) => !this.state.folder.showColumnPicker && this.handleColorButtonClick(e)}
|
||||||
|
>
|
||||||
|
{this.state.folder.showColumnPicker
|
||||||
|
? <div style={popover}>
|
||||||
|
<div style={cover}
|
||||||
|
onClick={() => this.handleColorPickerClose()}
|
||||||
|
/>
|
||||||
|
<div style={pickerStyle}>
|
||||||
|
<SketchPicker
|
||||||
|
ref='colorPicker'
|
||||||
|
color={this.state.folder.color}
|
||||||
|
onChange={(color) => this.handleColorChange(color)}
|
||||||
|
onChangeComplete={(color) => this.handleColorChange(color)}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
: null
|
||||||
|
}
|
||||||
|
<i className='fa fa-square' />
|
||||||
|
</button>
|
||||||
|
<input styleName='folderItem-left-nameInput'
|
||||||
|
value={this.state.folder.name}
|
||||||
|
ref='nameInput'
|
||||||
|
onChange={(e) => this.handleEditChange(e)}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div styleName='folderItem-right'>
|
||||||
|
<button styleName='folderItem-right-confirmButton'
|
||||||
|
onClick={(e) => this.handleConfirmButtonClick(e)}
|
||||||
|
>
|
||||||
|
Confirm
|
||||||
|
</button>
|
||||||
|
<button styleName='folderItem-right-button'
|
||||||
|
onClick={(e) => this.handleCancelButtonClick(e)}
|
||||||
|
>
|
||||||
|
Cancel
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
handleDeleteConfirmButtonClick (e) {
|
||||||
|
let { storage, folder } = this.props
|
||||||
|
dataApi
|
||||||
|
.deleteFolder(storage.key, folder.key)
|
||||||
|
.then((data) => {
|
||||||
|
store.dispatch({
|
||||||
|
type: 'DELETE_FOLDER',
|
||||||
|
storage: data.storage,
|
||||||
|
folderKey: data.folderKey
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
renderDelete () {
|
||||||
|
return (
|
||||||
|
<div styleName='folderItem'>
|
||||||
|
<div styleName='folderItem-left'>
|
||||||
|
Are you sure to <span styleName='folderItem-left-danger'>delete</span> this folder?
|
||||||
|
</div>
|
||||||
|
<div styleName='folderItem-right'>
|
||||||
|
<button styleName='folderItem-right-dangerButton'
|
||||||
|
onClick={(e) => this.handleDeleteConfirmButtonClick(e)}
|
||||||
|
>
|
||||||
|
Confirm
|
||||||
|
</button>
|
||||||
|
<button styleName='folderItem-right-button'
|
||||||
|
onClick={(e) => this.handleCancelButtonClick(e)}
|
||||||
|
>
|
||||||
|
Cancel
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
handleEditButtonClick (e) {
|
||||||
|
let { folder: propsFolder } = this.props
|
||||||
|
let { folder: stateFolder } = this.state
|
||||||
|
const folder = Object.assign({}, stateFolder, propsFolder)
|
||||||
|
this.setState({
|
||||||
|
status: 'EDIT',
|
||||||
|
folder
|
||||||
|
}, () => {
|
||||||
|
this.refs.nameInput.select()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
handleDeleteButtonClick (e) {
|
||||||
|
this.setState({
|
||||||
|
status: 'DELETE'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
renderIdle () {
|
||||||
|
let { folder } = this.props
|
||||||
|
return (
|
||||||
|
<div styleName='folderItem'
|
||||||
|
onDoubleClick={(e) => this.handleEditButtonClick(e)}
|
||||||
|
>
|
||||||
|
<div styleName='folderItem-left'
|
||||||
|
style={{borderColor: folder.color}}
|
||||||
|
>
|
||||||
|
<span styleName='folderItem-left-name'>{folder.name}</span>
|
||||||
|
<span styleName='folderItem-left-key'>({folder.key})</span>
|
||||||
|
</div>
|
||||||
|
<div styleName='folderItem-right'>
|
||||||
|
<button styleName='folderItem-right-button'
|
||||||
|
onClick={(e) => this.handleEditButtonClick(e)}
|
||||||
|
>
|
||||||
|
Edit
|
||||||
|
</button>
|
||||||
|
<button styleName='folderItem-right-button'
|
||||||
|
onClick={(e) => this.handleDeleteButtonClick(e)}
|
||||||
|
>
|
||||||
|
Delete
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
render () {
|
||||||
|
switch (this.state.status) {
|
||||||
|
case 'DELETE':
|
||||||
|
return this.renderDelete()
|
||||||
|
case 'EDIT':
|
||||||
|
return this.renderEdit()
|
||||||
|
case 'IDLE':
|
||||||
|
default:
|
||||||
|
return this.renderIdle()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
FolderItem.propTypes = {
|
||||||
|
hostBoundingBox: PropTypes.shape({
|
||||||
|
bottom: PropTypes.number,
|
||||||
|
height: PropTypes.number,
|
||||||
|
left: PropTypes.number,
|
||||||
|
right: PropTypes.number,
|
||||||
|
top: PropTypes.number,
|
||||||
|
width: PropTypes.number
|
||||||
|
}),
|
||||||
|
storage: PropTypes.shape({
|
||||||
|
key: PropTypes.string
|
||||||
|
}),
|
||||||
|
folder: PropTypes.shape({
|
||||||
|
key: PropTypes.string,
|
||||||
|
color: PropTypes.string,
|
||||||
|
name: PropTypes.string
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
class Handle extends React.Component {
|
||||||
|
render () {
|
||||||
|
return (
|
||||||
|
<div styleName='folderItem-drag-handle'>
|
||||||
|
<i className='fa fa-reorder' />
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class SortableFolderItemComponent extends React.Component {
|
||||||
|
render () {
|
||||||
|
const StyledHandle = CSSModules(Handle, this.props.styles)
|
||||||
|
const DragHandle = SortableHandle(StyledHandle)
|
||||||
|
|
||||||
|
const StyledFolderItem = CSSModules(FolderItem, this.props.styles)
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<DragHandle />
|
||||||
|
<StyledFolderItem {...this.props} />
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default CSSModules(SortableElement(SortableFolderItemComponent), styles)
|
||||||
103
browser/main/modals/PreferencesModal/FolderItem.styl
Normal file
103
browser/main/modals/PreferencesModal/FolderItem.styl
Normal file
@@ -0,0 +1,103 @@
|
|||||||
|
.folderItem
|
||||||
|
height 35px
|
||||||
|
box-sizing border-box
|
||||||
|
padding 2.5px 15px
|
||||||
|
&:hover
|
||||||
|
background-color darken(white, 3%)
|
||||||
|
|
||||||
|
.folderItem-drag-handle
|
||||||
|
height 35px
|
||||||
|
border none
|
||||||
|
padding 0 10px
|
||||||
|
line-height 35px
|
||||||
|
float left
|
||||||
|
cursor row-resize
|
||||||
|
|
||||||
|
.folderItem-left
|
||||||
|
height 30px
|
||||||
|
border-left solid 2px transparent
|
||||||
|
padding 0 10px
|
||||||
|
line-height 30px
|
||||||
|
float left
|
||||||
|
.folderItem-left-danger
|
||||||
|
color $danger-color
|
||||||
|
font-weight bold
|
||||||
|
|
||||||
|
.folderItem-left-key
|
||||||
|
color $ui-inactive-text-color
|
||||||
|
font-size 13px
|
||||||
|
margin 0 5px
|
||||||
|
border none
|
||||||
|
|
||||||
|
.folderItem-left-colorButton
|
||||||
|
colorDefaultButton()
|
||||||
|
height 25px
|
||||||
|
width 25px
|
||||||
|
line-height 23px
|
||||||
|
padding 0
|
||||||
|
box-sizing border-box
|
||||||
|
vertical-align middle
|
||||||
|
border $ui-border
|
||||||
|
border-radius 2px
|
||||||
|
margin-right 5px
|
||||||
|
margin-left -15px
|
||||||
|
|
||||||
|
.folderItem-left-nameInput
|
||||||
|
height 25px
|
||||||
|
box-sizing border-box
|
||||||
|
vertical-align middle
|
||||||
|
border $ui-border
|
||||||
|
border-radius 2px
|
||||||
|
padding 0 5px
|
||||||
|
outline none
|
||||||
|
|
||||||
|
.folderItem-right
|
||||||
|
float right
|
||||||
|
|
||||||
|
.folderItem-right-button
|
||||||
|
vertical-align middle
|
||||||
|
height 25px
|
||||||
|
margin-top 2.5px
|
||||||
|
colorDefaultButton()
|
||||||
|
border-radius 2px
|
||||||
|
border $ui-border
|
||||||
|
margin-right 5px
|
||||||
|
padding 0 5px
|
||||||
|
&:last-child
|
||||||
|
margin-right 0
|
||||||
|
|
||||||
|
.folderItem-right-confirmButton
|
||||||
|
@extend .folderItem-right-button
|
||||||
|
border none
|
||||||
|
colorPrimaryButton()
|
||||||
|
|
||||||
|
.folderItem-right-dangerButton
|
||||||
|
@extend .folderItem-right-button
|
||||||
|
border none
|
||||||
|
colorDangerButton()
|
||||||
|
|
||||||
|
body[data-theme="dark"]
|
||||||
|
.folderItem
|
||||||
|
&:hover
|
||||||
|
background-color lighten($ui-dark-button--hover-backgroundColor, 5%)
|
||||||
|
|
||||||
|
.folderItem-left-danger
|
||||||
|
color $danger-color
|
||||||
|
font-weight bold
|
||||||
|
|
||||||
|
.folderItem-left-key
|
||||||
|
color $ui-dark-inactive-text-color
|
||||||
|
|
||||||
|
.folderItem-left-colorButton
|
||||||
|
colorDarkDefaultButton()
|
||||||
|
border-color $ui-dark-borderColor
|
||||||
|
|
||||||
|
.folderItem-right-button
|
||||||
|
colorDarkDefaultButton()
|
||||||
|
border-color $ui-dark-borderColor
|
||||||
|
|
||||||
|
.folderItem-right-confirmButton
|
||||||
|
colorDarkPrimaryButton()
|
||||||
|
|
||||||
|
.folderItem-right-dangerButton
|
||||||
|
colorDarkDangerButton()
|
||||||
84
browser/main/modals/PreferencesModal/FolderList.js
Normal file
84
browser/main/modals/PreferencesModal/FolderList.js
Normal file
@@ -0,0 +1,84 @@
|
|||||||
|
import React, { PropTypes } from 'react'
|
||||||
|
import CSSModules from 'browser/lib/CSSModules'
|
||||||
|
import dataApi from 'browser/main/lib/dataApi'
|
||||||
|
import styles from './FolderList.styl'
|
||||||
|
import store from 'browser/main/store'
|
||||||
|
import FolderItem from './FolderItem'
|
||||||
|
import { SortableContainer, arrayMove } from 'react-sortable-hoc'
|
||||||
|
|
||||||
|
class FolderList extends React.Component {
|
||||||
|
render () {
|
||||||
|
let { storage, hostBoundingBox } = this.props
|
||||||
|
|
||||||
|
let folderList = storage.folders.map((folder, index) => {
|
||||||
|
return <FolderItem key={folder.key}
|
||||||
|
folder={folder}
|
||||||
|
storage={storage}
|
||||||
|
index={index}
|
||||||
|
hostBoundingBox={hostBoundingBox}
|
||||||
|
/>
|
||||||
|
})
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div styleName='folderList'>
|
||||||
|
{folderList.length > 0
|
||||||
|
? folderList
|
||||||
|
: <div styleName='folderList-empty'>No Folders</div>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
FolderList.propTypes = {
|
||||||
|
hostBoundingBox: PropTypes.shape({
|
||||||
|
bottom: PropTypes.number,
|
||||||
|
height: PropTypes.number,
|
||||||
|
left: PropTypes.number,
|
||||||
|
right: PropTypes.number,
|
||||||
|
top: PropTypes.number,
|
||||||
|
width: PropTypes.number
|
||||||
|
}),
|
||||||
|
storage: PropTypes.shape({
|
||||||
|
key: PropTypes.string
|
||||||
|
}),
|
||||||
|
folder: PropTypes.shape({
|
||||||
|
key: PropTypes.number,
|
||||||
|
color: PropTypes.string,
|
||||||
|
name: PropTypes.string
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
class SortableFolderListComponent extends React.Component {
|
||||||
|
constructor (props) {
|
||||||
|
super(props)
|
||||||
|
this.onSortEnd = ({oldIndex, newIndex}) => {
|
||||||
|
let { storage } = this.props
|
||||||
|
dataApi
|
||||||
|
.reorderFolder(storage.key, oldIndex, newIndex)
|
||||||
|
.then((data) => {
|
||||||
|
store.dispatch({
|
||||||
|
type: 'REORDER_FOLDER',
|
||||||
|
storage: data.storage
|
||||||
|
})
|
||||||
|
this.setState()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
render () {
|
||||||
|
const StyledFolderList = CSSModules(FolderList, this.props.styles)
|
||||||
|
const SortableFolderList = SortableContainer(StyledFolderList)
|
||||||
|
|
||||||
|
return (
|
||||||
|
<SortableFolderList
|
||||||
|
helperClass='sortableItemHelper'
|
||||||
|
onSortEnd={this.onSortEnd}
|
||||||
|
useDragHandle
|
||||||
|
{...this.props}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default CSSModules(SortableFolderListComponent, styles)
|
||||||
@@ -3,6 +3,7 @@ import CSSModules from 'browser/lib/CSSModules'
|
|||||||
import styles from './ConfigTab.styl'
|
import styles from './ConfigTab.styl'
|
||||||
import ConfigManager from 'browser/main/lib/ConfigManager'
|
import ConfigManager from 'browser/main/lib/ConfigManager'
|
||||||
import store from 'browser/main/store'
|
import store from 'browser/main/store'
|
||||||
|
import _ from 'lodash'
|
||||||
|
|
||||||
const electron = require('electron')
|
const electron = require('electron')
|
||||||
const ipc = electron.ipcRenderer
|
const ipc = electron.ipcRenderer
|
||||||
@@ -50,6 +51,7 @@ class HotkeyTab extends React.Component {
|
|||||||
type: 'SET_UI',
|
type: 'SET_UI',
|
||||||
config: newConfig
|
config: newConfig
|
||||||
})
|
})
|
||||||
|
this.clearMessage()
|
||||||
}
|
}
|
||||||
|
|
||||||
handleHintToggleButtonClick (e) {
|
handleHintToggleButtonClick (e) {
|
||||||
@@ -69,6 +71,14 @@ class HotkeyTab extends React.Component {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
clearMessage () {
|
||||||
|
_.debounce(() => {
|
||||||
|
this.setState({
|
||||||
|
keymapAlert: null
|
||||||
|
})
|
||||||
|
}, 2000)()
|
||||||
|
}
|
||||||
|
|
||||||
render () {
|
render () {
|
||||||
let keymapAlert = this.state.keymapAlert
|
let keymapAlert = this.state.keymapAlert
|
||||||
let keymapAlertElement = keymapAlert != null
|
let keymapAlertElement = keymapAlert != null
|
||||||
@@ -94,7 +104,7 @@ class HotkeyTab extends React.Component {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div styleName='group-section'>
|
<div styleName='group-section'>
|
||||||
<div styleName='group-section-label'>Toggle Finder(popup)</div>
|
<div styleName='group-section-label'>Toggle Finder (Quick search)</div>
|
||||||
<div styleName='group-section-control'>
|
<div styleName='group-section-control'>
|
||||||
<input styleName='group-section-control-input'
|
<input styleName='group-section-control-input'
|
||||||
onChange={(e) => this.handleHotkeyChange(e)}
|
onChange={(e) => this.handleHotkeyChange(e)}
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import styles from './InfoTab.styl'
|
|||||||
import ConfigManager from 'browser/main/lib/ConfigManager'
|
import ConfigManager from 'browser/main/lib/ConfigManager'
|
||||||
import store from 'browser/main/store'
|
import store from 'browser/main/store'
|
||||||
import AwsMobileAnalyticsConfig from 'browser/main/lib/AwsMobileAnalyticsConfig'
|
import AwsMobileAnalyticsConfig from 'browser/main/lib/AwsMobileAnalyticsConfig'
|
||||||
|
import _ from 'lodash'
|
||||||
|
|
||||||
const electron = require('electron')
|
const electron = require('electron')
|
||||||
const { shell, remote } = electron
|
const { shell, remote } = electron
|
||||||
@@ -36,8 +37,21 @@ class InfoTab extends React.Component {
|
|||||||
|
|
||||||
if (!newConfig.amaEnabled) {
|
if (!newConfig.amaEnabled) {
|
||||||
AwsMobileAnalyticsConfig.recordDynamicCustomEvent('DISABLE_AMA')
|
AwsMobileAnalyticsConfig.recordDynamicCustomEvent('DISABLE_AMA')
|
||||||
|
this.setState({
|
||||||
|
amaMessage: 'We hope we will gain your trust'
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
this.setState({
|
||||||
|
amaMessage: 'Thank\'s for trust us'
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_.debounce(() => {
|
||||||
|
this.setState({
|
||||||
|
amaMessage: ''
|
||||||
|
})
|
||||||
|
}, 3000)()
|
||||||
|
|
||||||
ConfigManager.set(newConfig)
|
ConfigManager.set(newConfig)
|
||||||
|
|
||||||
store.dispatch({
|
store.dispatch({
|
||||||
@@ -46,10 +60,49 @@ class InfoTab extends React.Component {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
infoMessage () {
|
||||||
|
const { amaMessage } = this.state
|
||||||
|
return amaMessage ? <p styleName='policy-confirm'>{amaMessage}</p> : null
|
||||||
|
}
|
||||||
|
|
||||||
render () {
|
render () {
|
||||||
return (
|
return (
|
||||||
<div styleName='root'>
|
<div styleName='root'>
|
||||||
<div styleName='header'>Info</div>
|
|
||||||
|
<div styleName='header--sub'>Community</div>
|
||||||
|
<div styleName='top'>
|
||||||
|
<ul styleName='list'>
|
||||||
|
<li>
|
||||||
|
<a href='https://github.com/BoostIO/Boostnote/issues'
|
||||||
|
onClick={(e) => this.handleLinkClick(e)}
|
||||||
|
>GitHub</a>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<a href='https://medium.com/boostnote'
|
||||||
|
onClick={(e) => this.handleLinkClick(e)}
|
||||||
|
>Blog</a>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<a href='https://www.reddit.com/r/Boostnote/'
|
||||||
|
onClick={(e) => this.handleLinkClick(e)}
|
||||||
|
>Reddit</a>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<a href='https://www.facebook.com/groups/boostnote'
|
||||||
|
onClick={(e) => this.handleLinkClick(e)}
|
||||||
|
>Facebook Group</a>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<a href='https://twitter.com/boostnoteapp'
|
||||||
|
onClick={(e) => this.handleLinkClick(e)}
|
||||||
|
>Twitter</a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<hr />
|
||||||
|
|
||||||
|
<div styleName='header--sub'>Info</div>
|
||||||
|
|
||||||
<div styleName='top'>
|
<div styleName='top'>
|
||||||
<div styleName='icon-space'>
|
<div styleName='icon-space'>
|
||||||
@@ -62,31 +115,17 @@ class InfoTab extends React.Component {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<ul styleName='list'>
|
<ul styleName='list'>
|
||||||
<li>
|
<li>
|
||||||
<a href='https://boostnote.io'
|
<a href='https://boostnote.io'
|
||||||
onClick={(e) => this.handleLinkClick(e)}
|
onClick={(e) => this.handleLinkClick(e)}
|
||||||
>Website</a>
|
>Website</a>
|
||||||
</li>
|
</li>
|
||||||
<li>
|
|
||||||
<a href='https://boostnote.paintory.com/'
|
|
||||||
onClick={(e) => this.handleLinkClick(e)}
|
|
||||||
>Boostnote Shop</a> : Products are shipped to all over the world 🌏
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
<a href='https://salt.bountysource.com/teams/boostnote'
|
|
||||||
onClick={(e) => this.handleLinkClick(e)}
|
|
||||||
>Donate via Bountysource</a> : Thank you for your support 🎉
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
<a href='https://github.com/BoostIO/Boostnote/issues'
|
|
||||||
onClick={(e) => this.handleLinkClick(e)}
|
|
||||||
>GitHub Issues</a> : We'd love to hear your feedback 🙌
|
|
||||||
</li>
|
|
||||||
<li>
|
<li>
|
||||||
<a href='https://github.com/BoostIO/Boostnote/blob/master/docs/build.md'
|
<a href='https://github.com/BoostIO/Boostnote/blob/master/docs/build.md'
|
||||||
onClick={(e) => this.handleLinkClick(e)}
|
onClick={(e) => this.handleLinkClick(e)}
|
||||||
>Development</a> : Development configurations for Boostnote 🚀
|
>Development</a> : Development configurations for Boostnote.
|
||||||
</li>
|
</li>
|
||||||
<li styleName='cc'>
|
<li styleName='cc'>
|
||||||
Copyright (C) 2017 Maisin&Co.
|
Copyright (C) 2017 Maisin&Co.
|
||||||
@@ -95,11 +134,13 @@ class InfoTab extends React.Component {
|
|||||||
License: GPL v3
|
License: GPL v3
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
<hr />
|
|
||||||
|
<hr styleName='separate-line' />
|
||||||
|
|
||||||
<div styleName='policy'>Data collection policy</div>
|
<div styleName='policy'>Data collection policy</div>
|
||||||
<div>We collect only the number of DAU for Boostnote and **DO NOT collect** any detail information such as your note content.</div>
|
<div>We collect only the number of DAU for Boostnote and **DO NOT collect** any detail information such as your note content.</div>
|
||||||
<div>You can see how it works on <a href='https://github.com/BoostIO/Boostnote' onClick={(e) => this.handleLinkClick(e)}>GitHub</a>.</div>
|
<div>You can see how it works on <a href='https://github.com/BoostIO/Boostnote' onClick={(e) => this.handleLinkClick(e)}>GitHub</a>.</div>
|
||||||
<div>These data are only used for Boostnote improvements.</div>
|
<div>This data is only used for Boostnote improvements.</div>
|
||||||
<input onChange={(e) => this.handleConfigChange(e)}
|
<input onChange={(e) => this.handleConfigChange(e)}
|
||||||
checked={this.state.config.amaEnabled}
|
checked={this.state.config.amaEnabled}
|
||||||
ref='amaEnabled'
|
ref='amaEnabled'
|
||||||
@@ -107,6 +148,7 @@ class InfoTab extends React.Component {
|
|||||||
/>
|
/>
|
||||||
Enable to send analytics to our servers<br />
|
Enable to send analytics to our servers<br />
|
||||||
<button styleName='policy-submit' onClick={(e) => this.handleSaveButtonClick(e)}>Save</button>
|
<button styleName='policy-submit' onClick={(e) => this.handleSaveButtonClick(e)}>Save</button>
|
||||||
|
{this.infoMessage()}
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -42,6 +42,9 @@
|
|||||||
color #4E8EC6
|
color #4E8EC6
|
||||||
text-decoration none
|
text-decoration none
|
||||||
|
|
||||||
|
.separate-line
|
||||||
|
margin 40px 0
|
||||||
|
|
||||||
.policy
|
.policy
|
||||||
width 100%
|
width 100%
|
||||||
font-size 20px
|
font-size 20px
|
||||||
@@ -50,6 +53,10 @@
|
|||||||
.policy-submit
|
.policy-submit
|
||||||
margin-top 10px
|
margin-top 10px
|
||||||
|
|
||||||
|
.policy-confirm
|
||||||
|
margin-top 10px
|
||||||
|
font-size 12px
|
||||||
|
|
||||||
body[data-theme="dark"]
|
body[data-theme="dark"]
|
||||||
.root
|
.root
|
||||||
color alpha($tab--dark-text-color, 80%)
|
color alpha($tab--dark-text-color, 80%)
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ top-bar--height = 50px
|
|||||||
absolute top left right
|
absolute top left right
|
||||||
top top-bar--height
|
top top-bar--height
|
||||||
left 0
|
left 0
|
||||||
width 140px
|
width 170px
|
||||||
margin-left 10px
|
margin-left 10px
|
||||||
margin-top 20px
|
margin-top 20px
|
||||||
background-color $ui-backgroundColor
|
background-color $ui-backgroundColor
|
||||||
@@ -33,7 +33,7 @@ top-bar--height = 50px
|
|||||||
.nav-button
|
.nav-button
|
||||||
font-size 14px
|
font-size 14px
|
||||||
text-align left
|
text-align left
|
||||||
width 120px
|
width 150px
|
||||||
margin 5px 0
|
margin 5px 0
|
||||||
padding 7px 0
|
padding 7px 0
|
||||||
padding-left 10px
|
padding-left 10px
|
||||||
@@ -56,7 +56,7 @@ top-bar--height = 50px
|
|||||||
.content
|
.content
|
||||||
absolute left right bottom
|
absolute left right bottom
|
||||||
top top-bar--height
|
top top-bar--height
|
||||||
left 140px
|
left 170px
|
||||||
margin-top 10px
|
margin-top 10px
|
||||||
overflow-y auto
|
overflow-y auto
|
||||||
|
|
||||||
|
|||||||
@@ -1,265 +1,13 @@
|
|||||||
import React, { PropTypes } from 'react'
|
import React, { PropTypes } from 'react'
|
||||||
import ReactDOM from 'react-dom'
|
|
||||||
import CSSModules from 'browser/lib/CSSModules'
|
import CSSModules from 'browser/lib/CSSModules'
|
||||||
import styles from './StorageItem.styl'
|
import styles from './StorageItem.styl'
|
||||||
import consts from 'browser/lib/consts'
|
import consts from 'browser/lib/consts'
|
||||||
import dataApi from 'browser/main/lib/dataApi'
|
import dataApi from 'browser/main/lib/dataApi'
|
||||||
import store from 'browser/main/store'
|
import store from 'browser/main/store'
|
||||||
|
import FolderList from './FolderList'
|
||||||
|
|
||||||
const { shell, remote } = require('electron')
|
const { shell, remote } = require('electron')
|
||||||
const { dialog } = remote
|
const { dialog } = remote
|
||||||
import { SketchPicker } from 'react-color'
|
|
||||||
|
|
||||||
class UnstyledFolderItem extends React.Component {
|
|
||||||
constructor (props) {
|
|
||||||
super(props)
|
|
||||||
|
|
||||||
this.state = {
|
|
||||||
status: 'IDLE',
|
|
||||||
folder: {
|
|
||||||
showColumnPicker: false,
|
|
||||||
colorPickerPos: { left: 0, top: 0 },
|
|
||||||
color: props.color,
|
|
||||||
name: props.name
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
handleEditChange (e) {
|
|
||||||
let { folder } = this.state
|
|
||||||
|
|
||||||
folder.name = this.refs.nameInput.value
|
|
||||||
this.setState({
|
|
||||||
folder
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
handleConfirmButtonClick (e) {
|
|
||||||
this.confirm()
|
|
||||||
}
|
|
||||||
|
|
||||||
confirm () {
|
|
||||||
let { storage, folder } = this.props
|
|
||||||
dataApi
|
|
||||||
.updateFolder(storage.key, folder.key, {
|
|
||||||
color: this.state.folder.color,
|
|
||||||
name: this.state.folder.name
|
|
||||||
})
|
|
||||||
.then((data) => {
|
|
||||||
store.dispatch({
|
|
||||||
type: 'UPDATE_FOLDER',
|
|
||||||
storage: data.storage
|
|
||||||
})
|
|
||||||
this.setState({
|
|
||||||
status: 'IDLE'
|
|
||||||
})
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
handleColorButtonClick (e) {
|
|
||||||
const folder = Object.assign({}, this.state.folder, { showColumnPicker: true, colorPickerPos: { left: 0, top: 0 } })
|
|
||||||
this.setState({ folder }, function () {
|
|
||||||
// After the color picker has been painted, re-calculate its position
|
|
||||||
// by comparing its dimensions to the host dimensions.
|
|
||||||
const { hostBoundingBox } = this.props
|
|
||||||
const colorPickerNode = ReactDOM.findDOMNode(this.refs.colorPicker)
|
|
||||||
const colorPickerBox = colorPickerNode.getBoundingClientRect()
|
|
||||||
const offsetTop = hostBoundingBox.bottom - colorPickerBox.bottom
|
|
||||||
const folder = Object.assign({}, this.state.folder, {
|
|
||||||
colorPickerPos: {
|
|
||||||
left: 25,
|
|
||||||
top: offsetTop < 0 ? offsetTop - 5 : 0 // subtract 5px for aestetics
|
|
||||||
}
|
|
||||||
})
|
|
||||||
this.setState({ folder })
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
handleColorChange (color) {
|
|
||||||
const folder = Object.assign({}, this.state.folder, { color: color.hex })
|
|
||||||
this.setState({ folder })
|
|
||||||
}
|
|
||||||
|
|
||||||
handleColorPickerClose (event) {
|
|
||||||
const folder = Object.assign({}, this.state.folder, { showColumnPicker: false })
|
|
||||||
this.setState({ folder })
|
|
||||||
}
|
|
||||||
|
|
||||||
handleCancelButtonClick (e) {
|
|
||||||
this.setState({
|
|
||||||
status: 'IDLE'
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
handleFolderItemBlur (e) {
|
|
||||||
let el = e.relatedTarget
|
|
||||||
while (el != null) {
|
|
||||||
if (el === this.refs.root) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
el = el.parentNode
|
|
||||||
}
|
|
||||||
this.confirm()
|
|
||||||
}
|
|
||||||
|
|
||||||
renderEdit (e) {
|
|
||||||
const popover = { position: 'absolute', zIndex: 2 }
|
|
||||||
const cover = {
|
|
||||||
position: 'fixed',
|
|
||||||
top: 0,
|
|
||||||
right: 0,
|
|
||||||
bottom: 0,
|
|
||||||
left: 0
|
|
||||||
}
|
|
||||||
const pickerStyle = Object.assign({}, {
|
|
||||||
position: 'absolute'
|
|
||||||
}, this.state.folder.colorPickerPos)
|
|
||||||
return (
|
|
||||||
<div styleName='folderList-item'
|
|
||||||
onBlur={(e) => this.handleFolderItemBlur(e)}
|
|
||||||
tabIndex='-1'
|
|
||||||
ref='root'
|
|
||||||
>
|
|
||||||
<div styleName='folderList-item-left'>
|
|
||||||
<button styleName='folderList-item-left-colorButton' style={{color: this.state.folder.color}}
|
|
||||||
onClick={(e) => !this.state.folder.showColumnPicker && this.handleColorButtonClick(e)}
|
|
||||||
>
|
|
||||||
{this.state.folder.showColumnPicker
|
|
||||||
? <div style={popover}>
|
|
||||||
<div style={cover}
|
|
||||||
onClick={() => this.handleColorPickerClose()}
|
|
||||||
/>
|
|
||||||
<div style={pickerStyle}>
|
|
||||||
<SketchPicker
|
|
||||||
ref='colorPicker'
|
|
||||||
color={this.state.folder.color}
|
|
||||||
onChange={(color) => this.handleColorChange(color)}
|
|
||||||
onChangeComplete={(color) => this.handleColorChange(color)}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
: null
|
|
||||||
}
|
|
||||||
<i className='fa fa-square' />
|
|
||||||
</button>
|
|
||||||
<input styleName='folderList-item-left-nameInput'
|
|
||||||
value={this.state.folder.name}
|
|
||||||
ref='nameInput'
|
|
||||||
onChange={(e) => this.handleEditChange(e)}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div styleName='folderList-item-right'>
|
|
||||||
<button styleName='folderList-item-right-confirmButton'
|
|
||||||
onClick={(e) => this.handleConfirmButtonClick(e)}
|
|
||||||
>
|
|
||||||
Confirm
|
|
||||||
</button>
|
|
||||||
<button styleName='folderList-item-right-button'
|
|
||||||
onClick={(e) => this.handleCancelButtonClick(e)}
|
|
||||||
>
|
|
||||||
Cancel
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
handleDeleteConfirmButtonClick (e) {
|
|
||||||
let { storage, folder } = this.props
|
|
||||||
dataApi
|
|
||||||
.deleteFolder(storage.key, folder.key)
|
|
||||||
.then((data) => {
|
|
||||||
store.dispatch({
|
|
||||||
type: 'DELETE_FOLDER',
|
|
||||||
storage: data.storage,
|
|
||||||
folderKey: data.folderKey
|
|
||||||
})
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
renderDelete () {
|
|
||||||
return (
|
|
||||||
<div styleName='folderList-item'>
|
|
||||||
<div styleName='folderList-item-left'>
|
|
||||||
Are you sure to <span styleName='folderList-item-left-danger'>delete</span> this folder?
|
|
||||||
</div>
|
|
||||||
<div styleName='folderList-item-right'>
|
|
||||||
<button styleName='folderList-item-right-dangerButton'
|
|
||||||
onClick={(e) => this.handleDeleteConfirmButtonClick(e)}
|
|
||||||
>
|
|
||||||
Confirm
|
|
||||||
</button>
|
|
||||||
<button styleName='folderList-item-right-button'
|
|
||||||
onClick={(e) => this.handleCancelButtonClick(e)}
|
|
||||||
>
|
|
||||||
Cancel
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
handleEditButtonClick (e) {
|
|
||||||
let { folder: propsFolder } = this.props
|
|
||||||
let { folder: stateFolder } = this.state
|
|
||||||
const folder = Object.assign({}, stateFolder, propsFolder)
|
|
||||||
this.setState({
|
|
||||||
status: 'EDIT',
|
|
||||||
folder
|
|
||||||
}, () => {
|
|
||||||
this.refs.nameInput.select()
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
handleDeleteButtonClick (e) {
|
|
||||||
this.setState({
|
|
||||||
status: 'DELETE'
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
renderIdle () {
|
|
||||||
let { folder } = this.props
|
|
||||||
return (
|
|
||||||
<div styleName='folderList-item'
|
|
||||||
onDoubleClick={(e) => this.handleEditButtonClick(e)}
|
|
||||||
>
|
|
||||||
<div styleName='folderList-item-left'
|
|
||||||
style={{borderColor: folder.color}}
|
|
||||||
>
|
|
||||||
<span styleName='folderList-item-left-name'>{folder.name}</span>
|
|
||||||
<span styleName='folderList-item-left-key'>({folder.key})</span>
|
|
||||||
</div>
|
|
||||||
<div styleName='folderList-item-right'>
|
|
||||||
<button styleName='folderList-item-right-button'
|
|
||||||
onClick={(e) => this.handleEditButtonClick(e)}
|
|
||||||
>
|
|
||||||
Edit
|
|
||||||
</button>
|
|
||||||
<button styleName='folderList-item-right-button'
|
|
||||||
onClick={(e) => this.handleDeleteButtonClick(e)}
|
|
||||||
>
|
|
||||||
Delete
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
render () {
|
|
||||||
switch (this.state.status) {
|
|
||||||
case 'DELETE':
|
|
||||||
return this.renderDelete()
|
|
||||||
case 'EDIT':
|
|
||||||
return this.renderEdit()
|
|
||||||
case 'IDLE':
|
|
||||||
default:
|
|
||||||
return this.renderIdle()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const FolderItem = CSSModules(UnstyledFolderItem, styles)
|
|
||||||
|
|
||||||
class StorageItem extends React.Component {
|
class StorageItem extends React.Component {
|
||||||
constructor (props) {
|
constructor (props) {
|
||||||
@@ -349,13 +97,7 @@ class StorageItem extends React.Component {
|
|||||||
|
|
||||||
render () {
|
render () {
|
||||||
let { storage, hostBoundingBox } = this.props
|
let { storage, hostBoundingBox } = this.props
|
||||||
let folderList = storage.folders.map((folder) => {
|
|
||||||
return <FolderItem key={folder.key}
|
|
||||||
folder={folder}
|
|
||||||
storage={storage}
|
|
||||||
hostBoundingBox={hostBoundingBox}
|
|
||||||
/>
|
|
||||||
})
|
|
||||||
return (
|
return (
|
||||||
<div styleName='root' key={storage.key}>
|
<div styleName='root' key={storage.key}>
|
||||||
<div styleName='header'>
|
<div styleName='header'>
|
||||||
@@ -404,12 +146,9 @@ class StorageItem extends React.Component {
|
|||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div styleName='folderList'>
|
<FolderList storage={storage}
|
||||||
{folderList.length > 0
|
hostBoundingBox={hostBoundingBox}
|
||||||
? folderList
|
/>
|
||||||
: <div styleName='folderList-empty'>No Folders</div>
|
|
||||||
}
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -426,11 +165,6 @@ StorageItem.propTypes = {
|
|||||||
}),
|
}),
|
||||||
storage: PropTypes.shape({
|
storage: PropTypes.shape({
|
||||||
key: PropTypes.string
|
key: PropTypes.string
|
||||||
}),
|
|
||||||
folder: PropTypes.shape({
|
|
||||||
key: PropTypes.string,
|
|
||||||
color: PropTypes.string,
|
|
||||||
name: PropTypes.string
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -63,75 +63,6 @@
|
|||||||
z-index 10
|
z-index 10
|
||||||
white-space nowrap
|
white-space nowrap
|
||||||
|
|
||||||
.folderList-item
|
|
||||||
height 35px
|
|
||||||
box-sizing border-box
|
|
||||||
padding 2.5px 15px
|
|
||||||
&:hover
|
|
||||||
background-color darken(white, 3%)
|
|
||||||
.folderList-item-left
|
|
||||||
height 30px
|
|
||||||
border-left solid 2px transparent
|
|
||||||
padding 0 10px
|
|
||||||
line-height 30px
|
|
||||||
float left
|
|
||||||
.folderList-item-left-danger
|
|
||||||
color $danger-color
|
|
||||||
font-weight bold
|
|
||||||
|
|
||||||
.folderList-item-left-key
|
|
||||||
color $ui-inactive-text-color
|
|
||||||
font-size 10px
|
|
||||||
margin 0 5px
|
|
||||||
border none
|
|
||||||
|
|
||||||
.folderList-item-left-colorButton
|
|
||||||
colorDefaultButton()
|
|
||||||
height 25px
|
|
||||||
width 25px
|
|
||||||
line-height 23px
|
|
||||||
padding 0
|
|
||||||
box-sizing border-box
|
|
||||||
vertical-align middle
|
|
||||||
border $ui-border
|
|
||||||
border-radius 2px
|
|
||||||
margin-right 5px
|
|
||||||
margin-left -15px
|
|
||||||
|
|
||||||
.folderList-item-left-nameInput
|
|
||||||
height 25px
|
|
||||||
box-sizing border-box
|
|
||||||
vertical-align middle
|
|
||||||
border $ui-border
|
|
||||||
border-radius 2px
|
|
||||||
padding 0 5px
|
|
||||||
outline none
|
|
||||||
|
|
||||||
.folderList-item-right
|
|
||||||
float right
|
|
||||||
|
|
||||||
.folderList-item-right-button
|
|
||||||
vertical-align middle
|
|
||||||
height 25px
|
|
||||||
margin-top 2.5px
|
|
||||||
colorDefaultButton()
|
|
||||||
border-radius 2px
|
|
||||||
border $ui-border
|
|
||||||
margin-right 5px
|
|
||||||
padding 0 5px
|
|
||||||
&:last-child
|
|
||||||
margin-right 0
|
|
||||||
|
|
||||||
.folderList-item-right-confirmButton
|
|
||||||
@extend .folderList-item-right-button
|
|
||||||
border none
|
|
||||||
colorPrimaryButton()
|
|
||||||
|
|
||||||
.folderList-item-right-dangerButton
|
|
||||||
@extend .folderList-item-right-button
|
|
||||||
border none
|
|
||||||
colorDangerButton()
|
|
||||||
|
|
||||||
body[data-theme="dark"]
|
body[data-theme="dark"]
|
||||||
.header
|
.header
|
||||||
border-color $ui-dark-borderColor
|
border-color $ui-dark-borderColor
|
||||||
@@ -153,28 +84,3 @@ body[data-theme="dark"]
|
|||||||
top 25px
|
top 25px
|
||||||
z-index 10
|
z-index 10
|
||||||
white-space nowrap
|
white-space nowrap
|
||||||
|
|
||||||
.folderList-item
|
|
||||||
&:hover
|
|
||||||
background-color lighten($ui-dark-button--hover-backgroundColor, 5%)
|
|
||||||
|
|
||||||
.folderList-item-left-danger
|
|
||||||
color $danger-color
|
|
||||||
font-weight bold
|
|
||||||
|
|
||||||
.folderList-item-left-key
|
|
||||||
color $ui-dark-inactive-text-color
|
|
||||||
|
|
||||||
.folderList-item-left-colorButton
|
|
||||||
colorDarkDefaultButton()
|
|
||||||
border-color $ui-dark-borderColor
|
|
||||||
|
|
||||||
.folderList-item-right-button
|
|
||||||
colorDarkDefaultButton()
|
|
||||||
border-color $ui-dark-borderColor
|
|
||||||
|
|
||||||
.folderList-item-right-confirmButton
|
|
||||||
colorDarkPrimaryButton()
|
|
||||||
|
|
||||||
.folderList-item-right-dangerButton
|
|
||||||
colorDarkDangerButton()
|
|
||||||
|
|||||||
@@ -13,6 +13,10 @@ $tab--dark-text-color = #E5E5E5
|
|||||||
font-size 36px
|
font-size 36px
|
||||||
margin-bottom 60px
|
margin-bottom 60px
|
||||||
|
|
||||||
|
.header--sub
|
||||||
|
font-size 36px
|
||||||
|
margin-bottom 20px
|
||||||
|
|
||||||
body[data-theme="dark"]
|
body[data-theme="dark"]
|
||||||
.header
|
.header
|
||||||
color $tab--dark-text-color
|
color $tab--dark-text-color
|
||||||
|
|||||||
@@ -9,6 +9,11 @@ import CodeMirror from 'codemirror'
|
|||||||
|
|
||||||
const OSX = global.process.platform === 'darwin'
|
const OSX = global.process.platform === 'darwin'
|
||||||
|
|
||||||
|
import _ from 'lodash'
|
||||||
|
|
||||||
|
const electron = require('electron')
|
||||||
|
const ipc = electron.ipcRenderer
|
||||||
|
|
||||||
class UiTab extends React.Component {
|
class UiTab extends React.Component {
|
||||||
constructor (props) {
|
constructor (props) {
|
||||||
super(props)
|
super(props)
|
||||||
@@ -18,10 +23,32 @@ class UiTab extends React.Component {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
componentDidMount () {
|
||||||
|
this.handleSettingDone = () => {
|
||||||
|
this.setState({UiAlert: {
|
||||||
|
type: 'success',
|
||||||
|
message: 'Successfully applied!'
|
||||||
|
}})
|
||||||
|
}
|
||||||
|
this.handleSettingError = (err) => {
|
||||||
|
this.setState({UiAlert: {
|
||||||
|
type: 'error',
|
||||||
|
message: err.message != null ? err.message : 'Error occurs!'
|
||||||
|
}})
|
||||||
|
}
|
||||||
|
ipc.addListener('APP_SETTING_DONE', this.handleSettingDone)
|
||||||
|
ipc.addListener('APP_SETTING_ERROR', this.handleSettingError)
|
||||||
|
}
|
||||||
|
|
||||||
componentWillMount () {
|
componentWillMount () {
|
||||||
CodeMirror.autoLoadMode(ReactCodeMirror, 'javascript')
|
CodeMirror.autoLoadMode(ReactCodeMirror, 'javascript')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
componentWillUnmount () {
|
||||||
|
ipc.removeListener('APP_SETTING_DONE', this.handleSettingDone)
|
||||||
|
ipc.removeListener('APP_SETTING_ERROR', this.handleSettingError)
|
||||||
|
}
|
||||||
|
|
||||||
handleUIChange (e) {
|
handleUIChange (e) {
|
||||||
const { codemirrorTheme } = this.state
|
const { codemirrorTheme } = this.state
|
||||||
let checkHighLight = document.getElementById('checkHighLight')
|
let checkHighLight = document.getElementById('checkHighLight')
|
||||||
@@ -36,6 +63,7 @@ class UiTab extends React.Component {
|
|||||||
const newConfig = {
|
const newConfig = {
|
||||||
ui: {
|
ui: {
|
||||||
theme: this.refs.uiTheme.value,
|
theme: this.refs.uiTheme.value,
|
||||||
|
showCopyNotification: this.refs.showCopyNotification.checked,
|
||||||
disableDirectWrite: this.refs.uiD2w != null
|
disableDirectWrite: this.refs.uiD2w != null
|
||||||
? this.refs.uiD2w.checked
|
? this.refs.uiD2w.checked
|
||||||
: false
|
: false
|
||||||
@@ -60,7 +88,7 @@ class UiTab extends React.Component {
|
|||||||
const newCodemirrorTheme = this.refs.editorTheme.value
|
const newCodemirrorTheme = this.refs.editorTheme.value
|
||||||
|
|
||||||
if (newCodemirrorTheme !== codemirrorTheme) {
|
if (newCodemirrorTheme !== codemirrorTheme) {
|
||||||
checkHighLight.setAttribute('href', `../node_modules/codemirror/theme/${newCodemirrorTheme}.css`)
|
checkHighLight.setAttribute('href', `../node_modules/codemirror/theme/${newCodemirrorTheme.split(' ')[0]}.css`)
|
||||||
}
|
}
|
||||||
|
|
||||||
this.setState({ config: newConfig, codemirrorTheme: newCodemirrorTheme })
|
this.setState({ config: newConfig, codemirrorTheme: newCodemirrorTheme })
|
||||||
@@ -79,9 +107,25 @@ class UiTab extends React.Component {
|
|||||||
type: 'SET_UI',
|
type: 'SET_UI',
|
||||||
config: newConfig
|
config: newConfig
|
||||||
})
|
})
|
||||||
|
this.clearMessage()
|
||||||
|
}
|
||||||
|
|
||||||
|
clearMessage () {
|
||||||
|
_.debounce(() => {
|
||||||
|
this.setState({
|
||||||
|
UiAlert: null
|
||||||
|
})
|
||||||
|
}, 2000)()
|
||||||
}
|
}
|
||||||
|
|
||||||
render () {
|
render () {
|
||||||
|
let UiAlert = this.state.UiAlert
|
||||||
|
let UiAlertElement = UiAlert != null
|
||||||
|
? <p className={`alert ${UiAlert.type}`}>
|
||||||
|
{UiAlert.message}
|
||||||
|
</p>
|
||||||
|
: null
|
||||||
|
|
||||||
const themes = consts.THEMES
|
const themes = consts.THEMES
|
||||||
const { config, codemirrorTheme } = this.state
|
const { config, codemirrorTheme } = this.state
|
||||||
const codemirrorSampleCode = 'function iamHappy (happy) {\n\tif (happy) {\n\t console.log("I am Happy!")\n\t} else {\n\t console.log("I am not Happy!")\n\t}\n};'
|
const codemirrorSampleCode = 'function iamHappy (happy) {\n\tif (happy) {\n\t console.log("I am Happy!")\n\t} else {\n\t console.log("I am not Happy!")\n\t}\n};'
|
||||||
@@ -97,11 +141,22 @@ class UiTab extends React.Component {
|
|||||||
onChange={(e) => this.handleUIChange(e)}
|
onChange={(e) => this.handleUIChange(e)}
|
||||||
ref='uiTheme'
|
ref='uiTheme'
|
||||||
>
|
>
|
||||||
<option value='default'>Light</option>
|
<option value='default'>Default</option>
|
||||||
|
<option value='white'>White</option>
|
||||||
<option value='dark'>Dark</option>
|
<option value='dark'>Dark</option>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div styleName='group-checkBoxSection'>
|
||||||
|
<label>
|
||||||
|
<input onChange={(e) => this.handleUIChange(e)}
|
||||||
|
checked={this.state.config.ui.showCopyNotification}
|
||||||
|
ref='showCopyNotification'
|
||||||
|
type='checkbox'
|
||||||
|
/>
|
||||||
|
Show "Saved to Clipboard" notification when copying
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
{
|
{
|
||||||
global.process.platform === 'win32'
|
global.process.platform === 'win32'
|
||||||
? <div styleName='group-checkBoxSection'>
|
? <div styleName='group-checkBoxSection'>
|
||||||
@@ -217,7 +272,7 @@ class UiTab extends React.Component {
|
|||||||
<option value='vim'>vim</option>
|
<option value='vim'>vim</option>
|
||||||
<option value='emacs'>emacs</option>
|
<option value='emacs'>emacs</option>
|
||||||
</select>
|
</select>
|
||||||
<span styleName='note-for-keymap'>Please restart boostnote after you change the keymap</span>
|
<p styleName='note-for-keymap'>⚠️ Please restart boostnote after you change the keymap</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -274,12 +329,11 @@ class UiTab extends React.Component {
|
|||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className='group-control'>
|
<div styleName='group-control'>
|
||||||
<button styleName='group-control-rightButton'
|
<button styleName='group-control-rightButton'
|
||||||
onClick={(e) => this.handleSaveUIClick(e)}
|
onClick={(e) => this.handleSaveUIClick(e)}>Save
|
||||||
>
|
|
||||||
Save
|
|
||||||
</button>
|
</button>
|
||||||
|
{UiAlertElement}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -4,10 +4,12 @@ import { connect } from 'react-redux'
|
|||||||
import HotkeyTab from './HotkeyTab'
|
import HotkeyTab from './HotkeyTab'
|
||||||
import UiTab from './UiTab'
|
import UiTab from './UiTab'
|
||||||
import InfoTab from './InfoTab'
|
import InfoTab from './InfoTab'
|
||||||
|
import Crowdfunding from './Crowdfunding'
|
||||||
import StoragesTab from './StoragesTab'
|
import StoragesTab from './StoragesTab'
|
||||||
import ModalEscButton from 'browser/components/ModalEscButton'
|
import ModalEscButton from 'browser/components/ModalEscButton'
|
||||||
import CSSModules from 'browser/lib/CSSModules'
|
import CSSModules from 'browser/lib/CSSModules'
|
||||||
import styles from './PreferencesModal.styl'
|
import styles from './PreferencesModal.styl'
|
||||||
|
import RealtimeNotification from 'browser/components/RealtimeNotification'
|
||||||
|
|
||||||
class Preferences extends React.Component {
|
class Preferences extends React.Component {
|
||||||
constructor (props) {
|
constructor (props) {
|
||||||
@@ -64,6 +66,10 @@ class Preferences extends React.Component {
|
|||||||
config={config}
|
config={config}
|
||||||
/>
|
/>
|
||||||
)
|
)
|
||||||
|
case 'CROWDFUNDING':
|
||||||
|
return (
|
||||||
|
<Crowdfunding />
|
||||||
|
)
|
||||||
case 'STORAGES':
|
case 'STORAGES':
|
||||||
default:
|
default:
|
||||||
return (
|
return (
|
||||||
@@ -94,7 +100,8 @@ class Preferences extends React.Component {
|
|||||||
{target: 'STORAGES', label: 'Storages'},
|
{target: 'STORAGES', label: 'Storages'},
|
||||||
{target: 'HOTKEY', label: 'Hotkey'},
|
{target: 'HOTKEY', label: 'Hotkey'},
|
||||||
{target: 'UI', label: 'UI'},
|
{target: 'UI', label: 'UI'},
|
||||||
{target: 'INFO', label: 'Info'}
|
{target: 'INFO', label: 'Community / Info'},
|
||||||
|
{target: 'CROWDFUNDING', label: 'Crowdfunding'}
|
||||||
]
|
]
|
||||||
|
|
||||||
let navButtons = tabs.map((tab) => {
|
let navButtons = tabs.map((tab) => {
|
||||||
@@ -130,6 +137,7 @@ class Preferences extends React.Component {
|
|||||||
<div ref='content' styleName='content'>
|
<div ref='content' styleName='content'>
|
||||||
{content}
|
{content}
|
||||||
</div>
|
</div>
|
||||||
|
<RealtimeNotification />
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -346,6 +346,13 @@ function data (state = defaultDataMap(), action) {
|
|||||||
state.storageMap.set(action.storage.key, action.storage)
|
state.storageMap.set(action.storage.key, action.storage)
|
||||||
}
|
}
|
||||||
return state
|
return state
|
||||||
|
case 'REORDER_FOLDER':
|
||||||
|
{
|
||||||
|
state = Object.assign({}, state)
|
||||||
|
state.storageMap = new Map(state.storageMap)
|
||||||
|
state.storageMap.set(action.storage.key, action.storage)
|
||||||
|
}
|
||||||
|
return state
|
||||||
case 'DELETE_FOLDER':
|
case 'DELETE_FOLDER':
|
||||||
{
|
{
|
||||||
state = Object.assign({}, state)
|
state = Object.assign({}, state)
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ $danger-color = #c9302c
|
|||||||
$danger-lighten-color = lighten(#c9302c, 5%)
|
$danger-lighten-color = lighten(#c9302c, 5%)
|
||||||
|
|
||||||
// Layouts
|
// Layouts
|
||||||
$statusBar-height = 36px
|
$statusBar-height = 0px
|
||||||
$sideNav-width = 200px
|
$sideNav-width = 200px
|
||||||
$sideNav--folded-width = 44px
|
$sideNav--folded-width = 44px
|
||||||
$topBar-height = 60px
|
$topBar-height = 60px
|
||||||
@@ -15,18 +15,18 @@ $ui-text-color = #333333
|
|||||||
$ui-inactive-text-color = #939395
|
$ui-inactive-text-color = #939395
|
||||||
$ui-borderColor = #D1D1D1
|
$ui-borderColor = #D1D1D1
|
||||||
$ui-backgroundColor = #FFFFFF
|
$ui-backgroundColor = #FFFFFF
|
||||||
$ui-noteList-backgroundColor = #F3F3F3
|
$ui-noteList-backgroundColor = #FBFBFB
|
||||||
$ui-noteDetail-backgroundColor = #F4F4F4
|
$ui-noteDetail-backgroundColor = #FFFFFF
|
||||||
$ui-border = solid 1px $ui-borderColor
|
$ui-border = solid 1px $ui-borderColor
|
||||||
$ui-active-color = #6AA5E9
|
$ui-active-color = #6AA5E9
|
||||||
$ui-tag-backgroundColor = rgba(0, 0, 0, 0.3)
|
$ui-tag-backgroundColor = rgba(0, 0, 0, 0.3)
|
||||||
|
|
||||||
// UI Button
|
// UI Default Button
|
||||||
$ui-button-color = #939395
|
$ui-button-default-color = #FBFBFB
|
||||||
$ui-button--hover-backgroundColor = #D9D9D9
|
$ui-button-default--hover-backgroundColor = #2B8976
|
||||||
$ui-button--active-color = white
|
$ui-button-default--active-color = white
|
||||||
$ui-button--active-backgroundColor = #D9D9D9
|
$ui-button-default--active-backgroundColor = #2B8976
|
||||||
$ui-button--focus-borderColor = lighten(#369DCD, 25%)
|
$ui-button-default--focus-borderColor = lighten(#369DCD, 25%)
|
||||||
|
|
||||||
// UI Tooltip
|
// UI Tooltip
|
||||||
$ui-tooltip-text-color = white
|
$ui-tooltip-text-color = white
|
||||||
@@ -119,6 +119,22 @@ colorDangerButton()
|
|||||||
&:active:hover
|
&:active:hover
|
||||||
background-color $danger-button-background--active
|
background-color $danger-button-background--active
|
||||||
|
|
||||||
|
/**
|
||||||
|
* SideNav
|
||||||
|
*/
|
||||||
|
SideNavFilter()
|
||||||
|
background-color $ui-button-default--active-backgroundColor
|
||||||
|
.counters
|
||||||
|
color $ui-button-default-color
|
||||||
|
.menu-button-label
|
||||||
|
color $ui-button-default-color
|
||||||
|
&:hover
|
||||||
|
background-color alpha($ui-button-default--hover-backgroundColor, 20%)
|
||||||
|
&:active, &:active:hover
|
||||||
|
background-color alpha($ui-button-default--hover-backgroundColor, 20%)
|
||||||
|
.menu-button-label
|
||||||
|
color #1EC38B
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Nav
|
* Nav
|
||||||
*/
|
*/
|
||||||
@@ -129,13 +145,12 @@ navButtonColor()
|
|||||||
background-color transparent
|
background-color transparent
|
||||||
transition 0.15s
|
transition 0.15s
|
||||||
&:hover
|
&:hover
|
||||||
background-color alpha($ui-button--active-backgroundColor, 20%)
|
|
||||||
transition 0.15s
|
transition 0.15s
|
||||||
color $ui-text-color
|
color $ui-button-default-color
|
||||||
&:active, &:active:hover
|
&:active, &:active:hover
|
||||||
background-color $ui-button--active-backgroundColor
|
color $ui-button-default-color
|
||||||
color $ui-text-color
|
|
||||||
transition 0.15s
|
transition 0.15s
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* # Modal Stuff
|
* # Modal Stuff
|
||||||
* These will be moved lib/modal
|
* These will be moved lib/modal
|
||||||
@@ -159,23 +174,53 @@ modal()
|
|||||||
border-radius $modal-border-radius
|
border-radius $modal-border-radius
|
||||||
|
|
||||||
topBarButtonLight()
|
topBarButtonLight()
|
||||||
|
position absolute
|
||||||
width 34px
|
width 34px
|
||||||
height 34px
|
height 34px
|
||||||
border-radius 17px
|
border-radius 17px
|
||||||
font-size 14px
|
font-size 14px
|
||||||
margin 15px 7px
|
|
||||||
border none
|
border none
|
||||||
color $ui-button-color
|
color alpha($ui-button-color, 0.4)
|
||||||
fill $ui-button-color
|
fill $ui-button-color
|
||||||
background-color transparent
|
background-color transparent
|
||||||
&:active
|
&:active
|
||||||
border-color $ui-button--active-backgroundColor
|
border-color $ui-button--active-backgroundColor
|
||||||
&:hover
|
&:hover
|
||||||
background-color alpha($ui-button--hover-backgroundColor, 60%)
|
transform scale(1.1)
|
||||||
|
transition 0.4s
|
||||||
|
color $ui-button-color
|
||||||
.control-lockButton-tooltip
|
.control-lockButton-tooltip
|
||||||
opacity 1
|
opacity 1
|
||||||
|
|
||||||
// Dark theme
|
// White theme
|
||||||
|
$ui-white-noteList-backgroundColor = #F3F3F3
|
||||||
|
$ui-white-noteDetail-backgroundColor = #F4F4F4
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Nav
|
||||||
|
*/
|
||||||
|
navWhiteButtonColor()
|
||||||
|
border none
|
||||||
|
color $ui-button-color
|
||||||
|
background-color transparent
|
||||||
|
transition 0.15s
|
||||||
|
&:hover
|
||||||
|
background-color alpha($ui-button--active-backgroundColor, 20%)
|
||||||
|
transition 0.15s
|
||||||
|
color $ui-text-color
|
||||||
|
&:active, &:active:hover
|
||||||
|
background-color $ui-button--active-backgroundColor
|
||||||
|
color $ui-text-color
|
||||||
|
transition 0.15s
|
||||||
|
|
||||||
|
// UI Button
|
||||||
|
$ui-button-color = #939395
|
||||||
|
$ui-button--hover-backgroundColor = #F6F6F6
|
||||||
|
$ui-button--active-color = white
|
||||||
|
$ui-button--active-backgroundColor = #D9D9D9
|
||||||
|
$ui-button--focus-borderColor = lighten(#369DCD, 25%)
|
||||||
|
|
||||||
|
/******* Dark theme ********/
|
||||||
$ui-dark-active-color = #3A404C
|
$ui-dark-active-color = #3A404C
|
||||||
$ui-dark-borderColor = lighten(#21252B, 20%)
|
$ui-dark-borderColor = lighten(#21252B, 20%)
|
||||||
$ui-dark-backgroundColor = #1E2124
|
$ui-dark-backgroundColor = #1E2124
|
||||||
@@ -233,12 +278,10 @@ topBarButtonDark()
|
|||||||
border-color $ui-dark-borderColor
|
border-color $ui-dark-borderColor
|
||||||
color $ui-dark-topbar-button-color
|
color $ui-dark-topbar-button-color
|
||||||
&:hover
|
&:hover
|
||||||
background-color $dark-default-button-background--hover
|
|
||||||
color $ui-dark-tooltip-text-color
|
color $ui-dark-tooltip-text-color
|
||||||
&:active
|
&:active
|
||||||
border-color $ui-dark-button--focus-borderColor
|
border-color $ui-dark-button--focus-borderColor
|
||||||
&:active:hover
|
&:active:hover
|
||||||
background-color $ui-dark-button--active-backgroundColor
|
|
||||||
color $ui-dark-tooltip-text-color
|
color $ui-dark-tooltip-text-color
|
||||||
&:focus
|
&:focus
|
||||||
border-color $ui-button--focus-borderColor
|
border-color $ui-button--focus-borderColor
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
# Build
|
# Build
|
||||||
This page is also available in [Japanese](https://github.com/BoostIO/Boostnote/blob/master/docs/jp/build.md), [Korean](https://github.com/BoostIO/Boostnote/blob/master/docs/ko/build.md), [Russain](https://github.com/BoostIO/Boostnote/blob/master/docs/ru/build.md), and [Simplified Chinese](https://github.com/BoostIO/Boostnote/blob/master/docs/zh_CN/build.md).
|
This page is also available in [Japanese](https://github.com/BoostIO/Boostnote/blob/master/docs/jp/build.md), [Korean](https://github.com/BoostIO/Boostnote/blob/master/docs/ko/build.md), [Russain](https://github.com/BoostIO/Boostnote/blob/master/docs/ru/build.md), [Simplified Chinese](https://github.com/BoostIO/Boostnote/blob/master/docs/zh_CN/build.md), and [French](https://github.com/BoostIO/Boostnote/blob/master/docs/fr/build.md).
|
||||||
|
|
||||||
## Environments
|
## Environments
|
||||||
* npm: 4.x
|
* npm: 4.x
|
||||||
* node: 7.x
|
* node: 7.x
|
||||||
|
|
||||||
You should use `npm v4.x` because `$ grand pre-build` fails on `v5.x`.
|
You should use `npm v4.x` because `$ grunt pre-build` fails on `v5.x`.
|
||||||
|
|
||||||
## Development
|
## Development
|
||||||
|
|
||||||
@@ -53,3 +53,32 @@ grunt pre-build
|
|||||||
You will find the executable in the `dist` directory. Note, the auto updater won't work because the app isn't signed.
|
You will find the executable in the `dist` directory. Note, the auto updater won't work because the app isn't signed.
|
||||||
|
|
||||||
If you find it necessary, you can use codesign or authenticode with this executable.
|
If you find it necessary, you can use codesign or authenticode with this executable.
|
||||||
|
|
||||||
|
## Make own distribution packages (deb, rpm)
|
||||||
|
|
||||||
|
Distribution packages are created by exec `grunt build` on Linux platform (e.g. Ubuntu, Fedora).
|
||||||
|
|
||||||
|
> Note: You can create both `.deb` and `.rpm` in a single environment.
|
||||||
|
|
||||||
|
After installing the supported version of `node` and `npm`, install build dependency packages.
|
||||||
|
|
||||||
|
|
||||||
|
Ubuntu/Debian:
|
||||||
|
|
||||||
|
```
|
||||||
|
$ sudo apt-get install -y rpm fakeroot
|
||||||
|
```
|
||||||
|
|
||||||
|
Fedora:
|
||||||
|
|
||||||
|
```
|
||||||
|
$ sudo dnf install -y dpkg dpkg-dev rpm-build fakeroot
|
||||||
|
```
|
||||||
|
|
||||||
|
Then execute `grunt build`.
|
||||||
|
|
||||||
|
```
|
||||||
|
$ grunt build
|
||||||
|
```
|
||||||
|
|
||||||
|
You will find `.deb` and `.rpm` in the `dist` directory.
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
# How to debug Boostnote (Electron app)
|
# How to debug Boostnote (Electron app)
|
||||||
This page is also available in [Japanese](https://github.com/BoostIO/Boostnote/blob/master/docs/jp/debug.md), [Russain](https://github.com/BoostIO/Boostnote/blob/master/docs/ru/debug.md), and [Simplified Chinese](https://github.com/BoostIO/Boostnote/blob/master/docs/zh_CN/debug.md)
|
This page is also available in [Japanese](https://github.com/BoostIO/Boostnote/blob/master/docs/jp/debug.md), [Korean](https://github.com/BoostIO/Boostnote/blob/master/docs/ko/debug.md), [Russain](https://github.com/BoostIO/Boostnote/blob/master/docs/ru/debug.md), [Simplified Chinese](https://github.com/BoostIO/Boostnote/blob/master/docs/zh_CN/debug.md), and [French](https://github.com/BoostIO/Boostnote/blob/master/docs/fr/debug.md).
|
||||||
|
|
||||||
Boostnote is an Electron app so it's based on Chromium; developers can use `Developer Tools` just like Google Chrome.
|
Boostnote is an Electron app so it's based on Chromium; developers can use `Developer Tools` just like Google Chrome.
|
||||||
|
|
||||||
|
|||||||
83
docs/fr/build.md
Normal file
83
docs/fr/build.md
Normal file
@@ -0,0 +1,83 @@
|
|||||||
|
# Build
|
||||||
|
Cette page est également disponible en [Japonais](https://github.com/BoostIO/Boostnote/blob/master/docs/jp/build.md), [Coréen](https://github.com/BoostIO/Boostnote/blob/master/docs/ko/build.md), [Russe](https://github.com/BoostIO/Boostnote/blob/master/docs/ru/build.md), et en [Chinois Simplifié](https://github.com/BoostIO/Boostnote/blob/master/docs/zh_CN/build.md).
|
||||||
|
|
||||||
|
## Environnements
|
||||||
|
* npm: 4.x
|
||||||
|
* node: 7.x
|
||||||
|
|
||||||
|
Il est conseillé d'utiliser `npm v4.x` car `$ grunt pre-build` ne marche pas sur la `v5.x`.
|
||||||
|
|
||||||
|
## Développement
|
||||||
|
|
||||||
|
Webpack HMR est utilisé pour développer Boostnote.
|
||||||
|
En utilisant les commandes suivantes à la racine du projet, cela va démarrer Boostnote avec les configurations par défaut.
|
||||||
|
|
||||||
|
Installez les paquets requis à l'aide de `yarn`.
|
||||||
|
|
||||||
|
```
|
||||||
|
$ yarn
|
||||||
|
```
|
||||||
|
Build et start
|
||||||
|
|
||||||
|
```
|
||||||
|
$ yarn run dev-start
|
||||||
|
```
|
||||||
|
|
||||||
|
Cette commande lance `yarn run webpack` et `yarn run hot` en parallèle. Cela revient au même que si on utilisait ces deux commandes dans 2 terminaux.
|
||||||
|
|
||||||
|
La commande `webpack` va surveiller les changements de code et les appliquer automatiquement.
|
||||||
|
|
||||||
|
Si l'erreur suivante apparait : `Failed to load resource: net::ERR_CONNECTION_REFUSED`, relancez Boostnote.
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
> ### Notice
|
||||||
|
> Il y a certains cas où vous voudrez relancer l'application manuellement.
|
||||||
|
> 1. Quand vous éditez la méthode constructeur dans un composant
|
||||||
|
> 2. Quand vous ajoutez une nouvelle classe css. (Comme pour 1: la classe est réécrite pour chaque composant. Le process intervient dans la méthode constructeur)
|
||||||
|
|
||||||
|
## Déploiement
|
||||||
|
|
||||||
|
On utilise Grunt pour le déploiement automatique.
|
||||||
|
Vous pouvez build le programme en utilisant `grunt`. Cependant, nous ne recommandons pas cette méthode car la task par défaut inclut codesign et authenticode.
|
||||||
|
|
||||||
|
Nous avons donc préparé un script séparé qui va rendre un fichier exécutable.
|
||||||
|
|
||||||
|
Le build ne fonctionne pas sur `npm v5.3.0`. Il faut donc utiliser `npm v5.2.0` quand vous faites le build.
|
||||||
|
|
||||||
|
```
|
||||||
|
grunt pre-build
|
||||||
|
```
|
||||||
|
Vous trouverez l'exécutable dans le dossier `dist`.
|
||||||
|
Note : l'auto updater ne marchera pas car l'application n'est pas signée.
|
||||||
|
|
||||||
|
Si vous trouvez ça nécessaire, vous pouvez utiliser codesign ou authenticode avec cet exécutable.
|
||||||
|
|
||||||
|
## Faire un paquet (deb, rpm)
|
||||||
|
|
||||||
|
Les paquets sont créés en exécutant `grunt build` sur une plateforme Linux (e.g. Ubuntu, Fedora).
|
||||||
|
|
||||||
|
> Note: Vous pouvez créer à la fois un `.deb` et un `.rpm` dans un seul et même environnement.
|
||||||
|
|
||||||
|
Après avoir installé la version supportée de `node` et de `npm`, installer les paquets de builds.
|
||||||
|
|
||||||
|
|
||||||
|
Ubuntu/Debian:
|
||||||
|
|
||||||
|
```
|
||||||
|
$ sudo apt-get install -y rpm fakeroot
|
||||||
|
```
|
||||||
|
|
||||||
|
Fedora:
|
||||||
|
|
||||||
|
```
|
||||||
|
$ sudo dnf install -y dpkg dpkg-dev rpm-build fakeroot
|
||||||
|
```
|
||||||
|
|
||||||
|
Puis exécutez `grunt build`.
|
||||||
|
|
||||||
|
```
|
||||||
|
$ grunt build
|
||||||
|
```
|
||||||
|
|
||||||
|
Vous trouverez le `.deb` et le `.rpm` dans le dossier `dist`.
|
||||||
22
docs/fr/debug.md
Normal file
22
docs/fr/debug.md
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
# Comment débugger Boostnote (Application Electron)
|
||||||
|
Cette page est également disponible en [Japonais](https://github.com/BoostIO/Boostnote/blob/master/docs/jp/debug.md), [Coréen](https://github.com/BoostIO/Boostnote/blob/master/docs/ko/debug.md), [Russe](https://github.com/BoostIO/Boostnote/blob/master/docs/ru/debug.md), et en [Chinois Simplifié](https://github.com/BoostIO/Boostnote/blob/master/docs/zh_CN/debug.md)
|
||||||
|
|
||||||
|
Boostnote est une application Electron donc basée sur Chromium. Il est possible d'utiliser les `Developer Tools` comme dans Google Chrome.
|
||||||
|
|
||||||
|
Vous pouvez utiliser les `Developer Tools` de la façon suivante :
|
||||||
|

|
||||||
|
|
||||||
|
Les `Developer Tools` ressemblent à ça :
|
||||||
|

|
||||||
|
|
||||||
|
Quand une erreur arrive, les messages d'erreurs sont affichés dans la `console`.
|
||||||
|
|
||||||
|
## Debugging
|
||||||
|
Par exemple, vous pouvez utiliser le `debugger` pour placer un point d'arrêt dans le code de la façon suivante:
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
C'est une façon comme une autre de faire, vous pouvez trouver une façon de débugger que vous trouverez plus adaptée.
|
||||||
|
|
||||||
|
## Références
|
||||||
|
* [Documentation officiel de Google Chrome sur le debugging](https://developer.chrome.com/devtools)
|
||||||
@@ -46,3 +46,32 @@ grunt pre-build
|
|||||||
実行ファイルは`dist`から見つかります。この場合、認証されていないため、自動アップデーターは使えません。
|
実行ファイルは`dist`から見つかります。この場合、認証されていないため、自動アップデーターは使えません。
|
||||||
|
|
||||||
必要であれば、この実行ファイルからCodesignやAuthenticodeなどの署名ができます。
|
必要であれば、この実行ファイルからCodesignやAuthenticodeなどの署名ができます。
|
||||||
|
|
||||||
|
## ディストリビューション用パッケージ (deb, rpm)
|
||||||
|
|
||||||
|
ディストリビューション用パッケージはLinuxプラットフォーム(Ubuntu や Fedora)上で `grunt build` を実行する事で作成されます。
|
||||||
|
|
||||||
|
> 一つの環境で `.deb` と `.rpm` の両方を作成する事が出来ます。
|
||||||
|
|
||||||
|
|
||||||
|
対応するバージョンの `node` と `npm` をインストールした後、必要なパッケージをインストールします。
|
||||||
|
|
||||||
|
Ubuntu/Debian:
|
||||||
|
|
||||||
|
```
|
||||||
|
$ sudo apt-get install -y rpm fakeroot
|
||||||
|
```
|
||||||
|
|
||||||
|
Fedora:
|
||||||
|
|
||||||
|
```
|
||||||
|
$ sudo dnf install -y dpkg dpkg-dev rpm-build fakeroot
|
||||||
|
```
|
||||||
|
|
||||||
|
`grunt build` を実行します。
|
||||||
|
|
||||||
|
```
|
||||||
|
$ grunt build
|
||||||
|
```
|
||||||
|
|
||||||
|
`.deb` と `.rpm` は `dist` 配下に作成されます。
|
||||||
|
|||||||
@@ -1,43 +1,49 @@
|
|||||||
# Build
|
# Build
|
||||||
|
|
||||||
|
## 환경
|
||||||
|
* npm: 4.x
|
||||||
|
* node: 7.x
|
||||||
|
|
||||||
|
`$ grunt pre-build`를 `npm v5.x`에서 실행할 수 없기 때문에, 반드시 `npm v4.x`를 사용하셔야 합니다.
|
||||||
|
|
||||||
## 개발
|
## 개발
|
||||||
|
|
||||||
Webpack HRM을 개발을 위해 사용합니다.
|
개발에 있어서 Webpack HRM을 사용합니다.
|
||||||
다음 명령을 통해 저희가 해둔 설정을 사용 할 수 있습니다.
|
다음과 같은 명령을 프로젝트 디렉토리에서 실행하면, 기본 설정을 사용 할 수 있습니다.
|
||||||
|
|
||||||
|
먼저, yarn을 이용해서 필요한 패키지들을 설치합니다.
|
||||||
|
|
||||||
```
|
```
|
||||||
yarn run webpack
|
$ yarn
|
||||||
```
|
```
|
||||||
|
|
||||||
몇 초 후, 다음 메세지를 보게 될겁니다.
|
그 다음, 아래의 명령으로 빌드를 끝내고 자동적으로 어플리케이션을 실행합니다.
|
||||||
|
|
||||||
```
|
```
|
||||||
webpack: bundle is now VALID.
|
$ yarn run dev-start
|
||||||
```
|
```
|
||||||
|
|
||||||
그럼 앱을 실행합시다.
|
이 명령은 `yarn run webpack` 과 `yarn run hot`을 동시에 실행합니다. 이는 두개의 터미널에서 각각의 명령을 동시에 실행하는 것과 같습니다.
|
||||||
|
|
||||||
```
|
`Webpack`은 코드의 변화를 자동으로 탐지하여 적용시키는 역할을 합니다.
|
||||||
yarn run hot
|
|
||||||
```
|
|
||||||
|
|
||||||
> 원래 앱은 `yarn start`로 실행가능합니다. 하지만 이 경우, 컴파일된 스크립트를 사용할 것입니다.
|
만약, `Failed to load resource: net::ERR_CONNECTION_REFUSED`과 같은 에러가 나타난다면 Boostnote를 리로드해주세요.
|
||||||
|
|
||||||
이로써 웹팩이 자동적으로 코드변경을 확인하고 적용해줄 것입니다.
|

|
||||||
|
|
||||||
> ### 주의
|
> ### 주의
|
||||||
> 가끔 직접 리프레쉬를 해주어야 하는 경우가 있습니다.
|
> 가끔 직접 리프레쉬를 해주어야 하는 경우가 있습니다.
|
||||||
> 1. 콤포넌트의 컨스트럭터 함수를 수정할 경우샐
|
> 1. 콤포넌트의 컨스트럭터 함수를 수정할 경우
|
||||||
> 2. 새로운 CSS코드를 추가할 경우(1.과 같은 이유: CSS클래스는 콤포넌트마다 다시 만들어 지는데, 이 작업은 컨스트럭터에서 일어납니다.)
|
> 2. 새로운 CSS코드를 추가할 경우(1.과 같은 이유: CSS클래스는 콤포넌트마다 다시 만들어 지는데, 이 작업은 컨스트럭터에서 일어납니다.)
|
||||||
|
|
||||||
## 배포
|
## 배포
|
||||||
|
|
||||||
그런트를 사용합니다.
|
Boostnote에서는 배포 자동화를 위하여 그런트를 사용합니다.
|
||||||
실제 디플로이는 `grunt`로 실행할 수 있습니다. 하지만, 여기엔 Codesign과 Authenticode의 과정이 포함되어있기 때문에 사용 하셔선 안됩니다.
|
실제 배포는 `grunt`로 실행할 수 있습니다. 하지만, 여기엔 Codesign과 Authenticode의 과정이 포함되어있기 때문에 사용 하셔선 안됩니다.
|
||||||
|
|
||||||
그래서, 실행파일만을 만드는 스크립트를 준비해 뒀습니다.
|
그래서, 실행파일만을 만드는 스크립트를 준비해 뒀습니다.
|
||||||
|
|
||||||
This build doesn't work on npm v5.3.0. So you need to use v5.2.0 when you build it.
|
이 빌드는 npm v5.3.0에서는 작동하지 않습니다. 그러므로, 성공적으로 빌드하기 위해서는 v5.2.0을 사용해야 합니다.
|
||||||
|
|
||||||
```
|
```
|
||||||
grunt pre-build
|
grunt pre-build
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user