Skip to content

Commit

Permalink
Add <ArticleFooter/> (#78)
Browse files Browse the repository at this point in the history
* Add new component <ArticleFooter/>

* Apply <ArticleFooter/> in <Article/> and toc

* Adjustable font size in Footer section

* Prefetch article footer suggested article items

* Fix error when the suggested article return empty query

* Rename getArticleFooter -> getSuggestedArticles

* use isFooter to render <ArticleFooter/> and minor changes
  • Loading branch information
hueitan authored and jpita committed Jan 21, 2020
1 parent 866d625 commit 904f91e
Show file tree
Hide file tree
Showing 14 changed files with 247 additions and 33 deletions.
6 changes: 5 additions & 1 deletion i18n/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
"app-title": "Wikipedia",
"app-subtitle": "The free encyclopedia",
"app-description": "With the free Wikipedia app, search and explore information from all over the world in 300+ languages.",
"content-license": "Content is available under <a class=\"external\" rel=\"mw:ExtLink\" href=\"https://creativecommons.org/licenses/by-sa/3.0/\">CC BY-SA 3.0</a> unless otherwise noted.",
"confirm-section": "Go to Section \"$1\"",
"header-menu": "Article menu",
"header-search": "Search results",
Expand Down Expand Up @@ -40,6 +41,7 @@
"softkey-back": "Back",
"softkey-skip": "Skip",
"softkey-get-started": "Get started",
"suggested-articles": "SUGGESTED ARTICLES",
"reference-title": "Reference [$1]",
"offline-message": "No internet connection ",
"onboarding-0-title": "The free encyclopedia",
Expand All @@ -60,5 +62,7 @@
"settings-about-app": "About the app",
"textsize-increase": "Press 6 (Increase size)",
"textsize-decrease": "Press 4 (Decrease size)",
"textsize-default": "Press 5 (Default)"
"textsize-default": "Press 5 (Default)",
"toc-footer": "Suggested articles",
"view-in-browser": "View article in browser"
}
10 changes: 7 additions & 3 deletions i18n/qqq.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
"app-title": "Title of the application. Shown in the app store and the app launcher.",
"app-subtitle": "Subtitle of the application. Shown in the app store.",
"app-description": "Description of the application. Shown in the app store. The word \"free\" is in the sense of \"zero dollars, you don't have pay\".",
"content-license": "Paragraph of content license is under CC BY-SA 3.0. Shown in the Article footer page",
"confirm-section": "Confirm message switch to the selected section page. Shown in the Article page.\n* $1 - Selected section name",
"header-menu": "The header title of the menu page",
"header-search": "The header title of the search page",
Expand Down Expand Up @@ -40,6 +41,7 @@
"softkey-back": "Label of the back softkey",
"softkey-skip": "Label of the skip softkey",
"softkey-get-started": "Label of the get started softkey",
"suggested-articles": "Text of the suggested articles. Shown in the article footer page.",
"reference-title": "Header of the reference preview popup.\n* $1 - Number of the current reference.",
"offline-message": "Message to be display at the top of the screen when there is no internet connection.",
"onboarding-0-title": "First onboarding title message when the user first time start the application.",
Expand All @@ -58,7 +60,9 @@
"settings-rate": "Label of the Rate item list. Shown in the Settings menu, used in rating the app.",
"settings-help-feedback": "Label of Help and feedback item list. Shown in the Settings menu, to find help and give feedback.",
"settings-about-app": "Label of the About the app item list. Shown in the Settings menu, used in showing the information of this app",
"textsize-increase": "Label of the press key to increase the text size. Shown in the Text Size page.",
"textsize-decrease": "Label of the press key to decrease the text size. Shown in the Text Size page.",
"textsize-default": "Label of the press key to set the text size to be default. Shown in the Text Size page."
"textsize-increase": "Label of the press key to increase the text size. Shown in the Tet Size page.",
"textsize-decrease": "Label of the press key to decrease the text size. Shown in the Tet Size page.",
"textsize-default": "Label of the press key to set the text size to be default. Shown in the Tet Size page.",
"toc-footer": "Label of the footer item in the Table of Content list. Shown in the Toc page",
"view-in-browser": "Text of the View article in browser. Shown in the article footer page"
}
Binary file added images/wikipedia-wordmark-en.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
20 changes: 20 additions & 0 deletions src/api/getSuggestedArticles.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { buildMwApiUrl, cachedFetch } from 'utils'

export const getSuggestedArticles = (lang, title) => {
const params = {
action: 'query',
prop: 'pageimages|description',
piprop: 'thumbnail',
pithumbsize: 160,
pilimit: 3,
generator: 'search',
gsrsearch: `morelike:${title}`,
gsrnamespace: 0,
gsrlimit: 3,
gsrqiprofile: 'classic_noboostlinks',
uselang: 'content'
}

const url = buildMwApiUrl(lang, params)
return cachedFetch(url, data => data.query && data.query.pages)
}
1 change: 1 addition & 0 deletions src/api/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,6 @@ export * from './getArticle'
export * from './getArticleSummary'
export * from './getLanglinks'
export * from './getRandomArticleTitle'
export * from './getSuggestedArticles'
export * from './language'
export * from './search'
23 changes: 12 additions & 11 deletions src/components/Article.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { memo } from 'preact/compat'
import { useState, useRef, useEffect } from 'preact/hooks'
import {
ReferencePreview, ArticleToc, ArticleLanguage,
ArticleMenu, Loading
ArticleMenu, ArticleFooter, Loading
} from 'components'
import {
useArticle, useI18n, useSoftkey,
Expand All @@ -22,9 +22,9 @@ const ArticleBody = memo(({ content }) => {
})

const ArticleSection = ({
lang, imageUrl, title, description, hasActions,
content, page, showToc, goToSubpage, references,
hasInfobox
lang, imageUrl, title, description, isFooter,
hasActions, content, page, showToc, references,
goToSubpage, hasInfobox, articleTitle, suggestedArticles
}) => {
const contentRef = useRef()
const i18n = useI18n()
Expand Down Expand Up @@ -75,7 +75,10 @@ const ArticleSection = ({
) }
</div>
) }
<ArticleBody content={content} />
{ isFooter
? <ArticleFooter lang={lang} title={articleTitle} items={suggestedArticles} />
: <ArticleBody content={content} />
}
</div>
</div>
)
Expand All @@ -96,7 +99,6 @@ const ArticleInner = ({ lang, articleTitle, initialSubTitle }) => {
const [showMenuPopup] = usePopup(ArticleMenu, { mode: 'fullscreen' })
const [currentSection, setCurrentSection, currentPage] = useArticlePagination(containerRef, article, subTitle)
const section = article.sections[currentSection]

const goToArticleSubpage = ({ sectionIndex, title }) => {
setCurrentSection(
sectionIndex !== undefined
Expand Down Expand Up @@ -128,17 +130,16 @@ const ArticleInner = ({ lang, articleTitle, initialSubTitle }) => {
}, [])

return (
<div class='article' ref={containerRef}>
<div class={'article' + (section.isFooter ? ' footer' : '')} ref={containerRef}>
<ArticleSection
key={currentSection}
lang={lang}
title={section.title}
description={section.description}
imageUrl={section.imageUrl}
{...section}
articleTitle={articleTitle}
hasActions={currentSection === 0}
hasInfobox={!!article.infobox}
content={section.content}
references={article.references}
suggestedArticles={article.suggestedArticles}
showToc={showArticleTocPopup}
goToSubpage={goToArticleSubpage}
page={currentPage}
Expand Down
37 changes: 37 additions & 0 deletions src/components/ArticleFooter.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import { h } from 'preact'
import { useI18n } from 'hooks'
import { buildWpMobileWebUrl } from 'utils'

export const ArticleFooter = ({ lang, title, items = [] }) => {
const i18n = useI18n()

return (
<div class='article-footer'>
<div class='content'>
<h2 class='adjustable-font-size'>{i18n.i18n('suggested-articles')}</h2>
<div class='list'>
{ items.map(item => {
return (
<a class='item' title={item.title} key={item.title}>
<div class='info'>
<div class='article-title adjustable-font-size'>{item.title}</div>
<div class='description adjustable-font-size'>{item.description}</div>
</div>
{ item.thumbnail && <div class='img'><img src={item.thumbnail.source} /></div> }
</a>
)
})}
</div>
<h2 class='img'>
<img src='/images/wikipedia-wordmark-en.png' height='18' width='116' />
</h2>
<p class='license adjustable-font-size' dangerouslySetInnerHTML={{ __html: i18n.i18n('content-license') }} />
<p class='browser'>
<a class='external adjustable-font-size' rel='mw:ExtLink' href={buildWpMobileWebUrl(lang, title)}>
{i18n.i18n('view-in-browser')}
</a>
</p>
</div>
</div>
)
}
1 change: 1 addition & 0 deletions src/components/index.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
export * from './App'
export * from './Article'
export * from './ArticleFooter'
export * from './ArticleLanguage'
export * from './ArticleMenu'
export * from './ArticlePreview'
Expand Down
38 changes: 26 additions & 12 deletions src/hooks/useArticle.js
Original file line number Diff line number Diff line change
@@ -1,13 +1,27 @@
import { useState, useEffect } from 'preact/hooks'
import { getArticle } from 'api'

export const useArticle = (lang, title) => {
const [article, setArticle] = useState()

useEffect(() => {
getArticle(lang, title)
.then((article) => setArticle(article))
}, [lang, title])

return article
import { useState, useEffect } from 'preact/hooks'
import { useI18n } from 'hooks'
import { getArticle, getSuggestedArticles } from 'api'

export const useArticle = (lang, title) => {
const [article, setArticle] = useState()
const i18n = useI18n()

useEffect(() => {
Promise.all([getArticle(lang, title), getSuggestedArticles(lang, title)])
.then(([article, suggestedArticles]) => {
const { sections, toc } = article

// build footer used section and toc
const sectionsWithFooter = sections.concat({
title: i18n.i18n('toc-footer'),
imageUrl: false,
isFooter: true
})
const tocWithFooter = toc.concat({ level: 1, line: i18n.i18n('toc-footer'), sectionIndex: sectionsWithFooter.length - 1 })

setArticle({ ...article, sections: sectionsWithFooter, toc: tocWithFooter, suggestedArticles })
})
}, [lang, title])

return article
}
16 changes: 10 additions & 6 deletions src/hooks/useArticlePagination.js
Original file line number Diff line number Diff line change
Expand Up @@ -58,17 +58,21 @@ export const useArticlePagination = (
.from(elementRef.current.querySelectorAll('.title, h3, h4'))
.find(e => e.textContent === subTitle)

const offset = Math.floor(
subTitleElement.getBoundingClientRect().left / viewport.width
)
elementRef.current.scrollLeft += offset * viewport.width
setCurrentPage(elementRef.current.scrollLeft / viewport.width)
if (subTitleElement) {
const offset = Math.floor(
subTitleElement.getBoundingClientRect().left / viewport.width
)
elementRef.current.scrollLeft += offset * viewport.width
setCurrentPage(elementRef.current.scrollLeft / viewport.width)
}
}
}, [subTitle])

const showNextSection = () => {
const nextSection = currentSection + 1
setCurrentSection(nextSection < numOfSection ? nextSection : 0)
if (nextSection < numOfSection) {
setCurrentSection(nextSection)
}
}

const showPrevSection = () => {
Expand Down
5 changes: 5 additions & 0 deletions src/utils/mwApi.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,11 @@ export const buildMwApiUrl = (lang, params) => {
}).join('&')
}

export const buildWpMobileWebUrl = (lang, title) => {
const page = encodeURIComponent(normalizeTitle(title))
return `https://${lang}.m.wikipedia.org/w/index.php?title=${page}`
}

export const buildPcsUrl = (lang, title, endpoint) => {
const base = `https://${lang}.wikipedia.org`
const path = `api/rest_v1/page/${endpoint}`
Expand Down
15 changes: 15 additions & 0 deletions style/article.less
Original file line number Diff line number Diff line change
Expand Up @@ -171,4 +171,19 @@
}
}
}

&.footer {
.article-section {
padding-top: 0;

.card {
padding: 0;
margin: 0;

.title {
display: none;
}
}
}
}
}
107 changes: 107 additions & 0 deletions style/footer.less
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
.article-footer {
font-family: @textFont;
padding: 6px;
background-color: #f5f5f5;

.content {
h2 {
color: #54595d;
border-bottom: 0;
padding: 0.5em 0;
font-size: 0.8em;
font-weight: normal;
letter-spacing: 1px;
text-transform: uppercase;
}

.list {
width: 100%;

a.item {
height: 59px;
margin: 10px 0;
padding: 6px 10px;
display: flex;
justify-content: space-between;
border-radius: 5px;
background-color: #fff;
box-shadow: -2px 2px 10px 0 rgba( 0, 0, 0, 0.1 );
border: solid 1px #f5f5f5;

&[ data-selected='true' ] {
background-color: #eaf3ff;
}

.info {
font-family: @textFont;
height: 100%;
overflow: hidden;
display: flex;
flex-direction: column;
justify-content: center;

.article-title {
font-size: 15px;
white-space: nowrap;
text-overflow: ellipsis;
overflow: hidden;
}

.description {
font-size: 12px;
color: @colorLight;
white-space: nowrap;
text-overflow: ellipsis;
overflow: hidden;
}
}

.img {
height: 100%;
display: flex;
flex-direction: column;
justify-content: center;

img {
width: 38px;
height: 38px;
border-radius: 4px;
}
}

.link {
display: flex;
flex-direction: column;
justify-content: center;
}

&[ nav-selected=true ] {
background-color: #eaf3ff;
}
}
}
}

h2 {
padding-bottom: 10px;
padding-top: 20px;
margin: 0;

&.img {
padding: 20px 0 15px;
border-bottom: solid 1px #c8ccd1;
}
}

.license,
.browser {
font-size: 0.75em;
margin-bottom: 10px;
line-height: normal;
}

a {
text-decoration: none;
padding: 1px;
}
}
Loading

0 comments on commit 904f91e

Please sign in to comment.