Skip to content

Commit

Permalink
More tabs updates
Browse files Browse the repository at this point in the history
  • Loading branch information
rowanhogan committed Jul 18, 2020
1 parent 551f56f commit 6fd1906
Show file tree
Hide file tree
Showing 9 changed files with 127 additions and 26 deletions.
4 changes: 2 additions & 2 deletions src/components/header/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ class Header extends Component {
return window === window.top ? (
<header
ref='header'
className={['header', hidden && 'hidden', scroll > 20 && 'scrolled', tabs.length && 'header-tabs']
className={['header', hidden && 'hidden', scroll > 20 && 'scrolled', tabs.length > 1 && 'header-tabs']
.filter(Boolean)
.join(' ')}>
<nav className='header-nav'>
Expand All @@ -53,7 +53,7 @@ class Header extends Component {
<Search />
<Settings />
</nav>
<Tabs tabs={tabs} />
<Tabs />
</header>
) : null
}
Expand Down
15 changes: 11 additions & 4 deletions src/components/page/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ class Page extends Component {
return Promise.resolve()
.then(() => pageIsCached ? pages[title] : fetchPage(title))
.then(page => {
document.title = `${title} - Wikipadia`
document.title = `${page.title} - Wikipadia`
storePage(title, page)

this.setState(
Expand Down Expand Up @@ -73,19 +73,23 @@ class Page extends Component {
}

handleClick (e) {
const { tabs } = this.props
const { storePage, tabs } = this.props
const { title } = this.state

if (e.target.nodeName === 'A' && this.isWebApp()) {
e.preventDefault()

const url = e.target.href.replace(window.location.origin, '')
const newTitle = decodeURIComponent(url.split('/')[1].replace(/_/g, ' '))

if (tabs.length === 0) {
this.props.addTab(stripTags(title), `/${encodeURIComponent(stripTags(title).replace(/ /g, '_'))}`)
}

this.props.addTab(decodeURIComponent(url.split('/')[1].replace(/_/g, ' ')), url)
this.props.addTab(newTitle, url)

fetchPage(newTitle)
.then(page => storePage(newTitle, page))
}
}

Expand Down Expand Up @@ -118,7 +122,10 @@ class Page extends Component {
}
}

const mapStateToProps = ({ pages, tabs }) => ({ pages, tabs })
const mapStateToProps = ({ pages, tabs }) => ({
pages,
tabs: tabs.items
})

export default compose(
connect(mapStateToProps, { addTab, storePage }),
Expand Down
27 changes: 17 additions & 10 deletions src/components/tabs/index.js
Original file line number Diff line number Diff line change
@@ -1,18 +1,16 @@
import React, { useState } from 'react'
import React from 'react'
import { compose } from 'redux'
import { connect } from 'react-redux'
import { withRouter } from 'react-router-dom'
import { removeTab } from '../../store/tabs'
import { activateTab, removeTab } from '../../store/tabs'

import { Link } from 'react-router-dom'

const Tabs = ({ tabs, removeTab, history }) => {
if (tabs.length) {
const [active, setActive] = useState(tabs[0].id)

const Tabs = ({ activateTab, active, pages, tabs, removeTab, history }) => {
if (tabs.length > 1) {
const handleClick = tab => e => {
window.scrollTo(0, 0)
return setActive(tab.id)
return activateTab(tab.id)
}

const handleRemove = tab => e => {
Expand All @@ -22,7 +20,7 @@ const Tabs = ({ tabs, removeTab, history }) => {
const newTab = tabs[currentIndex + 1] || tabs[currentIndex - 1]

if (newTab) {
setActive(newTab.id)
activateTab(newTab.id)
window.scrollTo(0, 0)
history.push(newTab.path)
}
Expand All @@ -34,9 +32,10 @@ const Tabs = ({ tabs, removeTab, history }) => {
<nav className='tabs'>
{tabs.map(tab => {
const isActive = active === tab.id
const page = pages[tab.path.substring(1)]

return (
<div key={tab.id} className={['tab-link', isActive && 'tab-link-active'].filter(Boolean).join(' ')}>
<div key={tab.id} className={['tab-link', isActive && 'tab-link-active', (isActive && !page) && 'tab-link-loading', !page && 'tab-link-inactive'].filter(Boolean).join(' ')}>
<Link
to={tab.path}
onClick={handleClick(tab)}
Expand All @@ -56,7 +55,15 @@ const Tabs = ({ tabs, removeTab, history }) => {
return null
}

const mapStateToProps = ({ pages, tabs }) => ({
active: tabs.active,
pages,
tabs: tabs.items
})

const mapDispatchToProps = { activateTab, removeTab }

export default compose(
connect(null, { removeTab }),
connect(mapStateToProps, mapDispatchToProps),
withRouter
)(Tabs)
20 changes: 20 additions & 0 deletions src/lib/localStorage/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
export const setLocalStorageItem = (key, val) => {
try {
const { localStorage } = window
const serializedValue = JSON.stringify(val)
localStorage.setItem(key, serializedValue)
} catch (err) {}
}

export const getLocalStorageItem = key => {
try {
const { localStorage } = window
const serializedValue = localStorage.getItem(key)
if (serializedValue === null) {
return undefined
}
return JSON.parse(serializedValue)
} catch (err) {
return undefined
}
}
2 changes: 1 addition & 1 deletion src/routes/app/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ class App extends Component {
const mapStateToProps = ({ settings, tabs }) => ({
darkMode: settings.darkMode,
classNames: Object.keys(settings).filter(setting => settings[setting]),
tabs: tabs
tabs: tabs.items
})

export default connect(mapStateToProps)(App)
15 changes: 12 additions & 3 deletions src/store/index.js
Original file line number Diff line number Diff line change
@@ -1,15 +1,16 @@
import { combineReducers, createStore, applyMiddleware } from 'redux'
import { getLocalStorageItem, setLocalStorageItem } from '../lib/localStorage'
import thunk from 'redux-thunk'
import createLogger from 'redux-logger'

import pages from './pages'
import settings from './settings'
import tabs from './tabs'

const initialState = {}
const initialState = getLocalStorageItem('wikipadia-state')

export default () =>
createStore(
export default () => {
const store = createStore(
combineReducers({
pages,
settings,
Expand All @@ -18,3 +19,11 @@ export default () =>
initialState,
applyMiddleware(thunk, createLogger)
)

store.subscribe(() => {
const { tabs } = store.getState()
setLocalStorageItem('wikipadia-state', { tabs })
})

return store
}
40 changes: 34 additions & 6 deletions src/store/tabs/index.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
import uuid from 'uuid/v4'

export const activateTab = (id) => dispatch =>
dispatch({
type: 'TABS/ACTIVATE',
payload: { id }
})

export const addTab = (name, path) => dispatch =>
dispatch({
type: 'TABS/ADD',
Expand All @@ -12,25 +18,47 @@ export const removeTab = id => dispatch =>
payload: { id }
})

export default (state = [], action) => {
const defaultState = {
active: null,
items: []
}

export default (state = defaultState, action) => {
switch (action.type) {
case 'TABS/ACTIVATE': {
const { id } = action.payload

return {
...state,
active: id
}
}

case 'TABS/ADD': {
const { name, path } = action.payload
const id = uuid()

return [
return {
...state,
{ name, path, id: uuid() }
]
active: state.active || id,
items: [
...state.items,
{ name, path, id }
]
}
}

case 'TABS/REMOVE': {
const { id } = action.payload

if (state.length === 2) {
return []
return defaultState
}

return state.filter(tab => tab.id !== id)
return {
...state,
items: state.items.filter(tab => tab.id !== id)
}
}

default:
Expand Down
19 changes: 19 additions & 0 deletions src/styles/_layout.scss
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,25 @@
border-right-color: rgba(128, 128, 128, 0.25);
opacity: 1;
}

.tab-link.tab-link-loading {
opacity: 0.25;
animation: blink 2s ease infinite ;
}
}

@keyframes blink {
0% {
opacity: 0.25;
}

50% {
opacity: 0.75;
}

100% {
opacity: 0.25;
}
}

.remove-tab-link {
Expand Down
11 changes: 11 additions & 0 deletions src/styles/styles.css
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,17 @@ table {
border-bottom-color: transparent;
border-right-color: rgba(128, 128, 128, 0.25);
opacity: 1; }
.tabs .tab-link.tab-link-loading {
opacity: 0.25;
animation: blink 2s ease infinite; }

@keyframes blink {
0% {
opacity: 0.25; }
50% {
opacity: 0.75; }
100% {
opacity: 0.25; } }

.remove-tab-link {
position: absolute;
Expand Down

0 comments on commit 6fd1906

Please sign in to comment.