Skip to content

Commit

Permalink
Merge pull request #870 from dpc-sdp/feat/r20-994-favicon-generator
Browse files Browse the repository at this point in the history
[R20-994] Generate favicon assets
  • Loading branch information
dylankelly authored Oct 2, 2023
2 parents e33ddd4 + ca631da commit 9db150a
Show file tree
Hide file tree
Showing 6 changed files with 306 additions and 7 deletions.
18 changes: 14 additions & 4 deletions packages/nuxt-ripple/app.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,20 +6,30 @@ declare module '@nuxt/schema' {
featureFlags?: IRplFeatureFlags
theme?: {
['rpl-clr-primary']?: string
['rpl-clr-primary-alpha']?: string
['rpl-clr-footer']?: string
['rpl-clr-footer-alt']?: string
['rpl-clr-primary-alt']?: string
['rpl-clr-type-primary-accessible']?: string
['rpl-clr-type-primary-alt-accessible']?: string
['rpl-clr-type-footer-accessible']?: string
['rpl-clr-accent']?: string
['rpl-clr-accent-alt']?: string
['rpl-clr-link']?: string
['rpl-clr-focus']?: string
['rpl-clr-type-focus-contrast']?: string
['rpl-clr-gradient-horizontal']?: string
['rpl-clr-gradient-vertical']?: string
}
languages?: {
name?: string
url?: string
rtl?: boolean
[key: string]: {
name: string
url: string
rtl?: boolean
}
}
search?: {
contentTypes: string[]
contentTypes?: string[]
fallbackValues?: Record<
string,
(filterConfig: any, values: string[]) => void
Expand Down
91 changes: 91 additions & 0 deletions packages/nuxt-ripple/lib/generate.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
import { init as initRfgApi } from 'rfg-api'
import fs from 'fs'
import path from 'path'

const { generateFavicon, createRequest } = initRfgApi()

export interface generateOpts {
masterPath: string
outputPath: string
API_KEY: string
themeColour: string
siteName: string
}

export async function generate(opt: generateOpts): Promise<object | null> {
console.info('Favicon: generating assets')

const iosConfig = {
pictureAspect: 'noChange'
}

const safariConfig = {
pictureAspect: 'black_and_white',
backgroundColor: '#ffffff',
threshold: 60
}

const androidConfig = {
pictureAspect: 'noChange',
manifest: {
name: opt.siteName,
display: 'standalone',
orientation: 'portrait',
start_url: '/'
},
assets: {
legacyIcon: false,
lowResolutionIcons: false
},
theme_color: opt.themeColour
}

const windowsConfig = {
pictureAspect: 'white_silhouette',
backgroundColor: opt.themeColour,
assets: {
windows80Ie10Tile: true,
windows10Ie11EdgeTiles: {
small: true,
medium: true,
big: true,
rectangle: true
}
}
}

const faviconDesign = {
desktopBrowser: {},
ios: iosConfig,
androidChrome: androidConfig,
safariPinnedTab: safariConfig,
windows: windowsConfig
}

return generateFavicon(
createRequest({
apiKey: opt.API_KEY,
masterPicture: opt.masterPath,
iconsPath: opt.outputPath,
design: faviconDesign,
settings: { usePathAsIs: false }
// versioning?
}),
path.resolve(process.cwd(), opt.outputPath || '.'),
async (err: any) => {
if (err) {
throw err
}

// Remove outputPath from manifest files
for (const manifest of ['browserconfig.xml', 'site.webmanifest']) {
const path = `${opt.outputPath}/${manifest}`,
original = await fs.promises.readFile(path, 'utf8'),
updated = original.replace(new RegExp(opt.outputPath, 'g'), '')
await fs.promises.writeFile(path, updated, 'utf8')
}

console.info('Favicon: generate complete!')
}
)
}
2 changes: 2 additions & 0 deletions packages/nuxt-ripple/lib/lib.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
declare module 'rfg-api'
declare module 'jsonapi-parse'
91 changes: 91 additions & 0 deletions packages/nuxt-ripple/modules/generate-favicon.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
import { createResolver, defineNuxtModule } from 'nuxt/kit'
import { generate } from './../lib/generate'
import * as jsonapiParse from 'jsonapi-parse'
import fs from 'fs'
import path from 'path'
import { Readable } from 'stream'
import { finished } from 'stream/promises'

export default defineNuxtModule({
meta: {
name: 'generateFavicon'
},
hooks: {
ready: async (nuxtApp) => {
const faviconApiKey = process.env.RFG_API_KEY

// Exit early if API key is not set
if (faviconApiKey === undefined) {
console.info('Favicon: missing RFG_API_KEY, skipping')
return
}

const publicFolderPath = nuxtApp.options.alias.public

// 1. Check if asset already exists
if (fs.existsSync(`${publicFolderPath}/favicon.ico`)) {
console.info('Favicon: Assets already exist, skipping')
return
}

// 2. Fetch theme and master asset url from site taxonomy
const siteTaxonomyRes = await fetch(
`${nuxtApp.options.runtimeConfig.public.tide.baseUrl}/api/v1/taxonomy_term/sites?filter%5Bdrupal_internal__tid%5D=${nuxtApp.options.runtimeConfig.public.tide.site}&site=${nuxtApp.options.runtimeConfig.public.tide.site}&include=field_site_favicon`
),
siteTaxonomyData = await siteTaxonomyRes.json(),
parsedData = jsonapiParse.parse(siteTaxonomyData).data[0]

// 3. Extract site name
const siteName =
parsedData.field_site_slogan.processed.replace(/<p>|<\/p>/g, '') ||
parsedData.name ||
'SDP'

// 4. Extract theme colour (use Vic primary if theme is not set)
const themeColour =
parsedData.field_site_theme_values?.filter(
(t: any) => t.key.trim() === 'rpl-clr-primary'
)[0]?.value || '#0052C2'

// 5. Set up master asset in public
const masterAssetUrl = parsedData.field_site_favicon?.url
if (!masterAssetUrl) {
console.info('Favicon: Master asset not set in site taxonomy, skipping')
return
}

// 6. Create public folder if it doesn't exist at the app level
if (!fs.existsSync(publicFolderPath)) {
await fs.promises.mkdir(publicFolderPath)
}

// 7. Fetch master asset
const savedFaviconPath = `${publicFolderPath}/${path.basename(
masterAssetUrl
)}`

if (!fs.existsSync(savedFaviconPath)) {
const masterAssetRes = await fetch(masterAssetUrl),
fileStream = fs.createWriteStream(savedFaviconPath, { flags: 'wx' })
// @ts-ignore TS2345
await finished(Readable.fromWeb(masterAssetRes.body).pipe(fileStream))
}

// 8. Generate assets
await generate({
masterPath: savedFaviconPath,
outputPath: publicFolderPath,
API_KEY: faviconApiKey,
themeColour: themeColour,
siteName: siteName
}).then(() => {
// 9. Remove master asset
fs.unlinkSync(savedFaviconPath)
})
}
},
setup() {
const { resolve } = createResolver(import.meta.url)

Check warning on line 88 in packages/nuxt-ripple/modules/generate-favicon.ts

View workflow job for this annotation

GitHub Actions / Test

'resolve' is assigned a value but never used. Allowed unused vars must match /props/u

Check warning on line 88 in packages/nuxt-ripple/modules/generate-favicon.ts

View workflow job for this annotation

GitHub Actions / Test

'resolve' is assigned a value but never used. Allowed unused vars must match /props/u
// console.log(resolve('./../lib/generate'))
}
})
4 changes: 3 additions & 1 deletion packages/nuxt-ripple/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@
"@nuxtjs/robots": "^3.0.0",
"@vueuse/core": "^9.13.0",
"change-case": "^4.1.2",
"defu": "^6.1.2"
"defu": "^6.1.2",
"jsonapi-parse": "^2.0.1",
"rfg-api": "^0.5.3"
}
}
Loading

0 comments on commit 9db150a

Please sign in to comment.