1
0
mirror of https://github.com/BoostIo/Boostnote synced 2025-12-14 10:16:26 +00:00

Compare commits

..

61 Commits

Author SHA1 Message Date
Rokt33r
7fcaaa297a Merge branch 'dev'
* dev:
  alert fix
  debug missing argument
  bump version
  rollback: setVisibleOnAllWorkspaces(true)
  FinderのActivity logをちゃんと取ってくる
  FinderのInputにLato fontが使われていない問題修正
  Search inputにRegExp operatorが入ると使えなかった問題改善
  User name change and modify style

Conflicts:
	package.json
2015-12-04 04:56:55 +09:00
Rokt33r
7c2d2044a9 alert fix 2015-12-04 04:56:04 +09:00
Rokt33r
aa32f59dc6 debug missing argument 2015-12-03 12:15:07 +09:00
Rokt33r
182af99e7c bump version 2015-12-03 12:02:29 +09:00
Rokt33r
5b520a7a81 rollback: setVisibleOnAllWorkspaces(true) 2015-12-03 12:02:21 +09:00
Rokt33r
364917c910 FinderのActivity logをちゃんと取ってくる 2015-12-03 07:59:47 +09:00
Rokt33r
ca7b9c786a FinderのInputにLato fontが使われていない問題修正 2015-12-03 07:25:35 +09:00
Rokt33r
15c2363098 Search inputにRegExp operatorが入ると使えなかった問題改善 2015-12-03 06:44:52 +09:00
Rokt33r
1a11095121 User name change and modify style 2015-12-03 05:32:10 +09:00
Rokt33r
2b384b1d15 fix updater bug 2015-12-01 02:00:18 +09:00
Rokt33r
a1d61edb9c Merge branch 'dev'
* dev:
  bump version
  Folder create modalを出したら、まっすぐName inputをFocusする
  編集警告が出ている時にCode editorがキー入力を認識する問題解決
  External link動きDebug
  add copy button
  External link用のDropdown menu追加
  コードを綺麗に
  Titleがなかったら灰色でUntitleと出す
  新規投稿 Cmd + n / Preview Cmd + P 追加
  articleのタイトルの基本タイトル追加 / 何も書かれていない時にUntitled labelをだす
  Finderのvisibile on all workspaces解除
  Searchbar tooltip changed(add exact match)
  change tray menu label(Open Finder => Open FInder window)
  Main windowの visible on all worpspace解除

Conflicts:
	package.json
2015-12-01 00:10:15 +09:00
Rokt33r
96a8687896 bump version 2015-11-30 23:11:31 +09:00
Rokt33r
0448773682 Folder create modalを出したら、まっすぐName inputをFocusする 2015-11-30 16:28:14 +09:00
Rokt33r
57998ba727 編集警告が出ている時にCode editorがキー入力を認識する問題解決 2015-11-30 16:22:10 +09:00
Rokt33r
de83447cb3 External link動きDebug 2015-11-30 12:53:46 +09:00
Rokt33r
eba19468d5 add copy button 2015-11-30 12:53:21 +09:00
Rokt33r
65c78df671 External link用のDropdown menu追加 2015-11-30 11:14:16 +09:00
Rokt33r
a7096aa89f コードを綺麗に 2015-11-30 04:28:23 +09:00
Rokt33r
15a50ef452 Titleがなかったら灰色でUntitleと出す 2015-11-30 04:17:52 +09:00
Rokt33r
04036e5c87 新規投稿 Cmd + n / Preview Cmd + P 追加 2015-11-30 03:44:58 +09:00
Rokt33r
2bbb5ef74e articleのタイトルの基本タイトル追加 / 何も書かれていない時にUntitled labelをだす 2015-11-29 18:57:49 +09:00
Rokt33r
91eb7feb3c Finderのvisibile on all workspaces解除 2015-11-29 11:08:13 +09:00
Rokt33r
978d77142c Searchbar tooltip changed(add exact match) 2015-11-29 11:05:18 +09:00
Rokt33r
e36478b9ac modify method name (api changed as electron updated) 2015-11-25 10:49:06 +09:00
Rokt33r
e1fe4dd693 change to use HTTPS for checking update 2015-11-25 09:51:33 +09:00
Rokt33r
b1ee949b1c This is a release version 2015-11-25 09:40:07 +09:00
Rokt33r
a0e5f8e97e Merge commit '80a0c59f878d899fc21b72f08eb8afeb1970f9ba'
* commit '80a0c59f878d899fc21b72f08eb8afeb1970f9ba':
  make it as prerelease
  bump up version
  MarkdownのCodeblockの行間をひろげる 
  編集中キャンセルを押しても消える情報があれば警告をだす
  データ移転バグ修正
  最初以降からはUpdaterがエラーをださない。
  Stream EPIPEエラー解決、データはこれからJSON保存
  notification デバッグ
  intercept entry point
  using ipc but not working in production
  bump up electron version 0.34 -> 0.35.1
  MarkdownでEmojiが使える
  Markdown内のコードにSyntax highlightenをいれる

Conflicts:
	main.js
2015-11-25 09:08:13 +09:00
Rokt33r
e9cfb2c4ee change tray menu label(Open Finder => Open FInder window) 2015-11-25 08:59:43 +09:00
Rokt33r
190b6edfb1 Main windowの visible on all worpspace解除 2015-11-25 08:50:56 +09:00
Rokt33r
ee4ac7371c Merge branch 'dev'
* dev:
  No node-notifier
  fix: 新しい記事を書く時に発生するバグ一体
  cleanup notification code
  Default文書修正
  開発中のものはデータを送らない
  初期記事内容修正cmd -> ctrl
  show devtool only devmode

Conflicts:
	main.js
2015-11-22 16:31:48 +09:00
Rokt33r
e731b7882d Merge branch 'dev'
* dev:
  no source map
  bump version
  hidden code
2015-11-21 06:05:17 +09:00
Rokt33r
ee91daad7e Merge branch 'dev'
* dev:
  hotfix: Edited alertが変な時に出る
2015-11-18 18:51:39 +09:00
Dick Choi
09482ebcf3 fix wrong dependency 2015-11-17 05:36:08 +09:00
Rokt33r
67424f2d3a Merge branch 'dev'
* dev:
  bump up version 0.4.1
  記事が編集された状態で他の記事を見ようとすると警告をだす
  updateが準備できたら、再起動されるまで改めてUpdateの確認をしない
  Tag suggest
  EnterでSubmitができる - Hotkey, folder edit, folder create(preference/create new folder modal両方)
  Folderの位置を変えることができる
  Preferenceからもフォルダーの色の選択ができる。
  // filterを使うと確実にFolder名が一致するもののみを表示する
  fix style
  new folder modalにcolor select追加
  auto update確認
  FinderからCopyした時、通知を出す
  FinderにCopy to clipboard button追加
  Folder リストに articleの数をだす
  フォルダーで検索するときに in:じゃなくて /にする +バグ修正
  IntroのFinder説明変更
2015-11-16 07:03:46 +09:00
Rokt33r
61cc44cc83 Merge branch 'dev'
* dev:
  0.4.0-beta.2
  tutorial 追加
  ModeSelect
  行動データ, contact form, default articleに英語文追加, Intro fix
  Hotkey settingの時Alertで結果を出す Folder nameが長すぎ雨時のlayout崩れ解決 ArticleNavigatorの余計なスペースをなくす Default articleの誤字直し
  Cmd+Sで保存 debug craetedAt
  fix Title overflow behaviour
  0.4.0-beta.1

Conflicts:
	package.json
2015-11-11 03:09:28 +09:00
Rokt33r
59d3c6c94f 0.4.0-beta.1 2015-11-05 10:33:14 +09:00
Rokt33r
388027b731 Merge branch 'dev'
* dev:
  beta - add error alert(folder editing) - debug clear button of search input
2015-11-05 09:50:39 +09:00
Rokt33r
9758f5baa8 release version 0.4.0-alpha.7 2015-11-02 16:13:31 +09:00
Rokt33r
248262a597 Merge branch 'dev'
* dev: (43 commits)
  webpack bugfix, tooltip modified, preview button string changed(toggle Preview -> Preview / Edit)
  tooltip, tutorial追加
  ArticleListに自動scroll機能追加
  Tooltip追加、キー反応改善、Pinch2Zoom使用禁止、Webpack config debug
  編集状態でのMarkdown preview追加
  Key入力の動き改善 - Searchに内容がある時にEscを押すと内容をSearchの内容を削除する - Cmd + Fを押すとSearch inputがfocusされる
  Key入力追加
  prepare alpha.5 (remain work: MD preview, keybind)
  Going LIte
  add Team destroy
  add text:ellipsis to some labels & add member deletion confirm
  bump alpha.3
  add folder create
  add Member setting, Team setting, FolderSetting(80%) bump react-select
  bumpup alpha.2
  addTag search
  add Invalid token handler
  bumpup react (0.13.3->0.14.0), reacthmr work perfectly
  fix updater bug
  Folder indexing
  ...
2015-11-02 16:12:08 +09:00
Rokt33r
3f54eb52b2 Merge branch 'dev'
* dev:
  リアルタイム(SocketIO)実装 / Markdown style改善

Conflicts:
	package.json
2015-09-08 15:30:02 +09:00
Rokt33r
1e7415b692 fix version 0.2.11 2015-09-06 19:48:44 +09:00
Rokt33r
ff950ef28a Merge branch 'dev'
* dev:
  improve markdown style
2015-09-06 12:19:20 +09:00
Rokt33r
5fa37dbffb Merge branch 'dev'
* dev:
  version 0.2.10 - Hotkeyの設定機能 - Stylus refactor
2015-09-02 01:02:32 +09:00
Rokt33r
06a54d451c Merge branch 'dev'
* dev:
  0.2.9 API server changed, bump electron version 0.31.0
2015-08-31 01:34:15 +09:00
Rokt33r
45541a255b Merge branch 'dev'
* dev:
  - StylusでコンパイルされたCSSをCachingする(ロディングが短くなる) - Planet name changeのときにエラーハンドリング追加 + Bug fix - TeamのMemberを編集する場合、自分を編集することはできない - FinderにMarkdownのリンクがちゃんと外部に飛ぶように - Tray iconがちゃんと表示 - ArticleDetailのCodeアイコンがちゃんと表示されない
2015-08-30 05:31:13 +09:00
Rokt33r
345d7b427a Merge branch 'dev'
* dev:
  Loading font 微調整
2015-08-26 18:27:42 +09:00
Rokt33r
b2845e2284 Merge branch 'dev'
* dev:
  version 0.2.7  - Planet, Team作成の時Error message表示  - MarkdownのCode blockの背景を薄い灰色にする  - 権限なしのPlanetには  - SignUpに規約/Privacyの外部リンク追加  - Loading画面追加  - Font 添付(Lato regular)  - UserContainerでのTeam Label変更
2015-08-26 18:23:04 +09:00
Rokt33r
4bda84d69c cleanup old files 2015-08-24 17:42:43 +09:00
Rokt33r
b510aa11f5 Merge branch 'dev'
* dev:
  fix bugs - ArticleList text overflow behaviour in Finder, PlanetContainer - No DevTools
2015-08-24 17:42:00 +09:00
Rokt33r
85f833c865 Merge branch 'dev'
* dev:
  v0.2.5 - bugfix - Alert message added(Private planet/Team member)

Conflicts:
	package.json
2015-08-24 13:46:32 +09:00
Rokt33r
b93990d10b bump version 2015-08-24 06:23:41 +09:00
Rokt33r
a0bcb8edbe Merge branch 'dev'
* dev:
  実装 - MemberがOwnerではないときにTeam設定ボターンを全部隠す
  v0.2.4 - Minor fix
  fix minor bug
2015-08-24 06:22:32 +09:00
Rokt33r
19930a2472 fix minor bug 2015-08-23 03:49:19 +09:00
Rokt33r
e75d95b1fc Merge branch 'dev'
* dev:
  実装 - PlanetArticleListへのAuto scroll追加
  実装 - tooltip (Refresh, Planet setting, Planet refresh, Edit article, Delete article, Contact)
  #14 改善適用 - アプリが立ち上がったら最初はmy planetが表示されるようにしたい - Noteがスクロールできない - Note行間がなくて読みづらい
  実装 - Hotkey
2015-08-23 03:42:40 +09:00
Rokt33r
3b7215b36a Merge branch 'dev'
* dev:
  改善 - Finder descriptionのTextoverflow対策, 最初起動の時のFinderの異常振る舞い
2015-08-22 03:46:51 +09:00
Rokt33r
8ab96cf2fb fix version 2015-08-22 03:36:04 +09:00
Rokt33r
63af2fd8b1 fix submodule setting 2015-08-22 03:33:32 +09:00
Rokt33r
fcf26f7844 Merge branch 'dev'
* dev:
  改善 - PlanetArticleList, PlanetArticleDetail
  #14 改善点4つ適用  - Team member 管理画面でのスペルミス  - Member profile imageを丸にする  - Profile popup 改善  - 文字サイズ大きく(UserContainerのみ)
2015-08-22 03:28:56 +09:00
Rokt33r
a05bba15e7 Merge branch 'dev'
* dev: (79 commits)
  version 0.2.1
  修正 - Member list, Team listのデザイン修正
  実装 - Team pageとPlanet pageにMember List表示
  実装 - PlanetHeaderにPrivate鍵表示
  Noteから外部Linkを開くときにBrowserを使う
  LogoutModal実装
  Contact Modal追加
  on Refactor... #4
  on Refactor... #3
  on Refactor... #2
  on Refactoring...
  test 0.2.0
  Fix: Personal Settingボターンを右にする。写真からまっすぐProfile pageに入れるようにする
  Add: Refresh button
  Fix: Design changed
  Fix: Disable pinch to zoom
  Fix: Preview button修正
  Fix: PlanetNavigatorのHome削除 & SnippetsとBlueprintsはToggleができるように
  Fix: minor features 設定ボタンアイコンの変更 削除Modalでcmd+enterの使用 検索バーデザイン
  Add: Log in / Sign upの時にエラーが出たらAlertを表示する Debug: Tray Icon, PopUpWindow, Menuがいつの間にか消える
  ...

Conflicts:
	src/browser/main/controllers/AppController.js
	src/browser/main/controllers/directives/SideNavController.js
	src/browser/main/controllers/states/AuthRegisterController.js
	src/browser/main/index.html
	src/browser/main/services/Modal.js
	src/browser/main/styles/app.css
	src/browser/main/styles/app.styl
	src/browser/main/styles/directives/side-nav.styl
	src/browser/main/tpls/directives/side-nav.tpl.html
	src/browser/main/tpls/states/home.tpl.html
2015-08-21 04:58:01 +09:00
Rokt33r
3b907627f7 fix links 2015-07-03 18:35:10 +09:00
Rokt33r
2284fd41b9 add agreement 2015-07-03 16:41:42 +09:00
24 changed files with 368 additions and 82 deletions

View File

@@ -16,8 +16,6 @@ const url = path.resolve(__dirname, '../browser/main/index.html')
mainWindow.loadURL('file://' + url)
mainWindow.setVisibleOnAllWorkspaces(true)
mainWindow.webContents.on('new-window', function (e) {
e.preventDefault()
})

View File

@@ -11,7 +11,7 @@ import _ from 'lodash'
import dataStore from 'boost/dataStore'
const electron = require('electron')
const { remote, clipboard } = electron
const { remote, clipboard, ipcRenderer } = electron
var hideFinder = remote.getGlobal('hideFinder')
@@ -64,6 +64,7 @@ class FinderMain extends React.Component {
let { activeArticle } = this.props
clipboard.writeText(activeArticle.content)
ipcRenderer.send('copy-finder')
notify('Saved to Clipboard!', {
body: 'Paste it wherever you want!'
})
@@ -152,6 +153,14 @@ function buildFilter (key) {
return {type: TEXT_FILTER, value: key}
}
function isContaining (target, needle) {
return target.match(new RegExp(_.escapeRegExp(needle)))
}
function startsWith (target, needle) {
return target.match(new RegExp('^' + _.escapeRegExp(needle)))
}
function remap (state) {
let { articles, folders, status } = state
@@ -168,10 +177,10 @@ function remap (state) {
let targetFolders
if (folders != null) {
let exactTargetFolders = folders.filter(folder => {
return _.find(folderExactFilters, filter => folder.name.match(new RegExp(`^${filter.value}$`)))
return _.find(folderExactFilters, filter => isContaining(folder.name, filter.value))
})
let fuzzyTargetFolders = folders.filter(folder => {
return _.find(folderFilters, filter => folder.name.match(new RegExp(`^${filter.value}`)))
return _.find(folderFilters, filter => startsWith(folder.name, filter.value))
})
targetFolders = status.targetFolders = exactTargetFolders.concat(fuzzyTargetFolders)
@@ -184,7 +193,7 @@ function remap (state) {
if (textFilters.length > 0) {
articles = textFilters.reduce((articles, textFilter) => {
return articles.filter(article => {
return article.title.match(new RegExp(textFilter.value, 'i')) || article.content.match(new RegExp(textFilter.value, 'i'))
return isContaining(article.title, textFilter.value) || isContaining(article.content, textFilter.value)
})
}, articles)
}
@@ -192,7 +201,7 @@ function remap (state) {
if (tagFilters.length > 0) {
articles = tagFilters.reduce((articles, tagFilter) => {
return articles.filter(article => {
return _.find(article.tags, tag => tag.match(new RegExp(tagFilter.value, 'i')))
return _.find(article.tags, tag => isContaining(tag, tagFilter.value))
})
}, articles)
}
@@ -201,7 +210,6 @@ function remap (state) {
let activeArticle = _.findWhere(articles, {key: status.articleKey})
if (activeArticle == null) activeArticle = articles[0]
console.log(status.search)
return {
articles,
activeArticle,

View File

@@ -1,13 +1,13 @@
import React, { PropTypes} from 'react'
import { connect } from 'react-redux'
import { CREATE_MODE, EDIT_MODE, IDLE_MODE, NEW, toggleTutorial } from 'boost/actions'
// import UserNavigator from './HomePage/UserNavigator'
import { EDIT_MODE, IDLE_MODE, toggleTutorial } from 'boost/actions'
import ArticleNavigator from './HomePage/ArticleNavigator'
import ArticleTopBar from './HomePage/ArticleTopBar'
import ArticleList from './HomePage/ArticleList'
import ArticleDetail from './HomePage/ArticleDetail'
import _ from 'lodash'
import { isModalOpen, closeModal } from 'boost/modal'
const electron = require('electron')
const BrowserWindow = electron.remote.BrowserWindow
@@ -57,7 +57,7 @@ class HomePage extends React.Component {
}
switch (status.mode) {
case CREATE_MODE:
case EDIT_MODE:
if (e.keyCode === 27) {
detail.handleCancelButtonClick()
@@ -65,6 +65,13 @@ class HomePage extends React.Component {
if ((e.keyCode === 13 && e.metaKey) || (e.keyCode === 83 && e.metaKey)) {
detail.handleSaveButtonClick()
}
if (e.keyCode === 80 && e.metaKey) {
detail.handleTogglePreviewButtonClick()
}
if (e.keyCode === 78 && e.metaKey) {
nav.handleNewPostButtonClick()
e.preventDefault()
}
break
case IDLE_MODE:
if (e.keyCode === 69) {
@@ -99,7 +106,7 @@ class HomePage extends React.Component {
list.selectNextArticle()
}
if (e.keyCode === 65 || e.keyCode === 13 && e.metaKey) {
if (e.keyCode === 65 || (e.keyCode === 13 && e.metaKey) || (e.keyCode === 78 && e.metaKey)) {
nav.handleNewPostButtonClick()
e.preventDefault()
}
@@ -107,13 +114,14 @@ class HomePage extends React.Component {
}
render () {
let { dispatch, status, articles, allArticles, activeArticle, folders, tags, filters } = this.props
let { dispatch, status, user, articles, allArticles, activeArticle, folders, tags, filters } = this.props
return (
<div className='HomePage'>
<ArticleNavigator
ref='nav'
dispatch={dispatch}
user={user}
folders={folders}
status={status}
allArticles={allArticles}
@@ -164,8 +172,16 @@ function buildFilter (key) {
return {type: TEXT_FILTER, value: key}
}
function isContaining (target, needle) {
return target.match(new RegExp(_.escapeRegExp(needle)))
}
function startsWith (target, needle) {
return target.match(new RegExp('^' + _.escapeRegExp(needle)))
}
function remap (state) {
let { folders, articles, status } = state
let { user, folders, articles, status } = state
if (articles == null) articles = []
articles.sort((a, b) => {
@@ -192,10 +208,10 @@ function remap (state) {
let targetFolders
if (folders != null) {
let exactTargetFolders = folders.filter(folder => {
return _.find(folderExactFilters, filter => folder.name.match(new RegExp(`^${filter.value}$`)))
return _.findWhere(folderExactFilters, {value: folder.name})
})
let fuzzyTargetFolders = folders.filter(folder => {
return _.find(folderFilters, filter => folder.name.match(new RegExp(`^${filter.value}`)))
return _.find(folderFilters, filter => startsWith(folder.name, filter.value))
})
targetFolders = status.targetFolders = exactTargetFolders.concat(fuzzyTargetFolders)
@@ -208,7 +224,7 @@ function remap (state) {
if (textFilters.length > 0) {
articles = textFilters.reduce((articles, textFilter) => {
return articles.filter(article => {
return article.title.match(new RegExp(textFilter.value, 'i')) || article.content.match(new RegExp(textFilter.value, 'i'))
return isContaining(article.title, textFilter.value) || isContaining(article.content, textFilter.value)
})
}, articles)
}
@@ -216,7 +232,7 @@ function remap (state) {
if (tagFilters.length > 0) {
articles = tagFilters.reduce((articles, tagFilter) => {
return articles.filter(article => {
return _.find(article.tags, tag => tag.match(new RegExp(tagFilter.value, 'i')))
return _.find(article.tags, tag => isContaining(tag, tagFilter.value))
})
}, articles)
}
@@ -227,6 +243,7 @@ function remap (state) {
if (activeArticle == null) activeArticle = articles[0]
return {
user,
folders,
status,
allArticles,
@@ -242,11 +259,9 @@ function remap (state) {
}
HomePage.propTypes = {
params: PropTypes.shape({
userId: PropTypes.string
}),
status: PropTypes.shape({
userId: PropTypes.string
status: PropTypes.shape(),
user: PropTypes.shape({
name: PropTypes.string
}),
articles: PropTypes.array,
allArticles: PropTypes.array,
@@ -257,7 +272,8 @@ HomePage.propTypes = {
folder: PropTypes.array,
tag: PropTypes.array,
text: PropTypes.array
})
}),
tags: PropTypes.array
}
export default connect(remap)(HomePage)

View File

@@ -25,6 +25,9 @@ import TagSelect from 'boost/components/TagSelect'
import ModeSelect from 'boost/components/ModeSelect'
import activityRecord from 'boost/activityRecord'
const electron = require('electron')
const clipboard = electron.clipboard
const BRAND_COLOR = '#18AF90'
const editDeleteTutorialElement = (
@@ -84,6 +87,10 @@ const modeSelectTutorialElement = (
</svg>
)
function notify (...args) {
return new window.Notification(...args)
}
function makeInstantArticle (article) {
return Object.assign({}, article)
}
@@ -154,6 +161,13 @@ export default class ArticleDetail extends React.Component {
)
}
handleClipboardButtonClick (e) {
clipboard.writeText(this.props.activeArticle.content)
notify('Saved to Clipboard!', {
body: 'Paste it wherever you want!'
})
}
handleEditButtonClick (e) {
let { dispatch } = this.props
dispatch(switchMode(EDIT_MODE))
@@ -185,8 +199,13 @@ export default class ArticleDetail extends React.Component {
: (
<span className='noTags'>Not tagged yet</span>
) : null
let folder = _.findWhere(folders, {key: activeArticle.FolderKey})
let title = activeArticle.title.trim().length === 0
? <small>(Untitled)</small>
: activeArticle.title
return (
<div className='ArticleDetail idle'>
{this.state.openDeleteConfirmMenu
@@ -214,6 +233,9 @@ export default class ArticleDetail extends React.Component {
<div className='tags'><i className='fa fa-fw fa-tags'/>{tags}</div>
</div>
<div className='right'>
<button onClick={e => this.handleClipboardButtonClick(e)} className='editBtn'>
<i className='fa fa-fw fa-clipboard'/><span className='tooltip'>Copy to clipboard</span>
</button>
<button onClick={e => this.handleEditButtonClick(e)} className='editBtn'>
<i className='fa fa-fw fa-edit'/><span className='tooltip'>Edit (e)</span>
</button>
@@ -232,7 +254,7 @@ export default class ArticleDetail extends React.Component {
<div className='detailPanel'>
<div className='header'>
<ModeIcon className='mode' mode={activeArticle.mode}/>
<div className='title'>{activeArticle.title}</div>
<div className='title'>{title}</div>
</div>
{activeArticle.mode === 'markdown'
? <MarkdownPreview content={activeArticle.content}/>
@@ -265,8 +287,12 @@ export default class ArticleDetail extends React.Component {
delete newArticle.status
newArticle.updatedAt = new Date()
newArticle.title = newArticle.title.trim()
if (newArticle.createdAt == null) {
newArticle.createdAt = new Date()
if (newArticle.title.length === 0) {
newArticle.title = `Created at ${moment(newArticle.createdAt).format('YYYY/MM/DD HH:mm')}`
}
activityRecord.emit('ARTICLE_CREATE')
} else {
activityRecord.emit('ARTICLE_UPDATE')
@@ -408,7 +434,9 @@ export default class ArticleDetail extends React.Component {
}
handleTogglePreviewButtonClick (e) {
this.setState({previewMode: !this.state.previewMode})
if (this.state.article.mode === 'markdown') {
this.setState({previewMode: !this.state.previewMode})
}
}
handleTitleKeyDown (e) {
@@ -453,18 +481,36 @@ export default class ArticleDetail extends React.Component {
<div className='right'>
{
this.state.article.mode === 'markdown'
? (<button className='preview' onClick={e => this.handleTogglePreviewButtonClick(e)}>{!this.state.previewMode ? 'Preview' : 'Edit'}</button>)
? (<button className='preview' onClick={e => this.handleTogglePreviewButtonClick(e)}>
{
!this.state.previewMode
? 'Preview'
: 'Edit'
}
</button>)
: null
}
<button onClick={e => this.handleCancelButtonClick(e)}>Cancel</button>
<button onClick={e => this.handleSaveButtonClick(e)} className='primary'>Save</button>
<button onClick={e => this.handleCancelButtonClick(e)}>
Cancel
</button>
<button onClick={e => this.handleSaveButtonClick(e)} className='primary'>
Save
</button>
</div>
</div>
<div className='detailBody'>
<div className='detailPanel'>
<div className='header'>
<div className='title'>
<input onKeyDown={e => this.handleTitleKeyDown(e)} placeholder='Title' ref='title' value={this.state.article.title} onChange={e => this.handleTitleChange(e)}/>
<input
onKeyDown={e => this.handleTitleKeyDown(e)}
placeholder={this.state.article.createdAt == null
? `Created at ${moment().format('YYYY/MM/DD HH:mm')}`
: 'Title'}
ref='title'
value={this.state.article.title}
onChange={e => this.handleTitleChange(e)}
/>
</div>
<ModeSelect
ref='mode'

View File

@@ -80,6 +80,12 @@ export default class ArticleList extends React.Component {
: (<span>Not tagged yet</span>)
let folder = _.findWhere(folders, {key: article.FolderKey})
let title = article.status !== NEW
? article.title.trim().length === 0
? <small>(Untitled)</small>
: article.title
: '(New article)'
return (
<div key={'article-' + article.key}>
<div onClick={e => this.handleArticleClick(article)(e)} className={'articleItem' + (activeArticle.key === article.key ? ' active' : '')}>
@@ -91,7 +97,7 @@ export default class ArticleList extends React.Component {
<span className='updatedAt'>{article.status != null ? article.status : moment(article.updatedAt).fromNow()}</span>
</div>
<div className='middle'>
<ModeIcon className='mode' mode={article.mode}/> <div className='title'>{article.status !== NEW ? article.title : '(New article)'}</div>
<ModeIcon className='mode' mode={article.mode}/> <div className='title'>{title}</div>
</div>
<div className='bottom'>
<div className='tags'><i className='fa fa-fw fa-tags'/>{tagElements}</div>

View File

@@ -1,16 +1,12 @@
import React, { PropTypes } from 'react'
import { findWhere } from 'lodash'
import { setSearchFilter, switchFolder, switchMode, switchArticle, updateArticle, EDIT_MODE } from 'boost/actions'
import { setSearchFilter, switchFolder, switchMode, switchArticle, updateArticle, clearNewArticle, EDIT_MODE } from 'boost/actions'
import { openModal } from 'boost/modal'
import FolderMark from 'boost/components/FolderMark'
import Preferences from 'boost/components/modal/Preferences'
import CreateNewFolder from 'boost/components/modal/CreateNewFolder'
import keygen from 'boost/keygen'
const electron = require('electron')
const remote = electron.remote
let userName = remote.getGlobal('process').env.USER
const BRAND_COLOR = '#18AF90'
const preferenceTutorialElement = (
@@ -85,6 +81,7 @@ export default class ArticleNavigator extends React.Component {
status: 'NEW'
}
dispatch(clearNewArticle())
dispatch(updateArticle(newArticle))
dispatch(switchArticle(newArticle.key, true))
dispatch(switchMode(EDIT_MODE))
@@ -108,7 +105,7 @@ export default class ArticleNavigator extends React.Component {
}
render () {
let { status, folders, allArticles } = this.props
let { status, user, folders, allArticles } = this.props
let { targetFolders } = status
if (targetFolders == null) targetFolders = []
@@ -126,7 +123,7 @@ export default class ArticleNavigator extends React.Component {
return (
<div className='ArticleNavigator'>
<div className='userInfo'>
<div className='userProfileName'>{userName}</div>
<div className='userProfileName'>{user.name}</div>
<div className='userName'>localStorage</div>
<button onClick={e => this.handlePreferencesButtonClick(e)} className='settingBtn'>
<i className='fa fa-fw fa-chevron-down'/>

View File

@@ -35,18 +35,33 @@ export default class ArticleTopBar extends React.Component {
super(props)
this.state = {
isTooltipHidden: true
isTooltipHidden: true,
isLinksDropdownOpen: false
}
}
componentDidMount () {
this.searchInput = ReactDOM.findDOMNode(this.refs.searchInput)
this.linksButton = ReactDOM.findDOMNode(this.refs.links)
this.showLinksDropdown = e => {
e.preventDefault()
e.stopPropagation()
if (!this.state.isLinksDropdownOpen) {
this.setState({isLinksDropdownOpen: true})
}
}
this.linksButton.addEventListener('click', this.showLinksDropdown)
this.hideLinksDropdown = e => {
if (this.state.isLinksDropdownOpen) {
this.setState({isLinksDropdownOpen: false})
}
}
document.addEventListener('click', this.hideLinksDropdown)
}
componentWillUnmount () {
this.searchInput.removeEventListener('keydown', this.showTooltip)
this.searchInput.removeEventListener('focus', this.showTooltip)
this.searchInput.removeEventListener('blur', this.showTooltip)
document.removeEventListener('click', this.hideLinksDropdown)
this.linksButton.removeEventListener('click', this.showLinksDropdown())
}
handleTooltipRequest (e) {
@@ -118,8 +133,11 @@ export default class ArticleTopBar extends React.Component {
: null
}
<div className={'tooltip' + (this.state.isTooltipHidden ? ' hide' : '')}>
- Search by tag : #{'{string}'}<br/>
- Search by folder : /{'{folder_name}'}
<ul>
<li>- Search by tag : #{'{string}'}</li>
<li>- Search by folder : /{'{folder_name}'}</li>
<li><small>exact match : //{'{folder_name}'}</small></li>
</ul>
</div>
</div>
@@ -129,10 +147,23 @@ export default class ArticleTopBar extends React.Component {
<div className='right'>
<button onClick={e => this.handleTutorialButtonClick(e)}>?<span className='tooltip'>How to use</span>
</button>
<ExternalLink className='logo' href='http://b00st.io'>
<a ref='links' className='linksBtn' href>
<img src='../../resources/favicon-230x230.png' width='44' height='44'/>
<span className='tooltip'>Boost official page</span>
</ExternalLink>
</a>
{
this.state.isLinksDropdownOpen
? (
<div className='links-dropdown'>
<ExternalLink className='links-item' href='https://b00st.io'>
<i className='fa fa-fw fa-home'/>Boost official page
</ExternalLink>
<ExternalLink className='links-item' href='https://github.com/BoostIO/boost-app-discussions/issues'>
<i className='fa fa-fw fa-bullhorn'/> Discuss
</ExternalLink>
</div>
)
: null
}
</div>
{status.isTutorialOpen ? (

View File

@@ -29,6 +29,13 @@ ipc.on('notify', function (e, payload) {
})
})
ipc.on('copy-finder', function () {
activityRecord.emit('FINDER_COPY')
})
ipc.on('open-finder', function () {
activityRecord.emit('FINDER_OPEN')
})
let routes = (
<Route path='/' component={MainPage}>
<IndexRoute name='home' component={HomePage}/>

View File

@@ -14,6 +14,8 @@ body
width 100%
height 100%
overflow hidden
button, input
font-family "Lato"
.Finder
absolute top bottom left right

View File

@@ -323,7 +323,8 @@ iptFocusBorderColor = #369DCD
right 15px
font-size 24px
line-height 60px
white-space nowrap
overflow-x auto
overflow-y hidden
small
color #AAA

View File

@@ -48,6 +48,8 @@ articleItemColor = #777
left 19px
right 0
overflow ellipsis
small
color #AAA
.bottom
padding 5px 0
overflow-x auto

View File

@@ -14,7 +14,7 @@ articleCount = #999
.userProfileName
color brandColor
font-size 28px
padding 6px 0 0 10px
padding 6px 37px 0 10px
white-space nowrap
text-overflow ellipsis
overflow hidden

View File

@@ -62,6 +62,13 @@ infoBtnActiveBgColor = #3A3A3A
opacity 1
&.hide
opacity 0
ul
li:last-child
line-height 10px
margin-bottom 3px
small
font-size 10px
margin-left 15px
input
absolute top left
width 350px
@@ -140,17 +147,33 @@ infoBtnActiveBgColor = #3A3A3A
.tooltip
opacity 1
&>.logo
&>.linksBtn
display block
position absolute
top 8px
right 15px
opacity 0.7
.tooltip
tooltip()
margin-top 44px
margin-left -120px
&:hover
opacity 1
.tooltip
opacity 1
&>.links-dropdown
position fixed
z-index 50
right 10px
top 40px
background-color transparentify(invBackgroundColor, 80%)
padding 5px 0
.links-item
padding 0 10px
height 33px
width 100%
display block
line-height 33px
text-decoration none
color white
&:hover
background-color transparentify(lighten(invBackgroundColor, 30%), 80%)

View File

@@ -3,6 +3,7 @@ const app = electron.app
const Tray = electron.Tray
const Menu = electron.Menu
const MenuItem = electron.MenuItem
const ipcMain = electron.ipcMain
process.stdin.setEncoding('utf8')
@@ -36,7 +37,7 @@ app.on('ready', function () {
}
}))
trayMenu.append(new MenuItem({
label: 'Open Finder',
label: 'Open Finder window',
click: function () {
finderWindow.show()
}
@@ -63,6 +64,10 @@ app.on('ready', function () {
break
}
})
ipcMain.on('copy-finder', function () {
emit('copy-finder')
})
})
global.hideFinder = function () {

View File

@@ -1,4 +1,6 @@
// Action types
export const USER_UPDATE = 'USER_UPDATE'
export const CLEAR_NEW_ARTICLE = 'CLEAR_NEW_ARTICLE'
export const ARTICLE_UPDATE = 'ARTICLE_UPDATE'
export const ARTICLE_DESTROY = 'ARTICLE_DESTROY'
@@ -24,6 +26,13 @@ export const EDIT_MODE = 'EDIT_MODE'
// Article status
export const NEW = 'NEW'
export function updateUser (input) {
return {
type: USER_UPDATE,
data: input
}
}
// DB
export function clearNewArticle () {
return {

View File

@@ -1,4 +1,5 @@
import React, { PropTypes } from 'react'
import ReactDOM from 'react-dom'
import linkState from 'boost/linkState'
import { createFolder } from 'boost/actions'
import store from 'boost/store'
@@ -15,6 +16,10 @@ export default class CreateNewFolder extends React.Component {
}
}
componentDidMount () {
ReactDOM.findDOMNode(this.refs.folderName).focus()
}
handleCloseButton (e) {
this.props.close()
}
@@ -84,7 +89,7 @@ export default class CreateNewFolder extends React.Component {
<div className='title'>Create new folder</div>
<input onKeyDown={e => this.handleKeyDown(e)} className='ipt' type='text' valueLink={this.linkState('name')} placeholder='Enter folder name'/>
<input ref='folderName' onKeyDown={e => this.handleKeyDown(e)} className='ipt' type='text' valueLink={this.linkState('name')} placeholder='Enter folder name'/>
<div className='colorSelect'>
{colorElements}
</div>

View File

@@ -1,8 +1,13 @@
import React, { PropTypes } from 'react'
import ReactDOM from 'react-dom'
import store from 'boost/store'
import { unlockStatus, clearNewArticle } from 'boost/actions'
export default class EditedAlert extends React.Component {
componentDidMount () {
ReactDOM.findDOMNode(this.refs.no).focus()
}
handleNoButtonClick (e) {
this.props.close()
}
@@ -22,8 +27,8 @@ export default class EditedAlert extends React.Component {
<div className='message'>Do you really want to leave without finishing?</div>
<div className='control'>
<button onClick={e => this.handleNoButtonClick(e)}><i className='fa fa-fw fa-close'/> No</button>
<button onClick={e => this.handleYesButtonClick(e)} className='primary'><i className='fa fa-fw fa-check'/> Yes</button>
<button ref='no' onClick={e => this.handleNoButtonClick(e)}><i className='fa fa-fw fa-close'/> No</button>
<button ref='yes' onClick={e => this.handleYesButtonClick(e)} className='primary'><i className='fa fa-fw fa-check'/> Yes</button>
</div>
</div>
)

View File

@@ -1,5 +1,6 @@
import React from 'react'
import React, { PropTypes } from 'react'
import linkState from 'boost/linkState'
import { updateUser } from 'boost/actions'
const electron = require('electron')
const ipc = electron.ipcRenderer
@@ -9,24 +10,32 @@ export default class AppSettingTab extends React.Component {
constructor (props) {
super(props)
let keymap = remote.getGlobal('keymap')
let userName = props.user != null ? props.user.name : null
this.state = {
toggleFinder: keymap.toggleFinder,
alert: null
user: {
name: userName,
alert: null
},
userAlert: null,
keymap: {
toggleFinder: keymap.toggleFinder
},
keymapAlert: null
}
}
componentDidMount () {
this.handleSettingDone = () => {
this.setState({alert: {
this.setState({keymapAlert: {
type: 'success',
message: 'Successfully done!'
}})
}
this.handleSettingError = err => {
this.setState({alert: {
this.setState({keymapAlert: {
type: 'error',
message: err.message
message: err.message != null ? err.message : 'Error occurs!'
}})
}
ipc.addListener('APP_SETTING_DONE', this.handleSettingDone)
@@ -40,7 +49,7 @@ export default class AppSettingTab extends React.Component {
submitHotKey () {
ipc.send('hotkeyUpdated', {
toggleFinder: this.state.toggleFinder
toggleFinder: this.state.keymap.toggleFinder
})
}
@@ -54,25 +63,56 @@ export default class AppSettingTab extends React.Component {
}
}
handleNameSaveButtonClick (e) {
let { dispatch } = this.props
dispatch(updateUser({name: this.state.user.name}))
this.setState({
userAlert: {
type: 'success',
message: 'Successfully done!'
}
})
}
render () {
let alert = this.state.alert
let alertElement = alert != null ? (
<p className={`alert ${alert.type}`}>
{alert.message}
let keymapAlert = this.state.keymapAlert
let keymapAlertElement = keymapAlert != null
? (
<p className={`alert ${keymapAlert.type}`}>
{keymapAlert.message}
</p>
) : null
let userAlert = this.state.userAlert
let userAlertElement = userAlert != null
? (
<p className={`alert ${userAlert.type}`}>
{userAlert.message}
</p>
) : null
return (
<div className='AppSettingTab content'>
<div className='section'>
<div className='sectionTitle'>User's info</div>
<div className='sectionInput'>
<label>User name</label>
<input valueLink={this.linkState('user.name')} type='text'/>
</div>
<div className='sectionConfirm'>
<button onClick={e => this.handleNameSaveButtonClick(e)}>Save</button>
{userAlertElement}
</div>
</div>
<div className='section'>
<div className='sectionTitle'>Hotkey</div>
<div className='sectionInput'>
<label>Toggle Finder(popup)</label>
<input onKeyDown={e => this.handleKeyDown(e)} valueLink={this.linkState('toggleFinder')} type='text'/>
<input onKeyDown={e => this.handleKeyDown(e)} valueLink={this.linkState('keymap.toggleFinder')} type='text'/>
</div>
<div className='sectionConfirm'>
<button onClick={e => this.handleSaveButtonClick(e)}>Save</button>
{alertElement}
{keymapAlertElement}
</div>
<div className='description'>
<ul>
@@ -101,3 +141,6 @@ export default class AppSettingTab extends React.Component {
}
AppSettingTab.prototype.linkState = linkState
AppSettingTab.propTypes = {
dispatch: PropTypes.func
}

View File

@@ -62,7 +62,7 @@ class Preferences extends React.Component {
}
renderContent () {
let { folders, dispatch } = this.props
let { user, folders, dispatch } = this.props
switch (this.state.currentTab) {
case HELP:
@@ -80,12 +80,20 @@ class Preferences extends React.Component {
)
case APP:
default:
return (<AppSettingTab/>)
return (
<AppSettingTab
user={user}
dispatch={dispatch}
/>
)
}
}
}
Preferences.propTypes = {
user: PropTypes.shape({
name: PropTypes.string
}),
folders: PropTypes.array,
dispatch: PropTypes.func
}
@@ -93,9 +101,10 @@ Preferences.propTypes = {
Preferences.prototype.linkState = linkState
function remap (state) {
let { folders, status } = state
let { user, folders, status } = state
return {
user,
folders,
status
}

View File

@@ -1,4 +1,6 @@
import keygen from 'boost/keygen'
import _ from 'lodash'
const electron = require('electron')
const remote = electron.remote
const jetpack = require('fs-jetpack')
@@ -10,15 +12,66 @@ function getLocalPath () {
return path.join(remote.app.getPath('userData'), 'local.json')
}
function forgeInitialRepositories () {
return [{
key: keygen(),
name: 'local',
type: 'userData',
user: {
name: remote.getGlobal('process').env.USER
}
}]
}
function getRepositories () {
let raw = localStorage.getItem('repositories')
try {
let parsed = JSON.parse(raw)
if (!_.isArray(parsed)) {
throw new Error('repositories data is currupte. re-init data.')
}
return parsed
} catch (e) {
console.log(e)
let newRepos = forgeInitialRepositories()
saveRepositories(newRepos)
return newRepos
}
}
function saveRepositories (repos) {
localStorage.setItem('repositories', JSON.stringify(repos))
}
export function getUser (repoName) {
if (repoName == null) {
return getRepositories()[0]
}
return null
}
export function saveUser (repoName, user) {
let repos = getRepositories()
if (repoName == null) {
Object.assign(repos[0].user, user)
}
saveRepositories(repos)
}
export function init () {
console.log('initialize data store')
// set repositories info
getRepositories()
// set local.json
let data = jetpack.read(getLocalPath(), 'json')
if (data == null) {
// for 0.4.1 -> 0.4.2
if (localStorage.getItem('local') != null) {
data = JSON.parse(localStorage.getItem('local'))
jetpack.write(getLocalPath(), data)
localStorage.removeItem('local')
console.log('update 0.4.1 => 0.4.2')
return
}
@@ -70,6 +123,8 @@ export default (function () {
init()
}
return {
getUser,
saveUser,
init,
getData,
setArticles,

View File

@@ -2,6 +2,6 @@ var crypto = require('crypto')
module.exports = function () {
var shasum = crypto.createHash('sha1')
shasum.update(((new Date()).getTime()).toString())
shasum.update(((new Date()).getTime() + Math.round(Math.random()*1000)).toString())
return shasum.digest('hex')
}

View File

@@ -12,6 +12,9 @@ import {
UNLOCK_STATUS,
TOGGLE_TUTORIAL,
// user
USER_UPDATE,
// Article action type
ARTICLE_UPDATE,
ARTICLE_DESTROY,
@@ -42,10 +45,22 @@ const initialStatus = {
let data = dataStore.getData()
let initialArticles = data.articles
let initialFolders = data.folders
let initialUser = dataStore.getUser().user
let isStatusLocked = false
let isCreatingNew = false
function user (state = initialUser, action) {
switch (action.type) {
case USER_UPDATE:
let updated = Object.assign(state, action.data)
dataStore.saveUser(null, updated)
return updated
default:
return state
}
}
function folders (state = initialFolders, action) {
state = state.slice()
switch (action.type) {
@@ -250,6 +265,7 @@ function status (state = initialStatus, action) {
}
export default combineReducers({
user,
folders,
articles,
status

12
main.js
View File

@@ -66,8 +66,7 @@ app.on('ready', function () {
if (finderProcess) finderProcess.kill()
appQuit = true
})
autoUpdater.setFeedURL('https://orbital.b00st.io/rokt33r/boost-dev/latest?version=' + version)
autoUpdater.setFeedURL('https://orbital.b00st.io/rokt33r/boost-app/latest?version=' + version)
var template = require('./atom-lib/menu-template')
var menu = Menu.buildFromTemplate(template)
@@ -129,9 +128,10 @@ app.on('ready', function () {
console.log('FINDER(stdout): ' + payload.data)
break
case 'show-main-window':
if (mainWindow != null) {
mainWindow.show()
}
mainWindow.show()
break
case 'copy-finder':
mainWindow.webContents.send('copy-finder')
break
case 'request-data':
mainWindow.webContents.send('request-data')
@@ -174,6 +174,7 @@ app.on('ready', function () {
try {
globalShortcut.register(toggleFinderKey, function () {
emitToFinder('open-finder')
mainWindow.webContents.send('open-finder', {})
})
} catch (err) {
console.log(err.name)
@@ -190,6 +191,7 @@ app.on('ready', function () {
try {
globalShortcut.register(toggleFinderKey, function () {
emitToFinder('open-finder')
mainWindow.webContents.send('open-finder', {})
})
mainWindow.webContents.send('APP_SETTING_DONE', {})
} catch (err) {

View File

@@ -1,6 +1,6 @@
{
"name": "boost",
"version": "0.4.2-rc.0",
"version": "0.4.4",
"description": "Boost App",
"main": "index.js",
"scripts": {