mirror of
https://github.com/ThatGuySam/doesitarm.git
synced 2026-05-18 06:44:46 -07:00
Merge branch 'feat/devices'
This commit is contained in:
commit
3da46a63da
16 changed files with 453 additions and 35 deletions
|
|
@ -5,6 +5,7 @@ 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'
|
import buildHomebrewList from './helpers/build-homebrew-list.js'
|
||||||
import buildVideoList from './helpers/build-video-list.js'
|
import buildVideoList from './helpers/build-video-list.js'
|
||||||
|
import buildDeviceList from './helpers/build-device-list.js'
|
||||||
|
|
||||||
import { videosRelatedToApp } from './helpers/related.js'
|
import { videosRelatedToApp } from './helpers/related.js'
|
||||||
import { buildVideoPayload, buildAppBenchmarkPayload } from './helpers/build-payload.js'
|
import { buildVideoPayload, buildAppBenchmarkPayload } from './helpers/build-payload.js'
|
||||||
|
|
@ -14,6 +15,7 @@ import {
|
||||||
getAppType,
|
getAppType,
|
||||||
getAppEndpoint,
|
getAppEndpoint,
|
||||||
getVideoEndpoint,
|
getVideoEndpoint,
|
||||||
|
isVideo
|
||||||
} from './helpers/app-derived.js'
|
} from './helpers/app-derived.js'
|
||||||
import { makeSearchableList } from './helpers/searchable-list.js'
|
import { makeSearchableList } from './helpers/searchable-list.js'
|
||||||
|
|
||||||
|
|
@ -61,6 +63,11 @@ class BuildLists {
|
||||||
path: '/static/homebrew-list.json',
|
path: '/static/homebrew-list.json',
|
||||||
buildMethod: buildHomebrewList,
|
buildMethod: buildHomebrewList,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: 'device',
|
||||||
|
path: '/static/device-list.json',
|
||||||
|
buildMethod: buildDeviceList,
|
||||||
|
},
|
||||||
|
|
||||||
// Secondary Derivative built lists
|
// Secondary Derivative built lists
|
||||||
// Always goes after initial lists
|
// Always goes after initial lists
|
||||||
|
|
@ -225,10 +232,10 @@ class BuildLists {
|
||||||
|
|
||||||
this.lists[listKey].forEach( app => {
|
this.lists[listKey].forEach( app => {
|
||||||
|
|
||||||
const isVideo = (app.category === undefined)
|
// const isVideo = (app.category === undefined)
|
||||||
const appType = getAppType( app )
|
const appType = getAppType( app )
|
||||||
|
|
||||||
if ( isVideo ) {
|
if ( isVideo( app ) ) {
|
||||||
// this.endpointMaps.eleventy.add({
|
// this.endpointMaps.eleventy.add({
|
||||||
// route: getVideoEndpoint(app),
|
// route: getVideoEndpoint(app),
|
||||||
// payload: buildVideoPayload( app, this.allVideoAppsList, this.lists.video )
|
// payload: buildVideoPayload( app, this.allVideoAppsList, this.lists.video )
|
||||||
|
|
@ -273,9 +280,14 @@ class BuildLists {
|
||||||
relatedVideos
|
relatedVideos
|
||||||
} )
|
} )
|
||||||
|
|
||||||
|
} else if ( appType === 'device' ) {
|
||||||
|
// Add device endpoint
|
||||||
|
// console.log('Added to nuxt endpoints', app.endpoint )
|
||||||
|
this.endpointMaps.nuxt.set( app.endpoint , { listing: app } )
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
// Add game or other endpoint
|
// Add game or other endpoint
|
||||||
// console.log('Added to nuxt endpoints', getAppEndpoint(app))
|
// console.log('Added to nuxt endpoints', app.endpoint )
|
||||||
this.endpointMaps.nuxt.set( getAppEndpoint(app), { app } )
|
this.endpointMaps.nuxt.set( getAppEndpoint(app), { app } )
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -147,6 +147,10 @@ export default {
|
||||||
label: 'Categories',
|
label: 'Categories',
|
||||||
url: '/categories',
|
url: '/categories',
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
label: 'Devices',
|
||||||
|
url: '/devices',
|
||||||
|
},
|
||||||
{
|
{
|
||||||
label: 'Benchmarks',
|
label: 'Benchmarks',
|
||||||
url: '/benchmarks',
|
url: '/benchmarks',
|
||||||
|
|
|
||||||
|
|
@ -16,12 +16,12 @@
|
||||||
<input
|
<input
|
||||||
id="search"
|
id="search"
|
||||||
ref="search"
|
ref="search"
|
||||||
|
:autofocus="autofocus"
|
||||||
v-model="query"
|
v-model="query"
|
||||||
aria-label="Type here to Search"
|
aria-label="Type here to Search"
|
||||||
class="appearance-none w-full text-white font-hairline sm:text-5xl outline-none bg-transparent p-3"
|
class="appearance-none w-full text-white font-hairline sm:text-5xl outline-none bg-transparent p-3"
|
||||||
type="search"
|
type="search"
|
||||||
placeholder="Type to Search"
|
placeholder="Type to Search"
|
||||||
autofocus
|
|
||||||
autocomplete="off"
|
autocomplete="off"
|
||||||
@keyup="queryResults(query); scrollInputToTop()"
|
@keyup="queryResults(query); scrollInputToTop()"
|
||||||
>
|
>
|
||||||
|
|
@ -222,6 +222,10 @@ export default {
|
||||||
type: Number,
|
type: Number,
|
||||||
default: null
|
default: null
|
||||||
},
|
},
|
||||||
|
autofocus: {
|
||||||
|
type: Boolean,
|
||||||
|
default: true
|
||||||
|
},
|
||||||
quickButtons: {
|
quickButtons: {
|
||||||
type: Array,
|
type: Array,
|
||||||
default: () => [
|
default: () => [
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,10 @@
|
||||||
// App Data that is derived from other app data
|
// App Data that is derived from other app data
|
||||||
|
|
||||||
|
export function isDevice ( listing ) {
|
||||||
|
if ( !listing.hasOwnProperty('endpoint') ) return false
|
||||||
|
|
||||||
|
return listing.endpoint.startsWith('/device/')
|
||||||
|
}
|
||||||
|
|
||||||
export function isVideo ( app ) {
|
export function isVideo ( app ) {
|
||||||
return app.hasOwnProperty('thumbnail') && app.hasOwnProperty('timestamps')
|
return app.hasOwnProperty('thumbnail') && app.hasOwnProperty('timestamps')
|
||||||
|
|
@ -13,6 +18,10 @@ export function getAppType ( app ) {
|
||||||
return 'video'
|
return 'video'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ( isDevice( app ) ) {
|
||||||
|
return 'device'
|
||||||
|
}
|
||||||
|
|
||||||
if(app.category !== Object(app.category)) {
|
if(app.category !== Object(app.category)) {
|
||||||
console.warn('app has no categories', app)
|
console.warn('app has no categories', app)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,6 @@
|
||||||
|
|
||||||
import { promises as fs } from 'fs'
|
import { promises as fs } from 'fs'
|
||||||
import MarkdownIt from 'markdown-it'
|
import MarkdownIt from 'markdown-it'
|
||||||
import slugify from 'slugify'
|
|
||||||
import axios from 'axios'
|
import axios from 'axios'
|
||||||
|
|
||||||
import statuses, { getStatusName } from './statuses'
|
import statuses, { getStatusName } from './statuses'
|
||||||
|
|
@ -9,17 +8,11 @@ import appStoreGenres from './app-store/genres.js'
|
||||||
import parseDate from './parse-date'
|
import parseDate from './parse-date'
|
||||||
import { eitherMatches } from './matching.js'
|
import { eitherMatches } from './matching.js'
|
||||||
import { getAppEndpoint } from './app-derived'
|
import { getAppEndpoint } from './app-derived'
|
||||||
|
import { makeSlug } from './slug.js'
|
||||||
|
|
||||||
|
|
||||||
const md = new MarkdownIt()
|
const md = new MarkdownIt()
|
||||||
|
|
||||||
|
|
||||||
const makeSlug = name => slugify(name, {
|
|
||||||
lower: true,
|
|
||||||
strict: true
|
|
||||||
})
|
|
||||||
|
|
||||||
|
|
||||||
const getTokenLinks = function ( childTokens ) {
|
const getTokenLinks = function ( childTokens ) {
|
||||||
|
|
||||||
const tokenList = []
|
const tokenList = []
|
||||||
|
|
@ -264,10 +257,7 @@ export default async function () {
|
||||||
|
|
||||||
if (isHeading && token.type === 'inline') {
|
if (isHeading && token.type === 'inline') {
|
||||||
categoryTitle = token.content
|
categoryTitle = token.content
|
||||||
categorySlug = slugify(token.content, {
|
categorySlug = makeSlug( token.content )
|
||||||
lower: true,
|
|
||||||
strict: true
|
|
||||||
})
|
|
||||||
|
|
||||||
// appList[categorySlug] = []
|
// appList[categorySlug] = []
|
||||||
}
|
}
|
||||||
|
|
|
||||||
33
helpers/build-device-list.js
Normal file
33
helpers/build-device-list.js
Normal file
|
|
@ -0,0 +1,33 @@
|
||||||
|
import axios from 'axios'
|
||||||
|
|
||||||
|
import { makeSlug } from './slug.js'
|
||||||
|
|
||||||
|
export function getDeviceEndpoint ( slug ) {
|
||||||
|
return `/device/${ slug }`
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
export default async function () {
|
||||||
|
|
||||||
|
const devicesJsonUrl = `${process.env.VFUNCTIONS_URL}/api/devices`
|
||||||
|
|
||||||
|
const rawDeviceList = await axios.get(devicesJsonUrl)
|
||||||
|
.then( response => {
|
||||||
|
return response.data
|
||||||
|
})
|
||||||
|
.catch(function (error) {
|
||||||
|
// handle error
|
||||||
|
console.warn('Error fetching device list', error)
|
||||||
|
})
|
||||||
|
|
||||||
|
return rawDeviceList.filter( device => ( device.type !== 'ios' ) ).map( device => {
|
||||||
|
const slug = makeSlug( device.name )
|
||||||
|
|
||||||
|
return {
|
||||||
|
...device,
|
||||||
|
slug,
|
||||||
|
endpoint: getDeviceEndpoint( slug ),
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
@ -1,10 +1,8 @@
|
||||||
|
|
||||||
import { promises as fs } from 'fs'
|
|
||||||
import slugify from 'slugify'
|
|
||||||
import axios from 'axios'
|
import axios from 'axios'
|
||||||
|
|
||||||
// import { statuses } from './build-app-list'
|
// import { statuses } from './build-app-list'
|
||||||
import { getAppEndpoint } from './app-derived'
|
import { getAppEndpoint } from './app-derived'
|
||||||
|
import { makeSlug } from './slug.js'
|
||||||
|
|
||||||
|
|
||||||
// console.log('process.env.GAMES_SOURCE', process.env.GAMES_SOURCE)
|
// console.log('process.env.GAMES_SOURCE', process.env.GAMES_SOURCE)
|
||||||
|
|
@ -101,10 +99,7 @@ export default async function () {
|
||||||
if (isPlayable(game) && statusesTranslations.hasOwnProperty(environmentName(game)) === false) continue
|
if (isPlayable(game) && statusesTranslations.hasOwnProperty(environmentName(game)) === false) continue
|
||||||
|
|
||||||
// Generate slug
|
// Generate slug
|
||||||
const slug = slugify(game.Games, {
|
const slug = makeSlug( game.Games )
|
||||||
lower: true,
|
|
||||||
strict: true
|
|
||||||
})
|
|
||||||
|
|
||||||
// Find index of game is list so far
|
// Find index of game is list so far
|
||||||
const gameIndex = gameList.findIndex(game => {
|
const gameIndex = gameList.findIndex(game => {
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,11 @@
|
||||||
|
|
||||||
import slugify from 'slugify'
|
|
||||||
import axios from 'axios'
|
import axios from 'axios'
|
||||||
|
|
||||||
import { fuzzyMatchesWholeWord } from './matching.js'
|
import { fuzzyMatchesWholeWord } from './matching.js'
|
||||||
import { byTimeThenNull } from './sort-list.js'
|
import { byTimeThenNull } from './sort-list.js'
|
||||||
import { getVideoEndpoint } from './app-derived.js'
|
import { getVideoEndpoint } from './app-derived.js'
|
||||||
import parseDate from './parse-date'
|
import parseDate from './parse-date'
|
||||||
|
import { makeSlug } from './slug.js'
|
||||||
|
|
||||||
|
|
||||||
const inTimestamps = ( name, video ) => {
|
const inTimestamps = ( name, video ) => {
|
||||||
|
|
@ -150,10 +150,7 @@ export default async function ( applist ) {
|
||||||
if (fetchedVideos[videoId].title === 'Deleted video') continue
|
if (fetchedVideos[videoId].title === 'Deleted video') continue
|
||||||
|
|
||||||
// Build video slug
|
// Build video slug
|
||||||
const slug = slugify(`${fetchedVideos[videoId].title}-i-${videoId}`, {
|
const slug = makeSlug( `${fetchedVideos[videoId].title}-i-${videoId}` )
|
||||||
lower: true,
|
|
||||||
strict: true
|
|
||||||
})
|
|
||||||
|
|
||||||
const apps = []
|
const apps = []
|
||||||
// Generate new tag set based on api data
|
// Generate new tag set based on api data
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,8 @@
|
||||||
// Universal JS imports only
|
// Universal JS imports only
|
||||||
import slugify from 'slugify'
|
import { makeSlug } from './slug.js'
|
||||||
|
|
||||||
|
|
||||||
export function makeCategorySlug ( categoryName ) {
|
export function makeCategorySlug ( categoryName ) {
|
||||||
return slugify(categoryName, {
|
return makeSlug( categoryName )
|
||||||
lower: true,
|
|
||||||
strict: true
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
37
helpers/devices.js
Normal file
37
helpers/devices.js
Normal file
|
|
@ -0,0 +1,37 @@
|
||||||
|
|
||||||
|
import { getStatusName } from './statuses.js'
|
||||||
|
|
||||||
|
|
||||||
|
export const macAppleSiliconStatuses = new Set([
|
||||||
|
'native',
|
||||||
|
'rosetta'
|
||||||
|
])
|
||||||
|
|
||||||
|
export function deviceSupportsApp ( device, app ) {
|
||||||
|
|
||||||
|
// const statuses = {
|
||||||
|
// '✅': 'native',
|
||||||
|
// '✳️': 'rosetta',
|
||||||
|
// '⏹': 'no-in-progress',
|
||||||
|
// '🚫': 'no',
|
||||||
|
// '🔶': 'unreported',
|
||||||
|
// }
|
||||||
|
const appStatus = getStatusName( app.text )
|
||||||
|
|
||||||
|
if ( device.type === 'intel') {
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( device.type === 'mac-apple-silicon') {
|
||||||
|
|
||||||
|
return macAppleSiliconStatuses.has( appStatus )
|
||||||
|
}
|
||||||
|
|
||||||
|
// if ( device.type === 'ios') {
|
||||||
|
|
||||||
|
// return
|
||||||
|
// }
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
9
helpers/slug.js
Normal file
9
helpers/slug.js
Normal file
|
|
@ -0,0 +1,9 @@
|
||||||
|
// Universal JS imports only
|
||||||
|
import slugify from 'slugify'
|
||||||
|
|
||||||
|
export function makeSlug ( name ) {
|
||||||
|
return slugify(name, {
|
||||||
|
lower: true,
|
||||||
|
strict: true
|
||||||
|
})
|
||||||
|
}
|
||||||
11
package-lock.json
generated
11
package-lock.json
generated
|
|
@ -13,6 +13,7 @@
|
||||||
"@open-wc/webpack-import-meta-loader": "^0.4.7",
|
"@open-wc/webpack-import-meta-loader": "^0.4.7",
|
||||||
"@zip.js/zip.js": "^2.2.6",
|
"@zip.js/zip.js": "^2.2.6",
|
||||||
"axios": "^0.21.0",
|
"axios": "^0.21.0",
|
||||||
|
"chance": "^1.1.7",
|
||||||
"cross-env": "^5.2.0",
|
"cross-env": "^5.2.0",
|
||||||
"jsdom": "^16.4.0",
|
"jsdom": "^16.4.0",
|
||||||
"lazysizes": "^5.3.0-beta1",
|
"lazysizes": "^5.3.0-beta1",
|
||||||
|
|
@ -4842,6 +4843,11 @@
|
||||||
"node": ">=8"
|
"node": ">=8"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/chance": {
|
||||||
|
"version": "1.1.7",
|
||||||
|
"resolved": "https://registry.npmjs.org/chance/-/chance-1.1.7.tgz",
|
||||||
|
"integrity": "sha512-bua/2cZEfzS6qPm0vi3JEvGNbriDLcMj9lKxCQOjUcCJRcyjA7umP0zZm6bKWWlBN04vA0L99QGH/CZQawr0eg=="
|
||||||
|
},
|
||||||
"node_modules/character-parser": {
|
"node_modules/character-parser": {
|
||||||
"version": "2.2.0",
|
"version": "2.2.0",
|
||||||
"resolved": "https://registry.npmjs.org/character-parser/-/character-parser-2.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/character-parser/-/character-parser-2.2.0.tgz",
|
||||||
|
|
@ -29210,6 +29216,11 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"chance": {
|
||||||
|
"version": "1.1.7",
|
||||||
|
"resolved": "https://registry.npmjs.org/chance/-/chance-1.1.7.tgz",
|
||||||
|
"integrity": "sha512-bua/2cZEfzS6qPm0vi3JEvGNbriDLcMj9lKxCQOjUcCJRcyjA7umP0zZm6bKWWlBN04vA0L99QGH/CZQawr0eg=="
|
||||||
|
},
|
||||||
"character-parser": {
|
"character-parser": {
|
||||||
"version": "2.2.0",
|
"version": "2.2.0",
|
||||||
"resolved": "https://registry.npmjs.org/character-parser/-/character-parser-2.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/character-parser/-/character-parser-2.2.0.tgz",
|
||||||
|
|
|
||||||
|
|
@ -26,6 +26,7 @@
|
||||||
"@open-wc/webpack-import-meta-loader": "^0.4.7",
|
"@open-wc/webpack-import-meta-loader": "^0.4.7",
|
||||||
"@zip.js/zip.js": "^2.2.6",
|
"@zip.js/zip.js": "^2.2.6",
|
||||||
"axios": "^0.21.0",
|
"axios": "^0.21.0",
|
||||||
|
"chance": "^1.1.7",
|
||||||
"cross-env": "^5.2.0",
|
"cross-env": "^5.2.0",
|
||||||
"jsdom": "^16.4.0",
|
"jsdom": "^16.4.0",
|
||||||
"lazysizes": "^5.3.0-beta1",
|
"lazysizes": "^5.3.0-beta1",
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@ import dotenv from 'dotenv'
|
||||||
import config from '../nuxt.config.js'
|
import config from '../nuxt.config.js'
|
||||||
|
|
||||||
import { getAppType } from '../helpers/app-derived.js'
|
import { getAppType } from '../helpers/app-derived.js'
|
||||||
|
import { deviceSupportsApp } from '../helpers/devices.js'
|
||||||
import { makeLastUpdatedFriendly } from '../helpers/parse-date'
|
import { makeLastUpdatedFriendly } from '../helpers/parse-date'
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -84,10 +85,24 @@ export class AppTemplate {
|
||||||
|
|
||||||
render( data ) {
|
render( data ) {
|
||||||
|
|
||||||
const { app: { payload: { app, relatedVideos = [] } } } = data
|
const {
|
||||||
|
app: { payload: { app, relatedVideos = [] } },
|
||||||
|
'device-list': deviceList
|
||||||
|
} = data
|
||||||
|
|
||||||
|
// console.log('deviceList', deviceList)
|
||||||
|
|
||||||
// console.log('video.payload', Object.keys(video.payload))
|
// console.log('video.payload', Object.keys(video.payload))
|
||||||
|
|
||||||
|
const appDeviceSupport = deviceList.map( device => {
|
||||||
|
const supportsApp = deviceSupportsApp( device, app )
|
||||||
|
return {
|
||||||
|
...device,
|
||||||
|
emoji: supportsApp ? '✅' : '🚫',
|
||||||
|
ariaLabel: `${app.name} has ${ supportsApp ? '' : 'not' } been reported to work on ${device.name}`
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
const lastUpdatedFriendly = makeLastUpdatedFriendly( app.lastUpdated )
|
const lastUpdatedFriendly = makeLastUpdatedFriendly( app.lastUpdated )
|
||||||
|
|
||||||
const relatedLinksHtml = renderPageLinksHtml( app.relatedLinks )
|
const relatedLinksHtml = renderPageLinksHtml( app.relatedLinks )
|
||||||
|
|
@ -109,6 +124,24 @@ export class AppTemplate {
|
||||||
<div class="links space-y-6 sm:space-x-6 mb-8">
|
<div class="links space-y-6 sm:space-x-6 mb-8">
|
||||||
${ relatedLinksHtml }
|
${ relatedLinksHtml }
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="device-support w-full">
|
||||||
|
<h2 class="subtitle text-xl md:text-2xl font-bold mb-3">
|
||||||
|
Device Support
|
||||||
|
</h2>
|
||||||
|
<div class="device-support-apps overflow-x-auto overflow-y-visible md:whitespace-no-wrap py-2 space-x-2 space-y-3">
|
||||||
|
|
||||||
|
${ appDeviceSupport.map( device => /* html */`
|
||||||
|
<a
|
||||||
|
href="${ device.endpoint }"
|
||||||
|
role="button"
|
||||||
|
class="relative inline-flex items-center leading-5 font-bold text-white border border-transparent focus:outline-none focus:border-indigo-600 neumorphic-shadow-inner bg-darker hover:bg-indigo-400 active:bg-indigo-600 transition duration-150 ease-in-out text-xs rounded-lg px-4 py-2"
|
||||||
|
aria-label="${ device.ariaLabel }"
|
||||||
|
>${ device.emoji } ${ device.name }</a>
|
||||||
|
`).join('') }
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
${ relatedVideos.length > 0 ? /* html */`
|
${ relatedVideos.length > 0 ? /* html */`
|
||||||
|
|
|
||||||
211
pages/device/_slug.vue
Normal file
211
pages/device/_slug.vue
Normal file
|
|
@ -0,0 +1,211 @@
|
||||||
|
<template>
|
||||||
|
<section class="container py-24">
|
||||||
|
<div class="flex flex-col items-center">
|
||||||
|
<h1 class="title text-3xl md:text-5xl font-hairline leading-tight text-center pb-4">
|
||||||
|
{{ device.name }}
|
||||||
|
</h1>
|
||||||
|
|
||||||
|
<div class="summary space-y-4 max-w-2xl">
|
||||||
|
<div class="flex justify-center py-3">
|
||||||
|
<LinkButton
|
||||||
|
v-if="device.amazonUrl"
|
||||||
|
:href="device.amazonUrl"
|
||||||
|
target="_blank"
|
||||||
|
>
|
||||||
|
Check Pricing
|
||||||
|
</LinkButton>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<h2
|
||||||
|
class="subtitle md:text-lg text-center"
|
||||||
|
>
|
||||||
|
App support for {{ device.name }}
|
||||||
|
</h2>
|
||||||
|
|
||||||
|
<h2
|
||||||
|
v-if="supportedAppList.length !== 0"
|
||||||
|
class="subtitle md:text-lg text-center"
|
||||||
|
>
|
||||||
|
Supported apps include {{ supportedAppList.join(', ') }}.
|
||||||
|
</h2>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<Search
|
||||||
|
:app-list="deviceAppList"
|
||||||
|
:quick-buttons="quickButtons"
|
||||||
|
:autofocus="false"
|
||||||
|
:initial-limit="50"
|
||||||
|
@update:query="query = $event"
|
||||||
|
>
|
||||||
|
<template v-slot:before-search>
|
||||||
|
<div class="empty-div" />
|
||||||
|
</template>
|
||||||
|
</Search>
|
||||||
|
|
||||||
|
|
||||||
|
<div class="flex flex-col md:flex-row space-x-0 space-y-4 md:space-y-0 md:space-x-4">
|
||||||
|
|
||||||
|
<LinkButton
|
||||||
|
:href="`https://github.com/ThatGuySam/doesitarm/issues?q=is%3Aissue+${query}`"
|
||||||
|
class="text-xs"
|
||||||
|
>
|
||||||
|
Request an App with Github
|
||||||
|
</LinkButton>
|
||||||
|
|
||||||
|
<LinkButton
|
||||||
|
:href="`https://twitter.com/DoesItARM/status/1330027384041508865`"
|
||||||
|
class="text-xs"
|
||||||
|
>
|
||||||
|
Request an App with Twitter
|
||||||
|
</LinkButton>
|
||||||
|
|
||||||
|
<LinkButton
|
||||||
|
:href="`/apple-silicon-app-test/`"
|
||||||
|
class="text-xs"
|
||||||
|
>
|
||||||
|
Scan Your Own App
|
||||||
|
</LinkButton>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import Search from '~/components/search.vue'
|
||||||
|
import LinkButton from '~/components/link-button.vue'
|
||||||
|
|
||||||
|
// import { categories } from '~/helpers/categories.js'
|
||||||
|
import { deviceSupportsApp } from '~/helpers/devices.js'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
async asyncData ({ params: { slug } }) {
|
||||||
|
const { default: Chance } = await import('chance')
|
||||||
|
|
||||||
|
const { allList } = await import('~/helpers/get-list.js')
|
||||||
|
const { default: deviceList } = await import('~/static/device-list.json')
|
||||||
|
|
||||||
|
|
||||||
|
const charCode = slug.charCodeAt( slug.length-2 )
|
||||||
|
const shuffler = new Chance( charCode )
|
||||||
|
|
||||||
|
const device = deviceList.find( device => {
|
||||||
|
return device.slug === slug
|
||||||
|
})
|
||||||
|
|
||||||
|
// console.log( 'device', device )
|
||||||
|
|
||||||
|
const deviceAppList = allList.map( app => {
|
||||||
|
const appIsSupported = deviceSupportsApp( device, app )
|
||||||
|
|
||||||
|
return {
|
||||||
|
name: app.name,
|
||||||
|
status: app.status,
|
||||||
|
slug: app.slug,
|
||||||
|
// endpoint: app.endpoint,
|
||||||
|
text: appIsSupported ? `✅ Supported on ${device.name}` : `🚫 Not yet reported working on ${device.name}`,
|
||||||
|
lastUpdated: app.lastUpdated,
|
||||||
|
category: app.category,
|
||||||
|
// searchLinks: makeAppSearchLinks( app, (new Set(videoList)) )
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const supportedApps = deviceAppList.filter( app => {
|
||||||
|
const supported = app.text.startsWith('✅')
|
||||||
|
const hasNotAllowedCategory = ([
|
||||||
|
'no-category',
|
||||||
|
'homebrew',
|
||||||
|
'games',
|
||||||
|
]).some( categorySlug => (app.category.slug === categorySlug) )
|
||||||
|
|
||||||
|
// console.log('hasNonStandardCategory', app.category.slug, hasNonStandardCategory)
|
||||||
|
|
||||||
|
return supported && !hasNotAllowedCategory
|
||||||
|
})
|
||||||
|
|
||||||
|
const featuredApps = shuffler.shuffle( supportedApps ).slice(0, 12)
|
||||||
|
|
||||||
|
// console.log('featuredApps', featuredApps[0])
|
||||||
|
|
||||||
|
return {
|
||||||
|
slug,
|
||||||
|
device,
|
||||||
|
featuredApps,
|
||||||
|
deviceAppList
|
||||||
|
}
|
||||||
|
},
|
||||||
|
components: {
|
||||||
|
Search,
|
||||||
|
LinkButton
|
||||||
|
},
|
||||||
|
data: function () {
|
||||||
|
return {
|
||||||
|
query: '',
|
||||||
|
quickButtons: []
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
supportedAppList () {
|
||||||
|
return this.featuredApps.map(app => app.name)
|
||||||
|
},
|
||||||
|
title () {
|
||||||
|
return `App support list for ${this.device.name}`
|
||||||
|
},
|
||||||
|
description () {
|
||||||
|
return `Check the the latest reported support status of apps and software on ${this.device.name}.`
|
||||||
|
},
|
||||||
|
structuredData () {
|
||||||
|
return {
|
||||||
|
"@context": "https://schema.org",
|
||||||
|
// https://developers.google.com/search/docs/data-types/faqpage
|
||||||
|
// https://schema.org/FAQPage
|
||||||
|
"@type": "FAQPage",
|
||||||
|
"mainEntity": this.deviceAppList.map( app => {
|
||||||
|
return {
|
||||||
|
// https://schema.org/Question
|
||||||
|
"@type": "Question",
|
||||||
|
"name": `Does ${app.name} work on ${ this.device.name }?`,
|
||||||
|
"acceptedAnswer": {
|
||||||
|
// https://schema.org/Answer
|
||||||
|
"@type": "Answer",
|
||||||
|
"text": app.text
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
head() {
|
||||||
|
return {
|
||||||
|
title: this.title,
|
||||||
|
meta: [
|
||||||
|
// hid is used as unique identifier. Do not use `vmid` for it as it will not work
|
||||||
|
{
|
||||||
|
'hid': 'description',
|
||||||
|
'name': 'description',
|
||||||
|
'content': this.description
|
||||||
|
},
|
||||||
|
|
||||||
|
// Twitter Card
|
||||||
|
{
|
||||||
|
'hid': 'twitter:title',
|
||||||
|
'property': 'twitter:title',
|
||||||
|
'content': this.title
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'hid': 'twitter:description',
|
||||||
|
'property': 'twitter:description',
|
||||||
|
'content': this.description
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'property': 'twitter:url',
|
||||||
|
'content': `${process.env.URL}${this.$nuxt.$route.path}`
|
||||||
|
},
|
||||||
|
],
|
||||||
|
__dangerouslyDisableSanitizers: ['script'],
|
||||||
|
script: [{ innerHTML: JSON.stringify(this.structuredData), type: 'application/ld+json' }]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
76
pages/devices.vue
Normal file
76
pages/devices.vue
Normal file
|
|
@ -0,0 +1,76 @@
|
||||||
|
<template>
|
||||||
|
<section class="container py-24">
|
||||||
|
<div class="flex flex-col">
|
||||||
|
<h1 class="title text-2xl leading-tight mb-6">
|
||||||
|
Devices
|
||||||
|
</h1>
|
||||||
|
|
||||||
|
<div class="line-separator border-white border-t-2 mb-12" />
|
||||||
|
|
||||||
|
<!-- deviceList: {{ deviceList }} -->
|
||||||
|
|
||||||
|
<ul class="device-list space-y-3">
|
||||||
|
<li
|
||||||
|
v-for="(device, i) in deviceList"
|
||||||
|
:key="`${device.slug}-${i}`"
|
||||||
|
:ref="`${device.slug}-row`"
|
||||||
|
class="relative"
|
||||||
|
>
|
||||||
|
<!-- device.endpoint: {{ device.endpoint }} -->
|
||||||
|
<a
|
||||||
|
:href="device.endpoint"
|
||||||
|
class="flex justify-start items-center inset-x-0 text-3xl md:text-4xl hover:bg-darkest border-2 border-white border-opacity-0 hover:border-opacity-50 focus:outline-none focus:bg-gray-50 duration-300 ease-in-out rounded-lg space-x-3 -mx-5 px-5 md:pr-64 py-3"
|
||||||
|
style="transition-property: border;"
|
||||||
|
>
|
||||||
|
<div class="font-hairline">
|
||||||
|
<div>{{ device.name }}</div>
|
||||||
|
<!-- <div class="text-xs opacity-75 mb-3">{{ device.appNames }}</div> -->
|
||||||
|
</div>
|
||||||
|
<div>➔</div>
|
||||||
|
</a>
|
||||||
|
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import LinkButton from '~/components/link-button.vue'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
async asyncData () {
|
||||||
|
const { default: deviceList } = await import('~/static/device-list.json')
|
||||||
|
|
||||||
|
return {
|
||||||
|
deviceList
|
||||||
|
}
|
||||||
|
|
||||||
|
},
|
||||||
|
components: {
|
||||||
|
LinkButton
|
||||||
|
},
|
||||||
|
data: function () {
|
||||||
|
return {}
|
||||||
|
},
|
||||||
|
// computed: {
|
||||||
|
// deviceList () {
|
||||||
|
// return deviceList
|
||||||
|
// }
|
||||||
|
// },
|
||||||
|
head() {
|
||||||
|
return {
|
||||||
|
title: `Categories of App Support for Apple Silicon - Does It ARM`,
|
||||||
|
// 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>
|
||||||
Loading…
Add table
Add a link
Reference in a new issue