Skip to content

Commit

Permalink
Refactors
Browse files Browse the repository at this point in the history
- De-duplicate code on `_extendTheme` function
- Don't use generic type for `_extendTheme's `theme` object
- Don't re-export module exports in British English for the sake of simplicity and LSP
- Move the `ThemeObject` type to test file for now since it's only used there
- Some JSDoc description updates
  • Loading branch information
catuhana committed Oct 7, 2024
1 parent 09263d9 commit 03d530e
Show file tree
Hide file tree
Showing 5 changed files with 113 additions and 120 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,6 @@ export default defineConfig({
Please refer to
[the documentation in jsr.io](https://jsr.io/@tuhana/unocss-catppuccin/doc).

# License
# Licence

This project is licenced under [Mozilla Public License Version 2.0](LICENCE).
82 changes: 39 additions & 43 deletions src/extend.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
import {
flavorEntries as flavourEntries,
flavors as flavours,
} from '@catppuccin/palette';
import { flavorEntries, flavors } from '@catppuccin/palette';

import type { ExtendOptions } from './types.ts';
import type { CatppuccinFlavor } from '@catppuccin/palette';
import type { ExtendOptions, Falsy } from './types.ts';

/**
* Extend theme to UnoCSS by passing this to `extendTheme` function.
Expand All @@ -12,50 +10,48 @@ import type { ExtendOptions } from './types.ts';
* @returns The main function that supposed to be passed
* to UnoCSS `extendTheme` option.
*/
export const _extendTheme = <Theme extends object = object>(
export const _extendTheme = (
options: ExtendOptions = {},
): (theme: Theme) => void => {
const { prefix = 'ctp', defaultFlavour } = options;

//* We don't know what `theme` could be, since it's provided to us
//* by UnoCSS. I think we could type-safe the parts we have
//* (`ThemeObject` type), but I'm not sure how to do that.
// deno-lint-ignore no-explicit-any
return (theme: any): void => {
theme['colors'] ??= {};
): (theme: Record<string, any>) => void => {
const { prefix = 'ctp', defaultFlavour } = options;

// Determine the target object where the colours will be added
const target = prefix ? (theme['colors'][prefix] ??= {}) : theme['colors'];
return (theme): void => {
theme.colors ??= {};

// If `defaultFlavour` is set, and if it exists:
if (defaultFlavour && flavours[defaultFlavour]) {
// Iterate through the colours of that flavour and add them to the target
for (
const [colourName, colour] of flavours[defaultFlavour]
.colorEntries
) {
if (!prefix && target[colourName]) {
target['ctp'] ??= {};
target['ctp'][colourName] = colour.hex;
} else {
target[colourName] = colour.hex;
}
}
} // If `defaultFlavour` is not set, or specified flavour doesn't exist:
else {
// Iterate through all the flavours,
for (const [flavourName, flavour] of flavourEntries) {
// create an empty object for that flavour
//! We have to create a new variable to prevent
//! accidentally nesting flavours inside each other
const newTarget = (target[flavourName] ??= {});
const targetObject = prefix ? (theme.colors[prefix] ??= {}) : theme.colors;

// Iterate through the colours of the flavour
for (const [colourName, colour] of flavour.colorEntries) {
// and add them to the new target
newTarget[colourName] = colour.hex;
}
if (defaultFlavour && flavors[defaultFlavour]) {
addColoursToTarget(
targetObject,
flavors[defaultFlavour].colorEntries,
prefix,
);
} else {
for (const [flavourName, flavour] of flavorEntries) {
targetObject[flavourName] ??= {};
addColoursToTarget(
targetObject[flavourName],
flavour.colorEntries,
prefix,
);
}
}
};
};

function addColoursToTarget(
// deno-lint-ignore no-explicit-any
targetObject: any,
colourEntries: CatppuccinFlavor['colorEntries'],
prefix: string | Falsy,
) {
for (const [colourName, colour] of colourEntries) {
if (!prefix && targetObject[colourName]) {
targetObject['ctp'] ??= {};
targetObject['ctp'][colourName] = colour.hex;
} else {
targetObject[colourName] = colour.hex;
}
}
}
69 changes: 64 additions & 5 deletions src/extend_test.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,73 @@
import { describe, it } from '@std/testing/bdd';
import { assert, assertEquals, assertInstanceOf } from '@std/assert';

import { flavorEntries as flavourEntries } from '@catppuccin/palette';
import { flavorEntries } from '@catppuccin/palette';

import { _extendTheme } from './extend.ts';
import type { ExtendOptions, ThemeObject } from './types.ts';

import type { CatppuccinColors, CatppuccinFlavors } from '@catppuccin/palette';

import type { ExtendOptions, Falsy } from './types.ts';

type ThemeObject<Options extends ExtendOptions> = Options extends
{ prefix: string; defaultFlavour?: undefined } ? {
colors: {
[prefix in Options['prefix']]: {
[flavour in keyof CatppuccinFlavors]: {
[colour in keyof CatppuccinColors]: string;
};
};
};
}
: Options extends { prefix: Falsy; defaultFlavour?: undefined } ? {
colors: {
[flavour in keyof CatppuccinFlavors]: {
[colour in keyof CatppuccinColors]: string;
};
};
}
: Options extends { prefix?: undefined; defaultFlavour?: undefined } ? {
colors: {
'ctp': {
[flavour in keyof CatppuccinFlavors]: {
[colour in keyof CatppuccinColors]: string;
};
};
};
}
: Options extends { prefix: string; defaultFlavour: keyof CatppuccinFlavors }
? {
colors: {
[prefix in Options['prefix']]: {
[colour in keyof CatppuccinColors]: string;
};
};
}
: Options extends { prefix: Falsy; defaultFlavour: keyof CatppuccinFlavors }
? {
colors:
& {
[colour in keyof CatppuccinColors]?: string;
}
& {
'ctp'?: {
[colour in keyof CatppuccinColors]?: string;
};
};
}
: Options extends
{ prefix?: undefined; defaultFlavour: keyof CatppuccinFlavors } ? {
colors: {
'ctp': {
[colour in keyof CatppuccinColors]: string;
};
};
}
: never;

describe('`_extendTheme` with', () => {
const expectedFlavours = flavourEntries.map(([flavourName]) => flavourName);
const expectedColours = flavourEntries[0][1].colorEntries.map((
const expectedFlavours = flavorEntries.map(([flavourName]) => flavourName);
const expectedColours = flavorEntries[0][1].colorEntries.map((
[colourName],
) => colourName);

Expand Down Expand Up @@ -129,7 +188,7 @@ Deno.test("generated colours are accurate to Catppuccin's", () => {

_extendTheme(options)(theme);

for (const [flavourName, flavour] of flavourEntries) {
for (const [flavourName, flavour] of flavorEntries) {
assertInstanceOf(theme.colors.ctp[flavourName], Object);

for (const [colourName, colour] of flavour.colorEntries) {
Expand Down
2 changes: 1 addition & 1 deletion src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import type { UnoCSSCatppuccinOptions } from './types.ts';
/**
* Catppuccin preset for UnoCSS.
*
* @param options - Options for the preset.
* @param options - Options of the preset.
*/
export const presetCatppuccin = (
options: UnoCSSCatppuccinOptions = { mode: 'extend' },
Expand Down
78 changes: 8 additions & 70 deletions src/types.ts
Original file line number Diff line number Diff line change
@@ -1,83 +1,20 @@
import type {
CatppuccinColors as CatppuccinColours,
CatppuccinFlavors as CatppuccinFlavours,
} from '@catppuccin/palette';
import type { CatppuccinFlavors } from '@catppuccin/palette';

import type { PresetOptions } from '@unocss/core';

/**
* Theme object for Catppuccin colours.
*
* This type only contains the fields that are added with the `extend` mode.
*/
export type ThemeObject<Options extends ExtendOptions> = Options extends
{ prefix: string; defaultFlavour?: undefined } ? {
colors: {
[prefix in Options['prefix']]: {
[flavour in keyof CatppuccinFlavours]: {
[colour in keyof CatppuccinColours]: string;
};
};
};
}
: Options extends { prefix: Falsy; defaultFlavour?: undefined } ? {
colors: {
[flavour in keyof CatppuccinFlavours]: {
[colour in keyof CatppuccinColours]: string;
};
};
}
: Options extends { prefix?: undefined; defaultFlavour?: undefined } ? {
colors: {
'ctp': {
[flavour in keyof CatppuccinFlavours]: {
[colour in keyof CatppuccinColours]: string;
};
};
};
}
: Options extends { prefix: string; defaultFlavour: keyof CatppuccinFlavours }
? {
colors: {
[prefix in Options['prefix']]: {
[colour in keyof CatppuccinColours]: string;
};
};
}
: Options extends { prefix: Falsy; defaultFlavour: keyof CatppuccinFlavours }
? {
colors:
& {
[colour in keyof CatppuccinColours]?: string;
}
& {
'ctp'?: {
[colour in keyof CatppuccinColours]?: string;
};
};
}
: Options extends
{ prefix?: undefined; defaultFlavour: keyof CatppuccinFlavours } ? {
colors: {
'ctp': {
[colour in keyof CatppuccinColours]: string;
};
};
}
: never;

/**
* Falsy values except `undefined`.
*
* `undefined` *is* considered as a falsy value, but if `prefix` option is
* `undefined`, it will default to `ctp`.
* `undefined` *is* considered as a falsy value, but `undefined` some
* option fields ({@link UnoCSSCatppuccinOptions.prefix}) have default values.
*/
export type Falsy = false | 0 | '' | null;

/**
* Which mode to use the preset with.
*
* `extend` mode will create new colours for current preset by using `extendTheme` function from UnoCSS.
* `extend` mode will create new colours for current preset by using
* `extendTheme` function from UnoCSS.
*/
export type Modes = 'extend';

Expand All @@ -88,7 +25,8 @@ export interface UnoCSSCatppuccinOptions extends PresetOptions {
/**
* Which mode to use the preset with.
*
* `extend` mode will create new colours for current preset by using `extendTheme` function from UnoCSS.
* `extend` mode will create new colours for current preset by using
* `extendTheme` function from UnoCSS.
*
* @default 'extend'
*/
Expand Down Expand Up @@ -132,7 +70,7 @@ export interface UnoCSSCatppuccinOptions extends PresetOptions {
*
* @default undefined
*/
defaultFlavour?: keyof CatppuccinFlavours;
defaultFlavour?: keyof CatppuccinFlavors;
}

/**
Expand Down

0 comments on commit 03d530e

Please sign in to comment.