├── .babelrc ├── .editorconfig ├── .eslintrc ├── .gitattributes ├── .gitignore ├── .travis.yml ├── LICENSE ├── README.md ├── app ├── actions │ ├── favorites.js │ ├── lists.js │ ├── retweet.js │ ├── search.js │ ├── siteStream.js │ ├── timeline.js │ ├── update.js │ ├── user.js │ ├── userStream.js │ └── users.js ├── components │ ├── Atoms │ │ ├── Button │ │ │ ├── Button.js │ │ │ ├── Button.test.js │ │ │ └── button.css │ │ ├── CreatedAt │ │ │ ├── CreatedAt.js │ │ │ └── createdAt.css │ │ ├── FavoriteTrigger │ │ │ ├── FavoriteTrigger.js │ │ │ └── favoriteTrigger.css │ │ ├── Loading │ │ │ ├── Loading.js │ │ │ ├── Loading.test.js │ │ │ ├── loading.css │ │ │ └── loading.svg │ │ ├── Menu │ │ │ ├── Menu.js │ │ │ ├── back_off.svg │ │ │ ├── back_on.svg │ │ │ ├── forward_off.svg │ │ │ ├── forward_on.svg │ │ │ └── menu.css │ │ ├── Name │ │ │ ├── Name.js │ │ │ ├── Name.test.js │ │ │ └── name.css │ │ ├── NavigationItem │ │ │ ├── NavigationItem.js │ │ │ ├── home.svg │ │ │ ├── lists.svg │ │ │ ├── mentions.svg │ │ │ ├── navigationItem.css │ │ │ └── search.svg │ │ ├── RemainingCharacters │ │ │ ├── RemainingCharacters.js │ │ │ └── remainingCharacters.css │ │ ├── RetweetActions │ │ │ ├── RetweetActions.js │ │ │ └── retweetActions.css │ │ ├── RetweetTrigger │ │ │ ├── RetweetTrigger.js │ │ │ └── retweetTrigger.css │ │ ├── ScreenName │ │ │ ├── ScreenName.js │ │ │ ├── ScreenName.test.js │ │ │ └── screenName.css │ │ ├── Text │ │ │ ├── Text.js │ │ │ └── text.css │ │ ├── Textarea │ │ │ ├── Textarea.js │ │ │ ├── Textarea.test.js │ │ │ └── textarea.css │ │ ├── UserCount │ │ │ ├── UserCount.js │ │ │ └── userCount.css │ │ └── UserImage │ │ │ ├── UserImage.js │ │ │ └── userImage.css │ ├── Modules │ │ ├── App │ │ │ ├── App.js │ │ │ └── app.css │ │ ├── ListsTimeline │ │ │ ├── ListsTimeline.js │ │ │ └── listsTimeline.css │ │ ├── SearchTimeline │ │ │ ├── SearchTimeline.js │ │ │ └── searchTimeline.css │ │ ├── Timeline │ │ │ ├── Timeline.js │ │ │ └── timeline.css │ │ ├── TweetWrapper │ │ │ ├── TweetWrapper.js │ │ │ └── tweetWrapper.css │ │ └── UserModal │ │ │ └── UserModal.js │ ├── Molecules │ │ ├── Lists │ │ │ ├── Lists.js │ │ │ └── lists.css │ │ ├── Meta │ │ │ ├── Meta.js │ │ │ └── meta.css │ │ ├── Navigation │ │ │ ├── Navigation.js │ │ │ ├── github.svg │ │ │ └── navigation.css │ │ ├── PostForm │ │ │ ├── PostForm.js │ │ │ ├── PostForm.test.js │ │ │ └── postForm.css │ │ ├── RetweetModal │ │ │ ├── RetweetModal.js │ │ │ └── retweetModal.css │ │ ├── Triggers │ │ │ ├── Triggers.js │ │ │ └── triggers.css │ │ ├── UserCounts │ │ │ ├── UserCounts.js │ │ │ └── userCounts.css │ │ └── UserInfo │ │ │ ├── UserInfo.js │ │ │ └── userInfo.css │ └── Organisms │ │ ├── Tweet │ │ ├── Tweet.js │ │ └── tweet.css │ │ └── User │ │ ├── User.js │ │ └── user.css ├── containers │ ├── Atoms │ │ ├── FavoriteTrigger.js │ │ └── RetweetTrigger.js │ ├── Modules │ │ ├── App.js │ │ ├── HomeTimeline.js │ │ ├── ListsTimeline.js │ │ ├── MentionsTimeline.js │ │ ├── SearchTimeline.js │ │ ├── UserModal.js │ │ └── UserTimeline.js │ ├── Molecules │ │ ├── Lists.js │ │ ├── PostForm.js │ │ └── RetweetModal.js │ └── Organisms │ │ └── Tweet.js ├── entry.js ├── keymap.js ├── main.js ├── menu.js ├── reducers │ ├── homeTimeline.js │ ├── lists.js │ ├── mentionsTimeline.js │ ├── retweet.js │ ├── searchTimeline.js │ ├── update.js │ ├── update.test.js │ ├── user.js │ ├── user.test.js │ └── userTimeline.js ├── routes.js ├── sagas │ ├── favorites │ │ └── favorites.js │ ├── index.js │ ├── lists │ │ ├── list.js │ │ └── statuses.js │ ├── search │ │ └── tweets.js │ ├── statuses │ │ ├── homeTimeline.js │ │ ├── mentionsTimeline.js │ │ ├── retweet.js │ │ ├── update.js │ │ └── userTimeline.js │ ├── streams │ │ ├── siteStream.js │ │ └── userStream.js │ └── users │ │ └── show.js ├── styles │ └── variable.css └── utils │ ├── authentication.js │ ├── favorite.js │ ├── retweet.js │ ├── twitterClient.js │ └── update.js ├── assets └── images │ ├── worc.icns │ └── worc.ico ├── build ├── icon.icns └── icon.ico ├── dist └── index.html ├── docs ├── css │ └── style.css ├── images │ ├── bg_top_01.jpg │ ├── home.svg │ ├── lists.svg │ ├── logo_worc_01.png │ ├── logo_worc_02.png │ ├── mac.svg │ ├── mentions.svg │ ├── ogp.png │ ├── search.svg │ ├── ss_modal_01.png │ ├── ss_timeline_01.png │ ├── txt_catch_01.png │ ├── txt_catch_02.png │ ├── windows.svg │ └── worc.ico ├── index.html ├── ja │ └── index.html ├── latest.yml ├── releases │ └── latest.json └── scss │ ├── _reset.scss │ └── style.scss ├── package.json └── webpack.config.js /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets" : ["es2015", "react", "stage-2"], 3 | } 4 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # EditorConfig helps developers define and maintain consistent 2 | # coding styles between different editors and IDEs 3 | # editorconfig.org 4 | 5 | root = true 6 | 7 | 8 | [*] 9 | # Change these settings to your own preference 10 | indent_style = space 11 | indent_size = 2 12 | 13 | # We recommend you to keep these unchanged 14 | end_of_line = lf 15 | charset = utf-8 16 | trim_trailing_whitespace = true 17 | insert_final_newline = true 18 | 19 | [*.md] 20 | trim_trailing_whitespace = false 21 | -------------------------------------------------------------------------------- /.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "extends" : "airbnb", 3 | "rules" : { 4 | "comma-dangle" : 0, 5 | "no-constant-condition" : 0, 6 | "no-underscore-dangle" : 0, 7 | "no-param-reassign" : 0, 8 | "no-script-url" : 0, 9 | "no-new" : 0, 10 | "max-len" : [1, 200, 2], 11 | "import/no-extraneous-dependencies" : 0, 12 | "react/prop-types" : 0, 13 | "react/jsx-filename-extension" : 0, 14 | "react/no-danger" : 0, 15 | "react/prefer-stateless-function" : 0 16 | }, 17 | "globals": { 18 | "twttr": false, 19 | "document": false 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | docs/mac/worc-1.5.0.dmg filter=lfs diff=lfs merge=lfs -text 2 | docs/mac/worc-1.6.0.dmg filter=lfs diff=lfs merge=lfs -text 3 | docs/win/worc-Setup-1.6.0.exe filter=lfs diff=lfs merge=lfs -text 4 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | dist/* 4 | !index.html 5 | assets/* 6 | !images 7 | docs/mac/worc.app 8 | docs/win-ia32-unpacked 9 | worc-darwin-x64 10 | npm-debug.log 11 | **/__snapshots__ 12 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - 6.3.0 4 | install: 5 | - npm i 6 | script: 7 | - npm run build 8 | - npm test -- -u 9 | cache: 10 | directories: 11 | - node_modules 12 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2017 Kazuki Shibata 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Worc 2 | [](https://travis-ci.org/shibe97/worc) 3 | 4 |  5 | 6 | # Motivation 7 | Twitter is one of the great information gathering tool. 8 | You guys wanna use twitter during your working time. 9 | 10 | Worc is made for you. 11 | A quiet twitter client made by Electron. 12 | 13 | # Downloads 14 | You can download from following link. 15 | 16 | [https://shibe97.github.io/worc/](https://shibe97.github.io/worc/) 17 | 18 | **-NOTICE-** 19 | This application is not signed. 20 | You need to open it from right click. 21 | 22 | # Screenshots 23 |  24 |  25 | 26 | 27 | # How To Develop 28 | ## Setup 29 | ``` 30 | $ npm install 31 | ``` 32 | 33 | ## Build 34 | ``` 35 | $ npm run build 36 | ``` 37 | 38 | ## Watch and auto build 39 | ``` 40 | $ npm run watch 41 | ``` 42 | 43 | ## Test 44 | ``` 45 | $ npm test 46 | ``` 47 | 48 | # License 49 | MIT 50 | -------------------------------------------------------------------------------- /app/actions/favorites.js: -------------------------------------------------------------------------------- 1 | import { createAction } from 'redux-actions'; 2 | 3 | export const REQUEST_POST_FAVORITES_CREATE = 'REQUEST_POST_FAVORITES_CREATE'; 4 | export const SUCCESS_POST_FAVORITES_CREATE = 'SUCCESS_POST_FAVORITES_CREATE'; 5 | export const FAILURE_POST_FAVORITES_CREATE = 'FAILURE_POST_FAVORITES_CREATE'; 6 | export const requestPostFavoritesCreate = createAction(REQUEST_POST_FAVORITES_CREATE); 7 | export const successPostFavoritesCreate = createAction(SUCCESS_POST_FAVORITES_CREATE); 8 | export const failurePostFavoritesCreate = createAction(FAILURE_POST_FAVORITES_CREATE); 9 | 10 | export const REQUEST_POST_FAVORITES_DESTROY = 'REQUEST_POST_FAVORITES_DESTROY'; 11 | export const SUCCESS_POST_FAVORITES_DESTROY = 'SUCCESS_POST_FAVORITES_DESTROY'; 12 | export const FAILURE_POST_FAVORITES_DESTROY = 'FAILURE_POST_FAVORITES_DESTROY'; 13 | export const requestPostFavoritesDestroy = createAction(REQUEST_POST_FAVORITES_DESTROY); 14 | export const successPostFavoritesDestroy = createAction(SUCCESS_POST_FAVORITES_DESTROY); 15 | export const failurePostFavoritesDestroy = createAction(FAILURE_POST_FAVORITES_DESTROY); 16 | 17 | export const INPUT_FAVORITES_CREATE = 'INPUT_FAVORITES_CREATE'; 18 | export const inputFavoritesCreate = createAction(INPUT_FAVORITES_CREATE); 19 | -------------------------------------------------------------------------------- /app/actions/lists.js: -------------------------------------------------------------------------------- 1 | import { createAction } from 'redux-actions'; 2 | 3 | export const REQUEST_GET_LIST = 'REQUEST_GET_LIST'; 4 | export const SUCCESS_GET_LIST = 'SUCCESS_GET_LIST'; 5 | export const FAILURE_GET_LIST = 'FAILURE_GET_LIST'; 6 | export const requestGetList = createAction(REQUEST_GET_LIST); 7 | export const successGetList = createAction(SUCCESS_GET_LIST); 8 | export const failureGetList = createAction(FAILURE_GET_LIST); 9 | 10 | export const REQUEST_GET_LISTS_STATUSES = 'REQUEST_GET_LISTS_STATUSES'; 11 | export const SUCCESS_GET_LISTS_STATUSES = 'SUCCESS_GET_LISTS_STATUSES'; 12 | export const FAILURE_GET_LISTS_STATUSES = 'FAILURE_GET_LISTS_STATUSES'; 13 | export const requestGetListsStatuses = createAction(REQUEST_GET_LISTS_STATUSES); 14 | export const successGetListsStatuses = createAction(SUCCESS_GET_LISTS_STATUSES); 15 | export const failureGetListsStatuses = createAction(FAILURE_GET_LISTS_STATUSES); 16 | -------------------------------------------------------------------------------- /app/actions/retweet.js: -------------------------------------------------------------------------------- 1 | import { createAction } from 'redux-actions'; 2 | 3 | export const REQUEST_POST_RETWEET = 'REQUEST_POST_RETWEET'; 4 | export const SUCCESS_POST_RETWEET = 'SUCCESS_POST_RETWEET'; 5 | export const FAILURE_POST_RETWEET = 'FAILURE_POST_RETWEET'; 6 | export const requestPostRetweet = createAction(REQUEST_POST_RETWEET); 7 | export const successPostRetweet = createAction(SUCCESS_POST_RETWEET); 8 | export const failurePostRetweet = createAction(FAILURE_POST_RETWEET); 9 | 10 | export const CLOSE_RETWEET_MODAL = 'CLOSE_RETWEET_MODAL'; 11 | export const closeRetweetModal = createAction(CLOSE_RETWEET_MODAL); 12 | 13 | export const OPEN_RETWEET_MODAL = 'OPEN_RETWEET_MODAL'; 14 | export const openRetweetModal = createAction(OPEN_RETWEET_MODAL); 15 | -------------------------------------------------------------------------------- /app/actions/search.js: -------------------------------------------------------------------------------- 1 | import { createAction } from 'redux-actions'; 2 | 3 | export const REQUEST_GET_SEARCH_TWEETS = 'REQUEST_GET_SEARCH_TWEETS'; 4 | export const SUCCESS_GET_SEARCH_TWEETS = 'SUCCESS_GET_SEARCH_TWEETS'; 5 | export const FAILURE_GET_SEARCH_TWEETS = 'FAILURE_GET_SEARCH_TWEETS'; 6 | export const requestGetSearchTweets = createAction(REQUEST_GET_SEARCH_TWEETS); 7 | export const successGetSearchTweets = createAction(SUCCESS_GET_SEARCH_TWEETS); 8 | export const failureGetSearchTweets = createAction(FAILURE_GET_SEARCH_TWEETS); 9 | 10 | export const INPUT_QUERY = 'INPUT_QUERY'; 11 | export const inputQuery = createAction(INPUT_QUERY); 12 | -------------------------------------------------------------------------------- /app/actions/siteStream.js: -------------------------------------------------------------------------------- 1 | import { createAction } from 'redux-actions'; 2 | 3 | export const REQUEST_STREAM_SITE_FOLLOW = 'REQUEST_STREAM_SITE_FOLLOW'; 4 | export const SUCCESS_STREAM_SITE_FOLLOW = 'SUCCESS_STREAM_SITE_FOLLOW'; 5 | export const FAILURE_STREAM_SITE_FOLLOW = 'FAILURE_STREAM_SITE_FOLLOW'; 6 | 7 | export const requestStreamSiteFollow = (dispatch, listId) => ({ 8 | type: REQUEST_STREAM_SITE_FOLLOW, 9 | dispatch, 10 | listId 11 | }); 12 | export const successStreamSiteFollow = createAction(SUCCESS_STREAM_SITE_FOLLOW); 13 | export const failureStreamSiteFollow = createAction(FAILURE_STREAM_SITE_FOLLOW); 14 | 15 | export const REQUEST_STREAM_SITE_TRACK = 'REQUEST_STREAM_SITE_TRACK'; 16 | export const SUCCESS_STREAM_SITE_TRACK = 'SUCCESS_STREAM_SITE_TRACK'; 17 | export const FAILURE_STREAM_SITE_TRACK = 'FAILURE_STREAM_SITE_TRACK'; 18 | 19 | export const requestStreamSiteTrack = (dispatch, keyword) => ({ 20 | type: REQUEST_STREAM_SITE_TRACK, 21 | dispatch, 22 | keyword 23 | }); 24 | export const successStreamSiteTrack = createAction(SUCCESS_STREAM_SITE_TRACK); 25 | export const failureStreamSiteTrack = createAction(FAILURE_STREAM_SITE_TRACK); 26 | -------------------------------------------------------------------------------- /app/actions/timeline.js: -------------------------------------------------------------------------------- 1 | import { createAction } from 'redux-actions'; 2 | 3 | export const REQUEST_GET_HOME_TIMELINE = 'REQUEST_GET_HOME_TIMELINE'; 4 | export const SUCCESS_GET_HOME_TIMELINE = 'SUCCESS_GET_HOME_TIMELINE'; 5 | export const FAILURE_GET_HOME_TIMELINE = 'FAILURE_GET_HOME_TIMELINE'; 6 | export const requestGetHomeTimeline = createAction(REQUEST_GET_HOME_TIMELINE); 7 | export const successGetHomeTimeline = createAction(SUCCESS_GET_HOME_TIMELINE); 8 | export const failureGetHomeTimeline = createAction(FAILURE_GET_HOME_TIMELINE); 9 | 10 | export const REQUEST_GET_USER_TIMELINE = 'REQUEST_GET_USER_TIMELINE'; 11 | export const SUCCESS_GET_USER_TIMELINE = 'SUCCESS_GET_USER_TIMELINE'; 12 | export const FAILURE_GET_USER_TIMELINE = 'FAILURE_GET_USER_TIMELINE'; 13 | export const requestGetUserTimeline = createAction(REQUEST_GET_USER_TIMELINE); 14 | export const successGetUserTimeline = createAction(SUCCESS_GET_USER_TIMELINE); 15 | export const failureGetUserTimeline = createAction(FAILURE_GET_USER_TIMELINE); 16 | 17 | export const REQUEST_GET_MENTIONS_TIMELINE = 'REQUEST_GET_MENTIONS_TIMELINE'; 18 | export const SUCCESS_GET_MENTIONS_TIMELINE = 'SUCCESS_GET_MENTIONS_TIMELINE'; 19 | export const FAILURE_GET_MENTIONS_TIMELINE = 'FAILURE_GET_MENTIONS_TIMELINE'; 20 | export const requestGetMentionsTimeline = createAction(REQUEST_GET_MENTIONS_TIMELINE); 21 | export const successGetMentionsTimeline = createAction(SUCCESS_GET_MENTIONS_TIMELINE); 22 | export const failureGetMentionsTimeline = createAction(FAILURE_GET_MENTIONS_TIMELINE); 23 | 24 | export const RESET_TIMELINE = 'RESET_TIMELINE'; 25 | export const resetTimeline = createAction(RESET_TIMELINE); 26 | -------------------------------------------------------------------------------- /app/actions/update.js: -------------------------------------------------------------------------------- 1 | import { createAction } from 'redux-actions'; 2 | 3 | export const REQUEST_POST_UPDATE = 'REQUEST_POST_UPDATE'; 4 | export const SUCCESS_POST_UPDATE = 'SUCCESS_POST_UPDATE'; 5 | export const FAILURE_POST_UPDATE = 'FAILURE_POST_UPDATE'; 6 | export const requestPostUpdate = createAction(REQUEST_POST_UPDATE); 7 | export const successPostUpdate = createAction(SUCCESS_POST_UPDATE); 8 | export const failurePostUpdate = createAction(FAILURE_POST_UPDATE); 9 | 10 | export const INPUT_UPDATE = 'INPUT_UPDATE'; 11 | export const inputUpdate = createAction(INPUT_UPDATE); 12 | -------------------------------------------------------------------------------- /app/actions/user.js: -------------------------------------------------------------------------------- 1 | import { createAction } from 'redux-actions'; 2 | 3 | export const CLOSE_USER_MODAL = 'CLOSE_USER_MODAL'; 4 | export const closeUserModal = createAction(CLOSE_USER_MODAL); 5 | 6 | export const SET_USER = 'SET_USER'; 7 | export const setUser = createAction(SET_USER); 8 | -------------------------------------------------------------------------------- /app/actions/userStream.js: -------------------------------------------------------------------------------- 1 | import { createAction } from 'redux-actions'; 2 | 3 | export const REQUEST_STREAM_USER = 'REQUEST_STREAM_USER'; 4 | export const SUCCESS_STREAM_USER = 'SUCCESS_STREAM_USER'; 5 | export const FAILURE_STREAM_USER = 'FAILURE_STREAM_USER'; 6 | 7 | export const requestStreamUser = dispatch => ({ 8 | type: REQUEST_STREAM_USER, 9 | dispatch 10 | }); 11 | export const successStreamUser = createAction(SUCCESS_STREAM_USER); 12 | export const failureStreamUser = createAction(FAILURE_STREAM_USER); 13 | -------------------------------------------------------------------------------- /app/actions/users.js: -------------------------------------------------------------------------------- 1 | import { createAction } from 'redux-actions'; 2 | 3 | export const REQUEST_GET_USERS_SHOW = 'REQUEST_GET_USERS_SHOW'; 4 | export const SUCCESS_GET_USERS_SHOW = 'SUCCESS_GET_USERS_SHOW'; 5 | export const FAILURE_GET_USERS_SHOW = 'FAILURE_GET_USERS_SHOW'; 6 | export const requestGetUsersShow = createAction(REQUEST_GET_USERS_SHOW); 7 | export const successGetUsersShow = createAction(SUCCESS_GET_USERS_SHOW); 8 | export const failureGetUsersShow = createAction(FAILURE_GET_USERS_SHOW); 9 | -------------------------------------------------------------------------------- /app/components/Atoms/Button/Button.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import styles from './button.css'; 3 | 4 | export default ({ disabled = false, type = 'normal', value, disabledValue, onClick, title = '' }) => { 5 | if (disabled) { 6 | return ( 7 | 8 | ); 9 | } else if (type === 'submit') { 10 | return ( 11 | onClick()} title={title} /> 12 | ); 13 | } 14 | return ( 15 | onClick()} title={title} /> 16 | ); 17 | }; 18 | -------------------------------------------------------------------------------- /app/components/Atoms/Button/Button.test.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import sinon from 'sinon'; 3 | import { shallow, mount, render } from 'enzyme'; 4 | 5 | import Button from './Button'; 6 | 7 | describe('components/atoms/button', function() { 8 | it('should have "button" and "normal" classes', function() { 9 | expect(shallow().hasClass('button normal')).toEqual(true); 10 | }); 11 | it('should have "button" and "submit" classes', function() { 12 | expect(shallow().hasClass('button submit')).toEqual(true); 13 | }); 14 | it('should have value', function() { 15 | expect(shallow().prop('value')).toEqual('push'); 16 | }); 17 | it('simulates click events', function() { 18 | const onClick = sinon.spy(); 19 | const button = shallow(); 20 | button.simulate('click'); 21 | expect(onClick.calledOnce).toEqual(true); 22 | }); 23 | }); 24 | -------------------------------------------------------------------------------- /app/components/Atoms/Button/button.css: -------------------------------------------------------------------------------- 1 | @import '../../../styles/variable'; 2 | 3 | .button { 4 | display: inline-block; 5 | border: none; 6 | border-radius: 3px; 7 | padding: 5px 8px; 8 | font-size: 14px; 9 | cursor: pointer; 10 | 11 | &:hover { 12 | text-decoration: none; 13 | } 14 | 15 | &.disabled, &:disabled { 16 | background-image: none; 17 | background-color: #ccc; 18 | color: #999; 19 | cursor: default; 20 | 21 | &:hover { 22 | background-color: #ccc; 23 | background-image: none; 24 | } 25 | } 26 | } 27 | 28 | .normal { 29 | background: -moz-linear-gradient(top, #fff, #ddd); 30 | background: -webkit-gradient(linear, left top, left bottom, from(#fff), to(#ddd)); 31 | background-color: #ddd; 32 | color: #333; 33 | box-shadow: 0 0 1px rgba(0, 0, 0, 0.4); 34 | 35 | &:hover { 36 | background: -moz-linear-gradient(top, #fafafa, #d8d8d8); 37 | background: -webkit-gradient(linear, left top, left bottom, from(#fafafa), to(#d8d8d8)); 38 | background-color: #ddd; 39 | } 40 | } 41 | 42 | .submit { 43 | background-color: var(--color-submit); 44 | color: #fff; 45 | 46 | &:hover { 47 | opacity: 0.9; 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /app/components/Atoms/CreatedAt/CreatedAt.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import styles from './createdAt.css'; 3 | 4 | export default ({ children }) => { 5 | const getTime = (date) => { 6 | const hours = date.getHours(); 7 | const minutes = date.getMinutes() < 10 ? `0${date.getMinutes()}` : `${date.getMinutes()}`; 8 | return `${hours}:${minutes}`; 9 | }; 10 | 11 | return ( 12 | { getTime(new Date(children)) } 13 | ); 14 | }; 15 | -------------------------------------------------------------------------------- /app/components/Atoms/CreatedAt/createdAt.css: -------------------------------------------------------------------------------- 1 | .createdAt { 2 | color: #ccc; 3 | font-size: 10px; 4 | } 5 | -------------------------------------------------------------------------------- /app/components/Atoms/FavoriteTrigger/FavoriteTrigger.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import styles from './favoriteTrigger.css'; 3 | 4 | export default ({ id_str, favorited, favorite_count, requestPostFavoritesDestroy, requestPostFavoritesCreate }) => { 5 | const postFavorites = () => { 6 | if (favorited) { 7 | requestPostFavoritesDestroy(id_str); 8 | } else { 9 | requestPostFavoritesCreate(id_str); 10 | } 11 | }; 12 | return ( 13 | 14 | postFavorites()}> 15 | 16 | 17 | 18 | {favorite_count.toLocaleString()} 19 | 20 | 21 | ); 22 | }; 23 | -------------------------------------------------------------------------------- /app/components/Atoms/FavoriteTrigger/favoriteTrigger.css: -------------------------------------------------------------------------------- 1 | @import '../../../styles/variable'; 2 | 3 | .actionCount { 4 | display: inline-block; 5 | text-decoration: none; 6 | padding: 0 5px; 7 | } 8 | 9 | .isActioned path { 10 | fill: var(--color-accent) !important; 11 | } 12 | -------------------------------------------------------------------------------- /app/components/Atoms/Loading/Loading.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import styles from './loading.css'; 3 | 4 | export default () => ( 5 |
6 | ); 7 | -------------------------------------------------------------------------------- /app/components/Atoms/Loading/Loading.test.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { shallow, mount, render } from 'enzyme'; 3 | 4 | import Loading from './Loading'; 5 | 6 | describe('components/atoms/loading', function() { 7 | it('should have a "loading" class', function() { 8 | expect(shallow(