diff --git a/build-lists.js b/build-lists.js index cceacf9..f3daa2e 100644 --- a/build-lists.js +++ b/build-lists.js @@ -5,6 +5,7 @@ import buildAppList from './helpers/build-app-list.js' import buildGamesList from './helpers/build-game-list.js' import buildHomebrewList from './helpers/build-homebrew-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 { buildVideoPayload, buildAppBenchmarkPayload } from './helpers/build-payload.js' @@ -14,6 +15,7 @@ import { getAppType, getAppEndpoint, getVideoEndpoint, + isVideo } from './helpers/app-derived.js' import { makeSearchableList } from './helpers/searchable-list.js' @@ -61,6 +63,11 @@ class BuildLists { path: '/static/homebrew-list.json', buildMethod: buildHomebrewList, }, + { + name: 'device', + path: '/static/device-list.json', + buildMethod: buildDeviceList, + }, // Secondary Derivative built lists // Always goes after initial lists @@ -225,10 +232,10 @@ class BuildLists { this.lists[listKey].forEach( app => { - const isVideo = (app.category === undefined) + // const isVideo = (app.category === undefined) const appType = getAppType( app ) - if ( isVideo ) { + if ( isVideo( app ) ) { // this.endpointMaps.eleventy.add({ // route: getVideoEndpoint(app), // payload: buildVideoPayload( app, this.allVideoAppsList, this.lists.video ) @@ -273,9 +280,14 @@ class BuildLists { 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 { // 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 } ) } diff --git a/components/navbar.vue b/components/navbar.vue index 5ec6bba..ef68570 100644 --- a/components/navbar.vue +++ b/components/navbar.vue @@ -147,6 +147,10 @@ export default { label: 'Categories', url: '/categories', }, + { + label: 'Devices', + url: '/devices', + }, { label: 'Benchmarks', url: '/benchmarks', diff --git a/components/search.vue b/components/search.vue index bf56db3..c2c3fb1 100644 --- a/components/search.vue +++ b/components/search.vue @@ -16,12 +16,12 @@ @@ -222,6 +222,10 @@ export default { type: Number, default: null }, + autofocus: { + type: Boolean, + default: true + }, quickButtons: { type: Array, default: () => [ diff --git a/helpers/app-derived.js b/helpers/app-derived.js index 8ed7ec0..da98483 100644 --- a/helpers/app-derived.js +++ b/helpers/app-derived.js @@ -1,5 +1,10 @@ // 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 ) { return app.hasOwnProperty('thumbnail') && app.hasOwnProperty('timestamps') @@ -13,6 +18,10 @@ export function getAppType ( app ) { return 'video' } + if ( isDevice( app ) ) { + return 'device' + } + if(app.category !== Object(app.category)) { console.warn('app has no categories', app) diff --git a/helpers/build-app-list.js b/helpers/build-app-list.js index 2a4906b..2afdd0a 100644 --- a/helpers/build-app-list.js +++ b/helpers/build-app-list.js @@ -1,7 +1,6 @@ import { promises as fs } from 'fs' import MarkdownIt from 'markdown-it' -import slugify from 'slugify' import axios from 'axios' import statuses, { getStatusName } from './statuses' @@ -9,17 +8,11 @@ import appStoreGenres from './app-store/genres.js' import parseDate from './parse-date' import { eitherMatches } from './matching.js' import { getAppEndpoint } from './app-derived' +import { makeSlug } from './slug.js' const md = new MarkdownIt() - -const makeSlug = name => slugify(name, { - lower: true, - strict: true -}) - - const getTokenLinks = function ( childTokens ) { const tokenList = [] @@ -264,10 +257,7 @@ export default async function () { if (isHeading && token.type === 'inline') { categoryTitle = token.content - categorySlug = slugify(token.content, { - lower: true, - strict: true - }) + categorySlug = makeSlug( token.content ) // appList[categorySlug] = [] } diff --git a/helpers/build-device-list.js b/helpers/build-device-list.js new file mode 100644 index 0000000..0311ffd --- /dev/null +++ b/helpers/build-device-list.js @@ -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 ), + } + }) +} diff --git a/helpers/build-game-list.js b/helpers/build-game-list.js index 0195a7b..0375a9a 100644 --- a/helpers/build-game-list.js +++ b/helpers/build-game-list.js @@ -1,10 +1,8 @@ - -import { promises as fs } from 'fs' -import slugify from 'slugify' import axios from 'axios' // import { statuses } from './build-app-list' import { getAppEndpoint } from './app-derived' +import { makeSlug } from './slug.js' // 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 // Generate slug - const slug = slugify(game.Games, { - lower: true, - strict: true - }) + const slug = makeSlug( game.Games ) // Find index of game is list so far const gameIndex = gameList.findIndex(game => { diff --git a/helpers/build-video-list.js b/helpers/build-video-list.js index 4a32a97..619f9a0 100644 --- a/helpers/build-video-list.js +++ b/helpers/build-video-list.js @@ -1,11 +1,11 @@ -import slugify from 'slugify' import axios from 'axios' import { fuzzyMatchesWholeWord } from './matching.js' import { byTimeThenNull } from './sort-list.js' import { getVideoEndpoint } from './app-derived.js' import parseDate from './parse-date' +import { makeSlug } from './slug.js' const inTimestamps = ( name, video ) => { @@ -150,10 +150,7 @@ export default async function ( applist ) { if (fetchedVideos[videoId].title === 'Deleted video') continue // Build video slug - const slug = slugify(`${fetchedVideos[videoId].title}-i-${videoId}`, { - lower: true, - strict: true - }) + const slug = makeSlug( `${fetchedVideos[videoId].title}-i-${videoId}` ) const apps = [] // Generate new tag set based on api data diff --git a/helpers/categories.js b/helpers/categories.js index 5effd90..914d71a 100644 --- a/helpers/categories.js +++ b/helpers/categories.js @@ -1,12 +1,8 @@ // Universal JS imports only -import slugify from 'slugify' - +import { makeSlug } from './slug.js' export function makeCategorySlug ( categoryName ) { - return slugify(categoryName, { - lower: true, - strict: true - }) + return makeSlug( categoryName ) } diff --git a/helpers/devices.js b/helpers/devices.js new file mode 100644 index 0000000..667d978 --- /dev/null +++ b/helpers/devices.js @@ -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 +} diff --git a/helpers/slug.js b/helpers/slug.js new file mode 100644 index 0000000..9ad21dc --- /dev/null +++ b/helpers/slug.js @@ -0,0 +1,9 @@ +// Universal JS imports only +import slugify from 'slugify' + +export function makeSlug ( name ) { + return slugify(name, { + lower: true, + strict: true + }) +} diff --git a/package-lock.json b/package-lock.json index f88ea3e..3d5f8c4 100644 --- a/package-lock.json +++ b/package-lock.json @@ -13,6 +13,7 @@ "@open-wc/webpack-import-meta-loader": "^0.4.7", "@zip.js/zip.js": "^2.2.6", "axios": "^0.21.0", + "chance": "^1.1.7", "cross-env": "^5.2.0", "jsdom": "^16.4.0", "lazysizes": "^5.3.0-beta1", @@ -4842,6 +4843,11 @@ "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": { "version": "2.2.0", "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": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/character-parser/-/character-parser-2.2.0.tgz", diff --git a/package.json b/package.json index 245fd6e..8e912fd 100644 --- a/package.json +++ b/package.json @@ -26,6 +26,7 @@ "@open-wc/webpack-import-meta-loader": "^0.4.7", "@zip.js/zip.js": "^2.2.6", "axios": "^0.21.0", + "chance": "^1.1.7", "cross-env": "^5.2.0", "jsdom": "^16.4.0", "lazysizes": "^5.3.0-beta1", diff --git a/pages-eleventy/app.11ty.js b/pages-eleventy/app.11ty.js index 9c62842..ee03bf3 100644 --- a/pages-eleventy/app.11ty.js +++ b/pages-eleventy/app.11ty.js @@ -3,6 +3,7 @@ import dotenv from 'dotenv' import config from '../nuxt.config.js' import { getAppType } from '../helpers/app-derived.js' +import { deviceSupportsApp } from '../helpers/devices.js' import { makeLastUpdatedFriendly } from '../helpers/parse-date' @@ -84,10 +85,24 @@ export class AppTemplate { 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)) + 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 relatedLinksHtml = renderPageLinksHtml( app.relatedLinks ) @@ -109,6 +124,24 @@ export class AppTemplate {