Merge branch 'develop'

This commit is contained in:
Sam Carlton 2020-11-27 23:37:23 -06:00
commit 8a7b7fd6cf
14 changed files with 325 additions and 52 deletions

1
.gitignore vendored
View file

@ -85,5 +85,6 @@ dist
/static/app-list.json /static/app-list.json
/README-temp.md /README-temp.md
/static/game-list.json /static/game-list.json
/static/homebrew-list.json
.DS_Store .DS_Store
/commits-data.json /commits-data.json

View file

@ -146,6 +146,10 @@ export default {
label: 'Categories', label: 'Categories',
url: '/categories', url: '/categories',
}, },
{
label: 'Homebrew',
url: '/kind/homebrew',
},
{ {
label: 'Games', label: 'Games',
url: '/games', url: '/games',

View file

@ -76,7 +76,7 @@
style="transition-property: border;" style="transition-property: border;"
> >
<template v-if="seenItems[app.slug] === false && hasStartedAnyQuery === false"> <template v-if="seenItems[app.slug] === false && hasStartedAnyQuery === false">
{{ app.endpoint.includes('/game/') ? `🕹${app.name}` : app.name }} {{ app.section.icon.length !== 0 ? `${app.section.icon} ${app.name}` : app.name }}
<div class="text-sm leading-5 font-bold"> <div class="text-sm leading-5 font-bold">
{{ app.text }} {{ app.text }}
</div> </div>
@ -89,7 +89,7 @@
</div> </div>
</client-only> </client-only>
{{ app.endpoint.includes('/game/') ? `🕹${app.name}` : app.name }} {{ app.section.icon.length !== 0 ? `${app.section.icon} ${app.name}` : app.name }}
<div class="text-sm leading-5 font-bold"> <div class="text-sm leading-5 font-bold">
{{ app.text }} {{ app.text }}
</div> </div>
@ -192,6 +192,10 @@ export default {
type: Boolean, type: Boolean,
default: false default: false
}, },
initialLimit: {
type: Number,
default: null
},
quickButtons: { quickButtons: {
type: Array, type: Array,
default: () => [ default: () => [
@ -249,7 +253,9 @@ export default {
}, },
computed: { computed: {
results () { results () {
if (!this.hasSearchInputText) return this.appList if (!this.hasSearchInputText) {
return this.initialLimit !== null ? this.appList.slice(0, this.initialLimit) : this.appList
}
return [ return [
...this.titleStartsWithResults, ...this.titleStartsWithResults,

View file

@ -194,7 +194,8 @@ export default async function () {
endpoint, endpoint,
section: { section: {
label: sectionTitle, label: sectionTitle,
slug: sectionSlug slug: sectionSlug,
icon: ''
}, },
content: token.content, content: token.content,
relatedLinks relatedLinks

View file

@ -125,7 +125,8 @@ export default async function () {
endpoint: `/game/${slug}`, endpoint: `/game/${slug}`,
section: { section: {
label: 'Games', label: 'Games',
slug: 'games' slug: 'games',
icon: '🎮'
}, },
content: '', content: '',
relatedLinks: [ relatedLinks: [

View file

@ -0,0 +1,175 @@
// import { promises as fs } from 'fs'
// import MarkdownIt from 'markdown-it'
import slugify from 'slugify'
import axios from 'axios'
// import statuses from './statuses'
// import parseGithubDate from './parse-github-date'
const marked = require('marked')
const HTMLParser = require(`node-html-parser`)
const statusesTranslations = {
// brew install -s succeeds on Apple Silicon. The software works well enough natively.
'🥇': 'native',
// The formula has been updated with depends_on :arch => [:x86_64, :build]. The software works well enough on Rosetta.
'🥈': 'rosetta',
// The formula has known issues on macOS 11, though most features work. The issues are described in the Comments field.
'🥉': 'rosetta',
// The formula has been updated with depends_on :arch => :x86_64. The software has been deemed to work on Intel only (for now).
'🚫': 'no',
// The formula has been found to need more analysis/work.
'⚠️': 'no',
}
const statusesMessages = {
'🥇': '✅ Yes, Full Native Apple Silicon Support',
'🥈': '✳️ Yes, works via Rosetta 2',
'🥉': '⏹ Known issues on macOS 11, though most features work',
'⚠️': '⏹ No, not yet, support is still in progress',
'🚫': '🚫 No, not yet supported only works on Intel-based Macs'
}
function getStatusText(formula) {
// Match status to Sheet Status
return statusesMessages[formula.status]
}
function parseStatus(formulae) {
// Match status to Sheet Status
return statusesTranslations[formulae.status]
}
export default async function () {
// Fetch Homebrew
const response = await axios.get(process.env.HOMEBREW_SOURCE)
// Extract commit from response data
const issueMarkdown = response.data.data.repository.issue.body
// Parse markdown
const issueHTML = marked(issueMarkdown)
// Parse Markdown HTML into a dom
const dom = HTMLParser.parse(issueHTML)
// Map table Headings
// [ 'Formula', 'Works1on 11.0', 'Comments' ]
// const tableHeadings = dom.querySelectorAll('thead th').map(th => th.rawText)
const headings = [
'fullName',
'status',
'comments'
]
// Map Formulae List within table
const tableRows = dom.querySelectorAll('table tr')
// Remove the first row (Headings)
tableRows.shift()
const tableRowData = tableRows.map( tr => {
// Map Table Cells
const cellsData = tr.querySelectorAll('td').map((td, i) => {
const column = headings[i]
if (td.childNodes.length === 0) return ''
if (column === 'comments') return td.innerHTML
return td.rawText
})
const formulaeRow = Object.fromEntries(cellsData.map( (cellData, i) => {
return [ headings[i], cellData ]
}))
formulaeRow.name = formulaeRow.fullName.split(' ')[0]
formulaeRow.links = tr.querySelectorAll('a').map( a => {
const href = a.getAttribute('href')
return {
href,
label: a.rawText,
// a
}
})
// if (formulaeRow.links.length !== 0) console.log('formulaeRow', formulaeRow.links)
return formulaeRow
})
// console.log('dom', dom.length)
// console.log('issueHTML', issueHTML)
// console.log('formulaeWithStatus', formulaeWithStatus)
const formulaeList = []
for (const formulae of tableRowData) {
// If this formulae status is empty
// then skip this formulae
if (formulae.status.length === 0) continue
// If this formulae emoji status is not in statusesTranslations
// then skip this formulae
if (!statusesTranslations.hasOwnProperty(formulae.status)) continue
// Generate slug
const slug = formulae.name
// slugify(formulae.name, {
// lower: true,
// strict: true
// })
formulaeList.push({
name: formulae.name,
status: parseStatus(formulae),
url: `https://formulae.brew.sh/formula/${formulae.name}`,
text: getStatusText(formulae),
slug,
endpoint: `/formula/${slug}`,
section: {
label: 'Homebrew',
slug: 'homebrew',
icon: '🍺'
},
content: formulae.comments,
relatedLinks: [
{
href: `https://formulae.brew.sh/formula/${formulae.name}`,
label: formulae.name,
// a
},
...formulae.links
],
// reports: [
// formulae
// ]
})
}
// console.log('formulaeList', formulaeList)
return formulaeList
}

12
helpers/get-list.js Normal file
View file

@ -0,0 +1,12 @@
import appList from '~/static/app-list.json'
import gameList from '~/static/game-list.json'
import homebrewList from '~/static/homebrew-list.json'
import { byTimeThenNull } from '~/helpers/sort-list.js'
export const allList = [
...appList.sort(byTimeThenNull),
...homebrewList,
...gameList,
]

View file

@ -1,9 +1,10 @@
import { promises as fs } from 'fs' import { promises as fs } from 'fs'
import path from 'path' // import path from 'path'
import pkg from './package' import pkg from './package'
import buildAppList from './helpers/build-app-list.js' import buildAppList from './helpers/build-app-list.js'
import buildGamesList from './helpers/build-game-list.js' import buildGamesList from './helpers/build-game-list.js'
import buildHomebrewList from './helpers/build-homebrew-list.js'
const listsOptions = [ const listsOptions = [
@ -14,6 +15,10 @@ const listsOptions = [
{ {
buildMethod: buildGamesList, buildMethod: buildGamesList,
path: '/static/game-list.json', path: '/static/game-list.json',
},
{
buildMethod: buildHomebrewList,
path: '/static/homebrew-list.json',
} }
] ]
@ -91,21 +96,12 @@ export default {
.then(( lists ) => { .then(( lists ) => {
// console.log('appList', appList) // console.log('appList', appList)
// const appRoutes = appList.map(app => ({
// route: '/app/' + app.slug,
// // payload: appList
// }))
// const gameRoutes = gameList.map(game => ({
// route: '/game/' + game.slug,
// // payload: appList
// }))
const sectionList = [] const sectionList = []
const [ const [
appRoutes, appRoutes,
gameRoutes gameRoutes,
homebrewRoutes
] = lists.map((list, listI) => { ] = lists.map((list, listI) => {
return list.map( app => { return list.map( app => {
// Find and store all sections // Find and store all sections
@ -117,6 +113,8 @@ export default {
}) })
}) })
// console.log('homebrewRoutes', homebrewRoutes)
const sectionRoutes = sectionList.map(slug => ({ const sectionRoutes = sectionList.map(slug => ({
route: '/kind/' + slug, route: '/kind/' + slug,
// payload: appList // payload: appList
@ -125,6 +123,7 @@ export default {
return [ return [
...appRoutes, ...appRoutes,
...gameRoutes, ...gameRoutes,
...homebrewRoutes,
...sectionRoutes ...sectionRoutes
] ]
}) })

26
package-lock.json generated
View file

@ -1367,6 +1367,17 @@
"fs-extra": "^8.1.0", "fs-extra": "^8.1.0",
"html-minifier": "^4.0.0", "html-minifier": "^4.0.0",
"node-html-parser": "^1.3.1" "node-html-parser": "^1.3.1"
},
"dependencies": {
"node-html-parser": {
"version": "1.4.9",
"resolved": "https://registry.npmjs.org/node-html-parser/-/node-html-parser-1.4.9.tgz",
"integrity": "sha512-UVcirFD1Bn0O+TSmloHeHqZZCxHjvtIeGdVdGMhyZ8/PWlEiZaZ5iJzR189yKZr8p0FXN58BUeC7RHRkf/KYGw==",
"dev": true,
"requires": {
"he": "1.2.0"
}
}
} }
}, },
"@nuxt/loading-screen": { "@nuxt/loading-screen": {
@ -6471,8 +6482,7 @@
"he": { "he": {
"version": "1.2.0", "version": "1.2.0",
"resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz",
"integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw=="
"dev": true
}, },
"hex-color-regex": { "hex-color-regex": {
"version": "1.1.0", "version": "1.1.0",
@ -7729,6 +7739,11 @@
"uc.micro": "^1.0.5" "uc.micro": "^1.0.5"
} }
}, },
"marked": {
"version": "1.2.5",
"resolved": "https://registry.npmjs.org/marked/-/marked-1.2.5.tgz",
"integrity": "sha512-2AlqgYnVPOc9WDyWu7S5DJaEZsfk6dNh/neatQ3IHUW4QLutM/VPSH9lG7bif+XjFWc9K9XR3QvR+fXuECmfdA=="
},
"md5.js": { "md5.js": {
"version": "1.3.5", "version": "1.3.5",
"resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.5.tgz", "resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.5.tgz",
@ -8139,10 +8154,9 @@
"dev": true "dev": true
}, },
"node-html-parser": { "node-html-parser": {
"version": "1.4.3", "version": "2.0.0",
"resolved": "https://registry.npmjs.org/node-html-parser/-/node-html-parser-1.4.3.tgz", "resolved": "https://registry.npmjs.org/node-html-parser/-/node-html-parser-2.0.0.tgz",
"integrity": "sha512-GXiLAg4ecY8CItLXXd2I8BqScBcIewhxO1erTEJ0A9K+r5HORAUkROZLxDokestkJYxt06t/IK84WaP0+6GyHA==", "integrity": "sha512-3wJdYSxiVIBxuiFm9UtfNWAlBw2P+Vb/RN1nqf40q2JeZDpcJ1HsrWuWV3j15SSJ25TvfnOoac2Q+uDU9iY0sw==",
"dev": true,
"requires": { "requires": {
"he": "1.2.0" "he": "1.2.0"
} }

View file

@ -19,6 +19,8 @@
"axios": "^0.21.0", "axios": "^0.21.0",
"cross-env": "^5.2.0", "cross-env": "^5.2.0",
"markdown-it": "^11.0.1", "markdown-it": "^11.0.1",
"marked": "^1.2.5",
"node-html-parser": "^2.0.0",
"observe-element-in-viewport": "0.0.15", "observe-element-in-viewport": "0.0.15",
"scroll-into-view-if-needed": "^2.2.26", "scroll-into-view-if-needed": "^2.2.26",
"slugify": "^1.4.5", "slugify": "^1.4.5",

View file

@ -38,21 +38,16 @@
import Search from '~/components/search.vue' import Search from '~/components/search.vue'
import LinkButton from '~/components/link-button.vue' import LinkButton from '~/components/link-button.vue'
import { byTimeThenNull } from '~/helpers/sort-list.js'
// import appList from '~/static/app-list.json' // import appList from '~/static/app-list.json'
// import gamelist from '~/static/game-list.json' // import gamelist from '~/static/game-list.json'
export default { export default {
async asyncData () { async asyncData () {
const { default: appList } = await import('~/static/app-list.json') // const { default: appList } = await import('~/static/app-list.json')
const { default: gamelist } = await import('~/static/game-list.json') // const { default: gamelist } = await import('~/static/game-list.json')
const allList = [ const { allList } = await import('~/helpers/get-list.js')
...appList.sort(byTimeThenNull),
...gamelist,
]
const sectionList = {} const sectionList = {}

70
pages/formula/_slug.vue Normal file
View file

@ -0,0 +1,70 @@
<template>
<section class="container py-32">
<div class="flex flex-col items-center text-center">
<h1 class="title text-sm md:text-2xl font-semibold">
Does <code>{{ app.name }}</code> work on Apple Silicon?
</h1>
<h2 class="subtitle text-2xl md:text-5xl font-bold py-6">
{{ app.text }}
</h2>
<small class="data-credit text-sm opacity-75 text-center mb-4">
<span>According to Github</span>
</small>
<div
class="comments text-sm mb-8"
v-html="app.content"
/>
<div class="links space-y-6 sm:space-x-6 mb-8">
<LinkButton
v-for="(link, i) in app.relatedLinks"
:key="i"
:href="link.href"
target="_blank"
class=""
>{{ (i === 0) ? 'View' : link.label }}</LinkButton>
</div>
</div>
</section>
</template>
<script>
import LinkButton from '~/components/link-button.vue'
import EmailSubscribe from '~/components/email-subscribe.vue'
import ThomasCredit from '~/components/thomas-credit.vue'
import homebrewList from '~/static/homebrew-list.json'
export default {
components: {
LinkButton,
EmailSubscribe,
ThomasCredit
},
async asyncData ({ params: { slug } }) {
return {
slug,
app: homebrewList.find(app => (app.slug === slug))
}
},
head() {
return {
title: `Does ${this.app.name} work on Apple Silicon?`,
// meta: [
// // hid is used as unique identifier. Do not use `vmid` for it as it will not work
// {
// hid: 'description',
// name: 'description',
// content: 'My custom description'
// }
// ]
}
}
}
</script>

View file

@ -9,7 +9,8 @@
</h2> </h2>
<Search <Search
:app-list="appList" :app-list="allList"
:initial-limit="200"
@update:query="query = $event" @update:query="query = $event"
/> />
@ -37,22 +38,17 @@
import Search from '~/components/search.vue' import Search from '~/components/search.vue'
import LinkButton from '~/components/link-button.vue' import LinkButton from '~/components/link-button.vue'
import { byTimeThenNull } from '~/helpers/sort-list.js'
import appList from '~/static/app-list.json'
import gameList from '~/static/game-list.json'
// console.log('appList.length', appList.length)
// console.log('gameList.length', gameList.length)
const sortedAppList = appList.sort(byTimeThenNull)
const mergedList = [
...sortedAppList,
...gameList
]
export default { export default {
async asyncData () {
// const { default: appList } = await import('~/static/app-list.json')
// const { default: gamelist } = await import('~/static/game-list.json')
const { allList } = await import('~/helpers/get-list.js')
return {
allList
}
},
components: { components: {
Search, Search,
LinkButton LinkButton
@ -61,11 +57,6 @@ export default {
return { return {
query: '', query: '',
} }
},
computed: {
appList() {
return mergedList
}
} }
} }
</script> </script>

View file

@ -45,9 +45,11 @@ import { byTimeThenNull } from '~/helpers/sort-list.js'
import appList from '~/static/app-list.json' import appList from '~/static/app-list.json'
import gamelist from '~/static/game-list.json' import gamelist from '~/static/game-list.json'
import homebrewList from '~/static/homebrew-list.json'
const allList = [ const allList = [
...appList.sort(byTimeThenNull), ...appList.sort(byTimeThenNull),
...homebrewList,
...gamelist, ...gamelist,
] ]