-
Notifications
You must be signed in to change notification settings - Fork 7
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
Changes from all commits
12b5398
ef905ff
c866f2b
56162db
09f8b03
481b0b7
ac0935b
3b30303
3b3bc28
cff22bd
c3d65c7
e29e038
b2e321f
94f28f1
75ba29f
5ed7678
44ba200
3023b4c
903b787
b82b212
c769dce
115c085
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -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 | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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 { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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) => { | ||
|
@@ -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))) | ||
}) | ||
] |
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)] | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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> |
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 () { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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> |
There was a problem hiding this comment.
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