Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 26 additions & 3 deletions eleventy.config.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ const FEATURED_LABELS = [
'theme',
]
const LABELS_RANK = new Map(FEATURED_LABELS.map((label, index) => [label, index]))
const LABEL_ICON_MINIMUM_USAGE = 2

const MS_IN_DAY = 24 * 60 * 60 * 1000
const MAGIC_FRESHNESS_WINDOW_DAYS = 365 * 2 // bonus for packages that had updates
Expand Down Expand Up @@ -375,6 +376,7 @@ export default async function (eleventyConfig) {
const siteOrigin = isProd ? prodOrigin : devOrigin
const staticOutputDir = isProd ? 'static_' + util.gitHash : 'static'
const bundledScriptEntries = new Set()
let labelIcons = null

eleventyConfig.addPassthroughCopy(
{ static: staticOutputDir },
Expand All @@ -389,6 +391,11 @@ export default async function (eleventyConfig) {
eleventyConfig.on('eleventy.after', async ({ directories } = {}) => {
const outputDir = directories?.output ?? '_site'
await writeVendorModules(path.join(outputDir, staticOutputDir, 'vendor'))
writePrunedLabelIconSprite(
'static/label-icons.svg',
path.join(outputDir, staticOutputDir, 'label-icons.svg'),
labelIcons?.sources,
)

if (!isProd) {
return
Expand Down Expand Up @@ -514,6 +521,8 @@ export default async function (eleventyConfig) {

const packages = all_packages.map(packageData)
const packagesWithMagic = computeMagicMetadata(packages)
const labels = util.collectLabels(all_packages)
labelIcons = filters.configureLabelIcons(labels, { minimumUsage: LABEL_ICON_MINIMUM_USAGE })

const livingHomePackages = packages.filter(pkg => !pkg.removed)

Expand Down Expand Up @@ -603,9 +612,7 @@ export default async function (eleventyConfig) {
}
}

eleventyConfig.addCollection('labels', () => {
return util.collectLabels(all_packages)
})
eleventyConfig.addCollection('labels', () => labels)

eleventyConfig.addCollection('libraries', () => {
return Object.values(workspace.libraries)
Expand Down Expand Up @@ -668,6 +675,7 @@ export default async function (eleventyConfig) {

// Register all named exports from external module as filters
for (const [name, fn] of Object.entries(filters)) {
if (name === 'configureLabelIcons') continue
eleventyConfig.addFilter(name, fn)
}

Expand All @@ -686,6 +694,21 @@ export default async function (eleventyConfig) {
}
}

function writePrunedLabelIconSprite(sourcePath, outputPath, visibleSources) {
if (!(visibleSources instanceof Set) || !fs.existsSync(sourcePath)) {
return
}

const source = fs.readFileSync(sourcePath, 'utf8')
const pruned = source.replace(
/<symbol\b[^>]*\bid="label-icon-([^"]+)"[^>]*>[\s\S]*?<\/symbol>\r?\n?/g,
(symbol, iconSource) => visibleSources.has(iconSource) ? symbol : '',
)

fs.mkdirSync(path.dirname(outputPath), { recursive: true })
fs.writeFileSync(outputPath, pruned, 'utf8')
}

async function bundleJs(staticOutputDir, entries, isProd) {
if (!entries.size) {
return
Expand Down
79 changes: 75 additions & 4 deletions eleventy.filters.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ const configPath = path.join(__dirname, 'label-icons-config.json')
let labelIconSourceSet = new Set()
let labelIconAliases = {}
let labelIconTints = {}
let labelIconVisibleSourceSet = null
let labelIconVisibleTints = null

const longDateFormatter = new Intl.DateTimeFormat('en-US', { dateStyle: 'long' })
const compactNumberFormatter = new Intl.NumberFormat('en', { notation: 'compact' })
Expand Down Expand Up @@ -67,7 +69,17 @@ export function label_icon_aliases_json() {
}

export function label_icon_tints_json() {
return JSON.stringify(labelIconTints)
return JSON.stringify(activeLabelIconTints())
}

export function configureLabelIcons(labels, { minimumUsage = 1 } = {}) {
labelIconVisibleSourceSet = visibleLabelIconSources(labels, minimumUsage)
labelIconVisibleTints = labelIconTintsForSources(labelIconVisibleSourceSet)

return {
sources: labelIconVisibleSourceSet,
tints: labelIconVisibleTints,
}
}

export function label_normalization_note(changes) {
Expand Down Expand Up @@ -102,7 +114,7 @@ export function search_index_json(packages) {
return JSON.stringify({
packages: packages.map(compactSearchPackage),
label_icon_aliases: labelIconAliases,
label_icon_tints: labelIconTints,
label_icon_tints: activeLabelIconTints(),
})
}

Expand Down Expand Up @@ -187,7 +199,30 @@ function joinAsSentenceList(parts) {
return `${parts.slice(0, -1).join(', ')}, and ${parts.at(-1)}`
}

function canonicalLabel(label) {
function visibleLabelIconSources(labels, minimumUsage) {
const counts = new Map()
const threshold = Math.max(1, Number(minimumUsage) || 1)

for (const item of labels ?? []) {
const key = typeof item?.key === 'string' ? item.key : String(item ?? '')
const canonical = sourceLabelFor(key)
if (!canonical) continue

const count = Number(item?.count ?? 1)
counts.set(canonical, (counts.get(canonical) ?? 0) + (Number.isFinite(count) ? count : 1))
}

const sources = new Set()
for (const source of labelIconSourceSet) {
if ((counts.get(source) ?? 0) >= threshold) {
sources.add(source)
}
}

return sources
}

function sourceLabelFor(label) {
if (typeof label !== 'string') return ''
const normalized = label.trim().toLowerCase()
if (!normalized) return ''
Expand All @@ -204,6 +239,42 @@ function canonicalLabel(label) {
return ''
}

function labelIconTintsForSources(sources) {
const tints = {}
for (const source of sources) {
if (Object.prototype.hasOwnProperty.call(labelIconTints, source)) {
tints[source] = labelIconTints[source]
}
}
return tints
}

function activeLabelIconSourceSet() {
return labelIconVisibleSourceSet ?? labelIconSourceSet
}

function activeLabelIconTints() {
return labelIconVisibleTints ?? labelIconTints
}

function canonicalLabel(label) {
if (typeof label !== 'string') return ''
const normalized = label.trim().toLowerCase()
if (!normalized) return ''

const sourceSet = activeLabelIconSourceSet()
const alias = labelIconAliases[normalized]
if (alias && sourceSet.has(alias)) {
return alias
}

if (sourceSet.has(normalized)) {
return normalized
}

return ''
}

export function label_icon_id(label) {
const canonical = canonicalLabel(label)
if (!canonical) return ''
Expand All @@ -213,7 +284,7 @@ export function label_icon_id(label) {
export function label_icon_tint(label) {
const canonical = canonicalLabel(label)
if (!canonical) return ''
return labelIconTints[canonical] ?? ''
return activeLabelIconTints()[canonical] ?? ''
}

// number formatting with grouping (e.g. 10,000)
Expand Down
5 changes: 3 additions & 2 deletions label-icons-config.json
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
{
"_": "Manually maintained set of icons to exclude and an alias map from labels to icon/language ids",
"exclude": ["ai"],
"exclude": ["ai", "c", "c#", "c++"],
"aliases": {
"javascript": "js",
"ecmascript": "js",
"ecmascript6": "js"
"ecmascript6": "js",
"cpp": "c++"
}
}
4 changes: 0 additions & 4 deletions label-icons.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,15 +10,11 @@
"binary": "graphite",
"blade": "orange",
"bower": "yellow",
"c": "purple",
"c#": "blue",
"c++": "sky",
"cairo": "graphite",
"clojure": "purple",
"cmake": "blue",
"coffeescript": "orange",
"composer": "orange",
"cpp": "sky",
"crystal": "graphite",
"css": "blue",
"csv": "green",
Expand Down
Loading