Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Create a Wikibase discovery page #719

Merged
merged 22 commits into from
Sep 11, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
12b5398
Create a Wikibase discovery page
AndrewKostka Aug 25, 2023
ef905ff
Merge branch 'main' into discovery-feature
AndrewKostka Aug 28, 2023
c866f2b
Show first page of results when modifying filters
AndrewKostka Aug 28, 2023
56162db
Enable empty Wikibase filter
AndrewKostka Aug 28, 2023
09f8b03
Adjust empty Wikibase filter positioning
AndrewKostka Aug 28, 2023
481b0b7
Fix content width for larger displays
AndrewKostka Aug 28, 2023
ac0935b
Update copy for when Wikibase stats are unavailable
AndrewKostka Aug 28, 2023
3b30303
Switch to a masonry grid layout
AndrewKostka Sep 1, 2023
3b3bc28
Rename components
AndrewKostka Sep 1, 2023
cff22bd
Remove semicolons and trailing commas
AndrewKostka Sep 1, 2023
c3d65c7
Add mock data
AndrewKostka Sep 5, 2023
e29e038
Fix logo url for mock data
AndrewKostka Sep 5, 2023
b2e321f
Set page count as the default sort order
AndrewKostka Sep 6, 2023
94f28f1
Enter key should open Wikibase
AndrewKostka Sep 6, 2023
75ba29f
Update copy for discovery page
AndrewKostka Sep 7, 2023
5ed7678
Scroll to top after list is updated
AndrewKostka Sep 7, 2023
44ba200
Adjust content margins and breakpoints
AndrewKostka Sep 7, 2023
3023b4c
Merge branch 'main' into discovery-feature
AndrewKostka Sep 7, 2023
903b787
Fix linting errors
AndrewKostka Sep 7, 2023
b82b212
Switch to a rounded avatar for Wikibase logos
AndrewKostka Sep 11, 2023
c769dce
Simplify diff for merge
AndrewKostka Sep 11, 2023
115c085
Merge branch 'main' into discovery-feature
AndrewKostka Sep 11, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 12 additions & 5 deletions src/App.vue
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
<template>
<v-app id="app">
<Navbar></Navbar>

<v-container class="full-height-content">
<router-view v-if="customLayout"/>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess this might be a sign in future we should move the "rows and cols" into each page. I suspect in most cases each "page" really wants control of it's layout rather than having it imposed on it at the App level

<v-container v-else class="full-height-content">
<v-row >
<v-col cols="1"></v-col>
<v-col cols="10">
Expand All @@ -11,9 +11,7 @@
<v-col cols="1"></v-col>
</v-row>
</v-container>

<Foot></Foot>

<Foot :class="{'tall-footer': customLayout}"></Foot>
<Interval
v-if="this.$store.getters.isLoggedIn && !this.$store.getters.currentUser.verified"
:callback="checkVerified"
Expand All @@ -34,6 +32,11 @@ export default {
Foot,
Interval
},
computed: {
customLayout: function () {
return this.$route.meta.customLayout
}
},
methods: {
checkVerified () {
this.$api
Expand All @@ -51,4 +54,8 @@ export default {
.full-height-content {
height: 100%
}

.tall-footer.footer {
height: 100%;
}
</style>
11 changes: 11 additions & 0 deletions src/backend/api.js
Original file line number Diff line number Diff line change
Expand Up @@ -52,3 +52,14 @@ export const updateLogo = async ({ file, fileName, wikiId }) => {
export const updateSetting = async (setting, payload) => axios.post(`/wiki/setting/${setting}/update`, { ...payload, setting })
export const updateSkin = async payload => updateSetting('wgDefaultSkin', payload)
export const wikiDetails = async payload => (await axios.post('/wiki/details', payload)).data.data
export const wikiDiscovery = async ({ sort, direction, active, currentPage, resultsPerPage }) => {
return (await axios.get('/wiki', {
params: {
sort: sort,
direction: direction,
is_active: active,
page: currentPage,
per_page: resultsPerPage
}
})).data
}
80 changes: 80 additions & 0 deletions src/backend/mocks/default_handlers.js
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,83 @@ const removeWiki = wikiIndex => {
localStorage.setItem('msw-myWikis', JSON.stringify(myWikis))
}

const wikiDiscovery = (referrer, params) => {
const pseudorandom = {
seed: 1,
next: function () {
const x = Math.sin(this.seed++) * 10000
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice, quite a satisfying way to do this

return x - Math.floor(x)
}
}

const names = [
'Wikibase Name',
'A Very Long Wikibase Name'
]

let wikis = [...Array(75).keys()].map((id) => {
const wiki = {
id: id,
domain: id + '-wikibase.wbaas.localhost',
sitename: id + ' - ' + names[id % names.length],
wiki_site_stats: null,
logo_url: null
}

if (pseudorandom.next() >= 0.1) {
wiki.wiki_site_stats = {
pages: Math.ceil(pseudorandom.next() * 250)
}
}

if (pseudorandom.next() >= 0.5) {
wiki.logo_url = new URL(referrer).origin + '/favicon.ico'
}
return wiki
})

if (parseInt(params.get('is_active'))) {
wikis = wikis.filter((wiki) => {
const stats = wiki.wiki_site_stats
return stats && stats.pages > 1
})
}

if (params.get('sort') === 'sitename') {
wikis = wikis.sort((a, b) => {
let sort = a.sitename.localeCompare(b.sitename, 'en', { numeric: true })
if (params.get('direction') === 'desc') {
sort *= -1
}
return sort
})
}

if (params.get('sort') === 'pages') {
wikis = wikis.sort((a, b) => {
const aPages = a.wiki_site_stats ? a.wiki_site_stats.pages : 0
const bPages = b.wiki_site_stats ? b.wiki_site_stats.pages : 0
if (params.get('direction') === 'desc') {
return bPages - aPages
}
return aPages - bPages
})
}

const currentPage = parseInt(params.get('page'))
const resultsPerPage = parseInt(params.get('per_page'))
const start = (currentPage - 1) * resultsPerPage
const end = start + resultsPerPage

return {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just generally I love this super comprehensive mock data; makes testing the thing really convenient

data: wikis.slice(start, end),
meta: {
last_page: Math.ceil(wikis.length / resultsPerPage),
total: wikis.length
}
}
}

export const handlers = [
/* User endpoints */
rest.post(/\/auth\/login$/, (req, res, ctx) => {
Expand Down Expand Up @@ -108,5 +185,8 @@ export const handlers = [
return res(ctx.status(404))
}
return res(ctx.json({ data: wikiDetails }), ctx.status(200))
}),
rest.get(/\/wiki$/, (req, res, ctx) => {
return res(ctx.json(wikiDiscovery(req.referrer, req.url.searchParams)))
})
]
10 changes: 8 additions & 2 deletions src/components/Layout/Foot.vue
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
<template>
<footer>
<footer class="footer">
<v-footer color="primary lighten-1">
<v-container>
<v-row dense>
<v-col cols="1"></v-col>
<v-col cols="10">
<ul class="footer-list">
<li><a target="_blank" rel="noopener noreferrer" href="https://wikiba.se/about-us/">About</a></li>
<li><router-link to="/discovery">Discovery</router-link></li>
<li><a target="_blank" rel="noopener noreferrer" href="https://www.mediawiki.org/wiki/Wikibase/Wikibase.cloud">Documentation</a></li>
<li><a target="_blank" rel="noopener noreferrer" href="https://github.com/wbstack">Github</a></li>
<li><router-link to="/privacy-policy">Privacy Policy</router-link></li>
Expand Down Expand Up @@ -39,5 +40,10 @@ export default {
.white-footer-links a{
color: white !important;
}

.footer {
height: auto;
}
.v-footer, .container {
height: 100%;
}
</style>
3 changes: 3 additions & 0 deletions src/components/Layout/Navbar.vue
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,9 @@ export default {
</script>

<style scoped>
.v-toolbar {
max-height: 64px;
}
.no-button-pointer-events{
pointer-events: none
}
Expand Down
74 changes: 74 additions & 0 deletions src/components/Pages/Discovery/Components/DiscoveryCard.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
<template>
<v-card @click="goToWiki" @keyup.enter="goToWiki">
<v-container class="content">
<v-row no-gutters>
<v-col class="flex-grow-0">
<v-avatar rounded :color="color">
<img v-if="logo" :src="logo.href">
<span v-else class="white--text">{{character}}</span>
</v-avatar>
</v-col>
<v-col class="details">
<div class="text-h5 font-weight-regular">{{name}}</div>
<div v-if="stats" class="text-body-2 pages">No. of pages: {{pages}}</div>
<div v-else class="text-body-2 pages">No. of pages: <i>currently unavailable</i></div>
</v-col>
</v-row>
</v-container>
</v-card>
</template>

<script>
export default {
name: 'DiscoveryCard',
props: {
name: {
type: String,
required: true
},
url: {
type: URL,
required: true
},
logo: {
type: URL,
required: false
},
stats: {
type: Boolean,
required: true
},
pages: {
type: Number,
required: false
}
},
computed: {
character: function () {
return this.name.substring(0, 1).toUpperCase()
},
color: function () {
const colors = ['red', 'blue', 'green', 'purple']
return this.logo ? 'white' : colors[Math.floor(Math.random() * colors.length)]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not really an issue but just a note: this means on recreating the component the colour will change

}
},
methods: {
goToWiki () {
window.open(this.url.href, '_blank')
}
}
}
</script>

<style scoped>
.content {
padding: 16px 16px;
}
.details.col {
padding-left: 16px !important;
word-wrap: anywhere;
}
.pages {
padding-top: 4px;
}
</style>
60 changes: 60 additions & 0 deletions src/components/Pages/Discovery/Components/MasonryGrid.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
<template>
<div class="grid" ref="grid">
<slot/>
</div>
</template>

<script>
export default {
name: 'MasonryGrid',
data () {
return {
timer: null
}
},
methods: {
resizeCards () {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is totally fine, no need to change but I was wondering if there was a more native vuetify way to do this (e.g. maybe using it's breakpoint functionality)

const cards = this.$refs.grid.children
const style = window.getComputedStyle(this.$refs.grid)
const rowGap = parseInt(style.getPropertyValue('row-gap'))
const gridAutoRows = parseInt(style.getPropertyValue('grid-auto-rows'))
const rowHeight = rowGap + gridAutoRows

Array.from(cards).forEach((card) => {
const cardHeight = card.firstChild.getBoundingClientRect().height + rowGap
const numRows = Math.round(cardHeight / rowHeight)
card.style['grid-row'] = 'span ' + numRows
})
},
debounceResize (time) {
clearTimeout(this.timer)
this.timer = setTimeout(() => {
this.resizeCards()
}, time)
},
windowResized () {
this.debounceResize(50)
}
},
created () {
window.addEventListener('resize', this.windowResized)
},
destroyed () {
window.removeEventListener('resize', this.windowResized)
},
updated () {
this.$nextTick(() => {
this.resizeCards()
})
}
}
</script>

<style scoped>
.grid {
display: grid;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is cool, I didn't know this was a thing (masonry grids in native css) until I saw this

row-gap: 16px;
grid-template-columns: repeat(auto-fill, minmax(288px, 1fr));
grid-auto-rows: 1px;
}
</style>
Loading
Loading