From b0d20c958cf8ef1edd4ac3ce28beb9ef63d00bdb Mon Sep 17 00:00:00 2001 From: "(quasar) nebula" Date: Fri, 29 Mar 2024 18:42:54 -0300 Subject: content, external-links: [normal, compact] -> [platform, handle] --- .../dependencies/generateAlbumReleaseInfo.js | 19 +- .../dependencies/generateAlbumSidebarGroupBox.js | 5 +- src/content/dependencies/generateArtistInfoPage.js | 7 +- src/content/dependencies/generateGroupInfoPage.js | 5 +- src/content/dependencies/linkExternal.js | 2 +- src/content/dependencies/linkExternalAsIcon.js | 8 +- src/data/things/language.js | 2 +- src/util/external-links.js | 295 ++++++--------------- 8 files changed, 106 insertions(+), 237 deletions(-) (limited to 'src') diff --git a/src/content/dependencies/generateAlbumReleaseInfo.js b/src/content/dependencies/generateAlbumReleaseInfo.js index 5128fbac..6fc1375b 100644 --- a/src/content/dependencies/generateAlbumReleaseInfo.js +++ b/src/content/dependencies/generateAlbumReleaseInfo.js @@ -96,17 +96,14 @@ export default { language.formatDisjunctionList( relations.externalLinks .map(link => - link.slots({ - context: [ - 'album', - (data.numTracks === 0 - ? 'albumNoTracks' - : data.numTracks === 1 - ? 'albumOneTrack' - : 'albumMultipleTracks'), - ], - style: 'normal', - }))), + link.slot('context', [ + 'album', + (data.numTracks === 0 + ? 'albumNoTracks' + : data.numTracks === 1 + ? 'albumOneTrack' + : 'albumMultipleTracks'), + ]))), })), ]); }, diff --git a/src/content/dependencies/generateAlbumSidebarGroupBox.js b/src/content/dependencies/generateAlbumSidebarGroupBox.js index 5b7e2e45..93ebf5d4 100644 --- a/src/content/dependencies/generateAlbumSidebarGroupBox.js +++ b/src/content/dependencies/generateAlbumSidebarGroupBox.js @@ -89,10 +89,7 @@ export default { links: language.formatDisjunctionList( relations.externalLinks - .map(link => link.slots({ - context: 'group', - style: 'platform', - }))), + .map(link => link.slot('context', 'group'))), })), slots.mode === 'album' && diff --git a/src/content/dependencies/generateArtistInfoPage.js b/src/content/dependencies/generateArtistInfoPage.js index 1b85680f..ac9209a7 100644 --- a/src/content/dependencies/generateArtistInfoPage.js +++ b/src/content/dependencies/generateArtistInfoPage.js @@ -163,11 +163,8 @@ export default { language.$('releaseInfo.visitOn', { links: language.formatDisjunctionList( - sec.visit.externalLinks.map(link => - link.slots({ - context: 'artist', - style: 'platform', - }))), + sec.visit.externalLinks + .map(link => link.slot('context', 'artist'))), })), sec.artworks?.artistGalleryLink && diff --git a/src/content/dependencies/generateGroupInfoPage.js b/src/content/dependencies/generateGroupInfoPage.js index 5cae730b..2e1d1688 100644 --- a/src/content/dependencies/generateGroupInfoPage.js +++ b/src/content/dependencies/generateGroupInfoPage.js @@ -137,10 +137,7 @@ export default { links: language.formatDisjunctionList( sec.info.visitLinks - .map(link => link.slots({ - context: 'group', - style: 'platform', - }))), + .map(link => link.slot('context', 'group'))), })), html.tag('blockquote', diff --git a/src/content/dependencies/linkExternal.js b/src/content/dependencies/linkExternal.js index ba2dbf21..282fb76c 100644 --- a/src/content/dependencies/linkExternal.js +++ b/src/content/dependencies/linkExternal.js @@ -11,7 +11,7 @@ export default { // differentiate between a function that returns a validator (the usual // syntax) and a function that is itself a validator. validate: () => isExternalLinkStyle, - default: 'normal', + default: 'platform', }, context: { diff --git a/src/content/dependencies/linkExternalAsIcon.js b/src/content/dependencies/linkExternalAsIcon.js index 3eb355a9..c363ad90 100644 --- a/src/content/dependencies/linkExternalAsIcon.js +++ b/src/content/dependencies/linkExternalAsIcon.js @@ -21,8 +21,8 @@ export default { const format = style => language.formatExternalLink(data.url, {style, context: slots.context}); - const normalText = format('normal'); - const compactText = format('compact'); + const platformText = format('platform'); + const handleText = format('handle'); const iconId = format('icon-id'); return html.tag('a', {class: 'icon'}, @@ -34,7 +34,7 @@ export default { [ html.tag('svg', [ !slots.withText && - html.tag('title', normalText), + html.tag('title', platformText), html.tag('use', { href: to('shared.staticIcon', iconId), @@ -43,7 +43,7 @@ export default { slots.withText && html.tag('span', {class: 'icon-text'}, - compactText ?? normalText), + handleText ?? platformText), ]); }, }; diff --git a/src/data/things/language.js b/src/data/things/language.js index 93ed40b6..4079ee71 100644 --- a/src/data/things/language.js +++ b/src/data/things/language.js @@ -522,7 +522,7 @@ export class Language extends Thing { } formatExternalLink(url, { - style = 'normal', + style = 'platform', context = 'generic', } = {}) { if (!this.externalLinkSpec) { diff --git a/src/util/external-links.js b/src/util/external-links.js index 877ef8d4..585e28aa 100644 --- a/src/util/external-links.js +++ b/src/util/external-links.js @@ -1,8 +1,9 @@ -import {empty, stitchArrays} from '#sugar'; +import {empty, stitchArrays, withEntries} from '#sugar'; import { anyOf, is, + isObject, isStringNonEmpty, looseArrayOf, optional, @@ -13,9 +14,8 @@ import { } from '#validators'; export const externalLinkStyles = [ - 'normal', - 'compact', 'platform', + 'handle', 'icon-id', ]; @@ -86,25 +86,24 @@ export const isExternalLinkSpec = }), platform: isStringNonEmpty, - substring: optional(isStringNonEmpty), - - // TODO: Don't allow 'handle' or 'custom' options if the corresponding - // properties aren't provided - normal: optional(is('domain', 'handle', 'custom')), - compact: optional(is('domain', 'handle', 'custom')), - icon: optional(isStringNonEmpty), handle: optional(isExternalLinkExtractSpec), - // TODO: This should validate each value with isExternalLinkExtractSpec. - custom: optional(validateAllPropertyValues(isExternalLinkExtractSpec)), + detail: + optional(anyOf( + isStringNonEmpty, + validateProperties({ + [validateProperties.validateOtherKeys]: + isExternalLinkExtractSpec, + + substring: isStringNonEmpty, + }))), + + icon: optional(isStringNonEmpty), })); export const fallbackDescriptor = { platform: 'external', - - normal: 'domain', - compact: 'domain', icon: 'globe', }; @@ -120,7 +119,7 @@ export const externalLinkSpec = [ }, platform: 'youtube', - substring: 'playlist', + detail: 'playlist', icon: 'youtube', }, @@ -133,7 +132,7 @@ export const externalLinkSpec = [ }, platform: 'youtube', - substring: 'fullAlbum', + detail: 'fullAlbum', icon: 'youtube', }, @@ -145,7 +144,7 @@ export const externalLinkSpec = [ }, platform: 'youtube', - substring: 'fullAlbum', + detail: 'fullAlbum', icon: 'youtube', }, @@ -159,12 +158,9 @@ export const externalLinkSpec = [ }, platform: 'patreon', + handle: {pathname: /([^/]+)\/?$/}, - normal: 'handle', - compact: 'handle', icon: 'globe', - - handle: /([^/]*)\/?$/, }, { @@ -174,14 +170,9 @@ export const externalLinkSpec = [ }, platform: 'youtube', + handle: {pathname: /^@([^/]+)\/?$/}, - normal: 'handle', - compact: 'handle', icon: 'youtube', - - handle: { - pathname: /^(@.*?)\/?$/, - }, }, // Special handling for flash links @@ -193,7 +184,7 @@ export const externalLinkSpec = [ }, platform: 'bgreco', - substring: 'flash', + detail: 'flash', icon: 'globe', }, @@ -207,16 +198,13 @@ export const externalLinkSpec = [ }, platform: 'homestuck', - substring: 'page', - - normal: 'custom', - icon: 'globe', - custom: { - page: { - pathname: /[0-9]+/, - }, + detail: { + substring: 'page', + page: {pathname: /[0-9]+/}, }, + + icon: 'globe', }, { @@ -227,7 +215,7 @@ export const externalLinkSpec = [ }, platform: 'homestuck', - substring: 'secretPage', + detail: 'secretPage', icon: 'globe', }, @@ -239,7 +227,7 @@ export const externalLinkSpec = [ }, platform: 'youtube', - substring: 'flash', + detail: 'flash', icon: 'youtube', }, @@ -256,31 +244,26 @@ export const externalLinkSpec = [ match: {domains: ['artstation.com']}, platform: 'artstation', + handle: {pathname: /^[^/]+/}, - compact: 'handle', icon: 'globe', - - handle: {pathname: /^[^/]*/}, }, { match: {domains: ['.artstation.com']}, platform: 'artstation', + handle: {domain: /^[^.]+/}, - compact: 'handle', icon: 'globe', - - handle: {domain: /^[^.]*/}, }, { match: {domains: ['bc.s3m.us', 'music.solatrus.com']}, platform: 'bandcamp', + handle: {domain: /.+/}, - normal: 'domain', - compact: 'domain', icon: 'bandcamp', }, @@ -288,11 +271,9 @@ export const externalLinkSpec = [ match: {domain: '.bandcamp.com'}, platform: 'bandcamp', + handle: {domain: /^[^.]*/}, - compact: 'handle', icon: 'bandcamp', - - handle: {domain: /^[^.]*/}, }, { @@ -302,22 +283,18 @@ export const externalLinkSpec = [ }, platform: 'bluesky', + handle: {pathname: /^profile\/([^/]+?)(?:\.bsky\.social)?\/?$/}, - compact: 'handle', icon: 'bluesky', - - handle: {pathname: /^profile\/([^/]+?)(?:\.bsky\.social)?\/?$/}, }, { match: {domain: '.carrd.co'}, platform: 'carrd', + handle: {domain: /^[^.]*/}, - compact: 'handle', icon: 'carrd', - - handle: {domain: /^[^.]*/}, }, { @@ -342,11 +319,9 @@ export const externalLinkSpec = [ match: {domain: '.itch.io'}, platform: 'itch', + handle: {domain: /^[^.]*/}, - compact: 'handle', icon: 'itch', - - handle: {domain: /^[^.]*/}, }, { @@ -356,11 +331,9 @@ export const externalLinkSpec = [ }, platform: 'itch', + handle: {pathname: /^profile\/(.+)\/?$/}, - compact: 'handle', icon: 'itch', - - handle: {pathname: /^profile\/(.+)\/?$/} }, { @@ -370,11 +343,9 @@ export const externalLinkSpec = [ }, platform: 'kofi', + handle: {pathname: /^(.+)\/?/}, - compact: 'handle', icon: 'kofi', - - handle: {pathname: /^(.+)\/?/}, }, { @@ -383,13 +354,10 @@ export const externalLinkSpec = [ pathname: /^wiki\/.+\/?$/, }, - platform: 'fandom', - substring: 'mspaintadventures.page', - - normal: 'custom', - icon: 'globe', + platform: 'fandom.mspaintadventures', - custom: { + detail: { + substring: 'page', page: { pathname: /^wiki\/(.+)\/?$/, transform: [ @@ -398,13 +366,14 @@ export const externalLinkSpec = [ ], }, }, + + icon: 'globe', }, { match: {domain: 'mspaintadventures.fandom.com'}, - platform: 'fandom', - substring: 'mspaintadventures', + platform: 'fandom.mspaintadventures', icon: 'globe', }, @@ -437,20 +406,17 @@ export const externalLinkSpec = [ match: {domains: ['tiktok.com']}, platform: 'tiktok', + handle: {pathname: /^@?([a-zA-Z0-9_]*)\/?$/}, - compact: 'handle', icon: 'tiktok', - - handle: {pathname: /^@?([a-zA-Z0-9_]*)\/?$/}, }, { match: {domains: ['types.pl']}, platform: 'mastodon', + handle: {domain: /.+/}, - normal: 'domain', - compact: 'domain', icon: 'mastodon', }, @@ -458,9 +424,8 @@ export const externalLinkSpec = [ match: {domain: '.neocities.org'}, platform: 'neocities', + handle: {domain: /.+/}, - normal: 'domain', - compact: 'domain', icon: 'globe', }, @@ -486,11 +451,9 @@ export const externalLinkSpec = [ match: {domain: 'soundcloud.com'}, platform: 'soundcloud', + handle: /([^/]*)\/?$/, - compact: 'handle', icon: 'soundcloud', - - handle: /([^/]*)\/?$/, }, { @@ -503,33 +466,27 @@ export const externalLinkSpec = [ match: {domain: '.tumblr.com'}, platform: 'tumblr', + handle: {domain: /^[^.]*/}, - compact: 'handle', icon: 'tumblr', - - handle: {domain: /^[^.]*/}, }, { match: {domain: 'twitch.tv'}, platform: 'twitch', + handle: {pathname: /^(.+)\/?/}, - compact: 'handle', icon: 'twitch', - - handle: {pathname: /^(.+)\/?/}, }, { match: {domain: 'twitter.com'}, platform: 'twitter', + handle: {pathname: /^@?([a-zA-Z0-9_]*)\/?$/}, - compact: 'handle', icon: 'twitter', - - handle: {pathname: /^@?([a-zA-Z0-9_]*)\/?$/}, }, { @@ -725,149 +682,73 @@ export function extractAllCustomPartsFromExternalLink(url, custom) { export function getExternalLinkStringOfStyleFromDescriptor(url, style, descriptor, {language}) { const prefix = 'misc.external'; - function getPlatform() { - return language.$(prefix, descriptor.platform); - } - - function getPlatformOrDomain() { - // The fallback descriptor has a "platform" which is just - // the word "External". This isn't really useful when you're - // looking for platform info! Compact mode shows the domain. - if (descriptor === fallbackDescriptor) { - return getCompactDomain(); - } else { - return getPlatform(); - } - } - - function getDomain() { - return urlParts(url).domain; - } - - function getCompactDomain() { - const domain = getDomain(); - - if (!domain) { + function getDetail() { + if (!descriptor.detail) { return null; } - return language.sanitize(domain.replace(/^www\./, '')); - } - - function getCustom() { - if (!descriptor.custom) { - return null; - } - - const customParts = - extractAllCustomPartsFromExternalLink(url, descriptor.custom); - - if (!customParts) { - return null; - } + if (typeof descriptor.detail === 'string') { + return language.$(prefix, descriptor.platform, descriptor.detail); + } else { + const {substring, ...rest} = descriptor.detail; - return language.$(prefix, descriptor.platform, descriptor.substring, customParts); - } + const opts = + withEntries(rest, entries => entries + .map(([key, value]) => [ + key, + extractPartFromExternalLink(url, value), + ])); - function getHandle() { - if (!descriptor.handle) { - return null; + return language.$(prefix, descriptor.platform, substring, opts); } - - return extractPartFromExternalLink(url, descriptor.handle); } - function getNormal() { - if (descriptor.custom) { - if (descriptor.normal === 'custom') { - return getCustom(); + switch (style) { + case 'platform': { + if (descriptor === fallbackDescriptor) { + // The fallback descriptor has a "platform" which is just + // the word "External". This isn't really useful when you're + // looking for platform info! + const domain = urlParts(url).domain; + if (domain) { + return language.sanitize(domain.replace(/^www\./, '')); + } else { + return language.$(prefix, descriptor.platform); + } + } else if (descriptor.detail) { + return getDetail(); } else { - return null; - } - } - - if (descriptor.normal === 'domain') { - const platform = getPlatform(); - const domain = getDomain(); - - if (!platform || !domain) { - return null; - } - - return language.$(prefix, 'withDomain', {platform, domain}); - } - - if (descriptor.normal === 'handle') { - const platform = getPlatform(); - const handle = getHandle(); - - if (!platform || !handle) { - return null; + return language.$(prefix, descriptor.platform); } - - return language.$(prefix, 'withHandle', {platform, handle}); } - return language.$(prefix, descriptor.platform, descriptor.substring); - } - - function getCompact() { - if (descriptor.custom) { - if (descriptor.compact === 'custom') { - return getCustom(); + case 'handle': { + if (descriptor.handle) { + return extractPartFromExternalLink(url, descriptor.handle); } else { return null; } } - if (descriptor.compact === 'domain') { - return getCompactDomain(); - } - - if (descriptor.compact === 'handle') { - const handle = getHandle(); - - if (!handle) { + case 'icon-id': { + if (descriptor.icon) { + return descriptor.icon; + } else { return null; } - - return language.sanitize(handle); } } - - function getIconId() { - return descriptor.icon ?? null; - } - - switch (style) { - case 'normal': return getNormal(); - case 'compact': return getCompact(); - case 'platform': return getPlatformOrDomain(); - case 'icon-id': return getIconId(); - } } export function couldDescriptorSupportStyle(descriptor, style) { - if (style === 'normal') { - if (descriptor.custom) { - return descriptor.normal === 'custom'; - } else { - return true; - } - } - - if (style === 'compact') { - if (descriptor.custom) { - return descriptor.compact === 'custom'; - } else { - return !!descriptor.compact; - } - } - if (style === 'platform') { return true; } + if (style === 'handle') { + return !!descriptor.handle; + } + if (style === 'icon-id') { return !!descriptor.icon; } -- cgit 1.3.0-6-gf8a5