Merge commit 'd78535eab9cefc285c0d7ef88adb125ab1ceb6bd' into glitch-soc/merge-upstream

Conflicts:
- `vite.config.mts`:
  Upstream moved its theming system to a plug-in, where we had our own.
  Adapted the file as well as our own plugin to adopt the same mechanisms.
This commit is contained in:
Claire
2025-05-27 20:49:19 +02:00
125 changed files with 994 additions and 454 deletions

View File

@@ -1,59 +1,65 @@
/* This plugins handles glitch-soc's specific theming system
*/
import fs from 'node:fs';
import fs from 'node:fs/promises';
import path from 'node:path';
import glob from 'fast-glob';
import yaml from 'js-yaml';
import type { Plugin, UserConfig } from 'vite';
export function GlitchThemesPlugin(): Plugin {
return {
name: 'glitch-themes',
config,
};
}
import type { Plugin } from 'vite';
interface Flavour {
pack_directory: string;
}
function config(): UserConfig {
const entrypoints: Record<string, string> = {};
const glitchFlavourFiles = glob.sync('app/javascript/flavours/*/theme.yml');
for (const flavourFile of glitchFlavourFiles) {
const flavourName = path.basename(path.dirname(flavourFile));
const flavourString = fs.readFileSync(flavourFile, 'utf8');
const flavourDef = yaml.load(flavourString, {
filename: 'theme.yml',
schema: yaml.FAILSAFE_SCHEMA,
}) as Flavour;
const flavourEntrypoints = glob.sync(
`${flavourDef.pack_directory}/*.{ts,tsx,js,jsx}`,
);
for (const entrypoint of flavourEntrypoints) {
const name = `${flavourName}/${path.basename(entrypoint)}`;
entrypoints[name] = path.resolve(process.cwd(), entrypoint);
}
// Skins
// TODO: handle variants such as `skin/common.scss`
const skinFiles = glob.sync(`app/javascript/skins/${flavourName}/*.scss`);
for (const entrypoint of skinFiles) {
const name = `skins/${flavourName}/${path.basename(entrypoint)}`;
entrypoints[name] = path.resolve(process.cwd(), entrypoint);
}
}
export function GlitchThemes(): Plugin {
return {
build: {
rollupOptions: {
input: entrypoints,
},
name: 'glitch-themes',
async config(userConfig) {
const entrypoints: Record<string, string> = {};
if (!userConfig.root || !userConfig.envDir) {
throw new Error('Unknown project directory');
}
const glitchFlavourFiles = glob.sync(
path.resolve(userConfig.root, 'flavours/*/theme.yml'),
);
for (const flavourFile of glitchFlavourFiles) {
const flavourName = path.basename(path.dirname(flavourFile));
const flavourString = await fs.readFile(flavourFile, 'utf8');
const flavourDef = yaml.load(flavourString, {
filename: 'theme.yml',
schema: yaml.FAILSAFE_SCHEMA,
}) as Flavour;
const flavourEntrypoints = glob.sync(
`${flavourDef.pack_directory}/*.{ts,tsx,js,jsx}`,
);
for (const entrypoint of flavourEntrypoints) {
const name = `${flavourName}/${path.basename(entrypoint)}`;
entrypoints[name] = path.resolve(userConfig.envDir, entrypoint);
}
// Skins
// TODO: handle variants such as `skin/common.scss`
const skinFiles = glob.sync(
`app/javascript/skins/${flavourName}/*.scss`,
);
for (const entrypoint of skinFiles) {
const name = `skins/${flavourName}/${path.basename(entrypoint)}`;
entrypoints[name] = path.resolve(userConfig.envDir, entrypoint);
}
}
return {
build: {
rollupOptions: {
input: entrypoints,
},
},
};
},
};
}

View File

@@ -0,0 +1,58 @@
/* This plugins handles Mastodon's theme system
*/
import fs from 'node:fs/promises';
import path from 'node:path';
import yaml from 'js-yaml';
import type { Plugin } from 'vite';
export function MastodonThemes(): Plugin {
return {
name: 'mastodon-themes',
async config(userConfig) {
if (!userConfig.root || !userConfig.envDir) {
throw new Error('Unknown project directory');
}
const themesFile = path.resolve(userConfig.envDir, 'config/themes.yml');
const entrypoints: Record<string, string> = {};
// Get all files mentioned in the themes.yml file.
const themesString = await fs.readFile(themesFile, 'utf8');
const themes = yaml.load(themesString, {
filename: 'themes.yml',
schema: yaml.FAILSAFE_SCHEMA,
});
if (!themes || typeof themes !== 'object') {
throw new Error('Invalid themes.yml file');
}
for (const themePath of Object.values(themes)) {
if (
typeof themePath !== 'string' ||
themePath.split('.').length !== 2 || // Ensure it has exactly one period
!themePath.endsWith('css')
) {
console.warn(
`Invalid theme path "${themePath}" in themes.yml, skipping`,
);
continue;
}
entrypoints[path.basename(themePath)] = path.resolve(
userConfig.root,
themePath,
);
}
return {
build: {
rollupOptions: {
input: entrypoints,
},
},
};
},
};
}