diff --git a/package.json b/package.json index a26461aa..d0c74511 100644 --- a/package.json +++ b/package.json @@ -6,9 +6,10 @@ "dependencies": { "@napi-rs/canvas": "^0.1.41", "@napi-rs/image": "^1.7.0", + "@resvg/resvg-js": "^2.6.0", "@skyra/gifenc": "^1.0.1", "file-type": "16.5.4", - "satori": "^0.10.1", + "satori": "^0.10.9", "tailwind-merge": "^1.14.0" }, "scripts": { diff --git a/src/assets/Font.ts b/src/assets/Font.ts index 3c3b4551..6cb961b8 100644 --- a/src/assets/Font.ts +++ b/src/assets/Font.ts @@ -4,6 +4,7 @@ import { readFile } from 'fs/promises'; import { Font as FontData } from 'satori'; import { FontFactory } from './AssetsFactory'; import { GlobalFonts } from '@napi-rs/canvas'; +import { Fonts } from './fonts/fonts'; const randomAlias = () => randomUUID() as string; @@ -43,4 +44,12 @@ export class Font { const buffer = readFileSync(path); return new Font(buffer, alias); } + + public static fromBuffer(buffer: Buffer, alias?: string) { + return new Font(buffer, alias); + } + + public static loadDefault() { + return this.fromBuffer(Fonts.Geist, 'geist'); + } } diff --git a/src/assets/fonts/fonts.ts b/src/assets/fonts/fonts.ts new file mode 100644 index 00000000..b016f494 --- /dev/null +++ b/src/assets/fonts/fonts.ts @@ -0,0 +1,12 @@ +export const Fonts = { + /** + * Geist sans font + * @see https://vercel.com/font/sans + */ + get Geist() { + return Buffer.from( + 'T1RUTwAMAIAAAwBAQ0ZGIC9Bk94AABT8AACZE0dERUY4EjfYAACuEAAAARJHUE9TxZMpCAAAryQAABi2R1NVQowLjN4AAMfcAAASgE9TLzJOyiLSAAALgAAAAGBjbWFwDu5h1AAADngAAAZkaGVhZCrJAR4AAADUAAAANmhoZWEM+AmbAAALXAAAACRobXR4vqWNQQAAAQwAAApObWF4cAKUUAAAAADMAAAABm5hbWU8hhcjAAAL4AAAApdwb3N0/58AMgAAFNwAAAAgAABQAAKUAAAAAQAAAAEAg3lXnhpfDzz1AAMD6AAAAADhXF5uAAAAAOFcXm7/1/8lCSIDtgAAAAcAAgAAAAAAAAGuAFAA+gAAApwAFQKcABUCnAAVApwAFQKcABUCnAAVApwAFQKcABUCvAAVApwAFQKcABUDywAVAqYAXAK8ADECvAAxArwAMQK8ADECvAAxArwAMQK9AFwDFQAxAr0AXAMVADECWgBcAloAXAJaAFwCWgBcAloAXAJaAFwCWgBcAloAXAJaAFwCWgBcAtEAMQJNAFwCwwAxAsMAMQLDADECwwAxAsMAMQLDADECvgBcA2UAXAK+AFwBDQBcAxMAXAENAFwBDf/+AQ0AEQENAFsBDQAOAQ0ABwENADABDf/fAlQAQwJUAEMCVABDAosAXAKLAFwCQwBcAkMAXAIfAFwCQwBcAmUAFgNsAFwC4QBcAuEAXALhAFwC4QBcAuEAXALkADEC5AAxAuQAMQLkADEC5AAxAuQAMQLkADEC6QAyAuQAMQQ9ADECiQBcAmsAXALkADECngBcAp4AXAKeAFwCngBcAocAOwKHADsAuQAxAocAOwKHADsChwA7AocAOwKVAFwCQgAZAkIAGQJCABkCQgAZArAATQKwAE0CsABNArAATQKwAE0CsABNArAATQKwAE0CsABNArAATQKwAE0CnAAVA44AFQOOABUDjgAVA44AFQOOABUCdAAbAnQAFQJ0ABUCdAAVAnQAFQJ0ABUCdAAVAh4AGwIeABsCHgAbAh4AGwJDAFwC4QBcAqMAXAKjAFwCowBcAqMAXAGuADEBrgAxAa4AMQGuADEBrgAxAa4AMQGuADEBrgAxAa4AMAK8ADECvAAxArwAMQK8ADECvAAxArwAMQKcABUCvAAxAloAXAJaAFwCwwAxAQ0AAQENAFMC5AAxArAATQOOABUCdAAVAh4AGwGuADEBrgAxArwAMQRKABUEXgBNAj4ALwI+AC8CPgAvAj4ALwI+AC8CPgAvAj4ALwI+AC8CPgAvAj4ALwI+AC8DpAAvAloAVQInAC8CJwAvAicALwInAC8CJwAvAicALwJaAC8CVAAvAvIALwKPAC8CNwAvAjcALwI3AC8CNwAvAjcALwI3AC8CNwAvAjcALwI3AC8CNwAvAjcALwGRAEECWQAvAlkALwJZAC8CWQAvAlkALwJZAC8CSABVAjkAGQJI//YA/ABTAPwAVQD8AFUA/P/2APwACQD8AFMA/AAGAfQAUwD8//8A/AAmAPz/1wEC//sBAv/7AQL/+wEC//sCUgBVAlIAVQEgAFcBIABXAZIAVwEgAE0BfwBXA28AVQJIAFUCSABVAkgAVQJIAFUCSABVAkIALwJCAC8CQgAvAkIALwJCAC8CQgAvAkIALwIyAAwCQgAvA8UALwJaAFUCWgBVAloALwGBAFUBgQBVAYEAPgGBAB8CEQAvAhEALwC5ADECEQAvAhEALwIRAC8CEQAvAlIAVQGPADwBvwA8AY8APAGPADwCSgBXAkoAVwJKAFcCSgBXAkoAVwJKAFcCSgBXAkoAVwJKAFcCSgBXAkoAVwIWABYDMQAWAzEAFgMxABYDMQAWAzEAFgJIAC8CFwAWAhcAFgIXABYCFwAWAhcAFgIXABYCJQA5AiUAOQIlADkCJQA5ASAATQJIAFUCLwAqAi8AKgIvACoCLwAqAi8AKgIvACoCLwAqAi8AKgIvACoCLwAqAi8AKgJUAC8CVAAvAlQALwJUAC8CVAAvAlQALwJUAC8CVAAvAlQALwJUAC8CVAAvAQsAXAELAFwBnABXAQsAJwGAAFcCPgAvAicALwI3AC8CNwAvAlkALwD8AEsA/P/5APwASwH0AEsA/AAmAQL/+wJCAC8CSgBXAzEAFgIXABYCJQA5Ai8AKgJUAC8CrgBBArsAPAKOAEECngBBAj4ALwJCAC8C4gAxApYAPAKUADEBXAAZAlQAMQJuADECSAAZAloAMQJZADECKQAZAm0AMQJZADEDQAAvA0AALwNAAC8DQAAvA0AALwNAAC8DQAAvA0AALwNAAC8DQAAvA0AALwNAAC8DQAAvA0AALwNAAC8DQAAvA0AALwNAAC8DQAAvA0AALwKUADEBsAAZAlgAEAJYAH8CWAAxAlgAKgJYABkCWAAvAlgALgJYAC0CWAAkAlgALgJYAA4DzQAyA8EAMgO6ADEDvAAyA80AMQO1ADIDvwAyA9AAMQPLADIEsACmAlgAlQJYALQCWACgAlgAoAJYAIQCWACmAlgApQJYAKYCWACfAlgAqAJYAJUCWAC0AlgAoAJYAKACWACEAlgApgJYAKUCWACmAlgAnwJYAKgA+gAAAV8ALwlgAD4HCAA+BLAAPgDIAC8AyAAvASIAXAEiAF0COgAvANYANgDWADYCMwAvAjMALwDIAC8BIwAvAbQALwFxAC8B3v/2Ad8AKAHcADQCfgAxAbQALwOPAC8B1wAvAMgALwDIAC8BEgA3Ad7/9gL+AC8AyAAvAjMALwFcAC8AtQAvAMgALwHeACcAzwAvASkAXAEqAFwCQgAvAM8ALwDPAC8CMwAvAjMALwDPAC8CMgAvAM8ALwESADAAzwAvAjMALwDQAC8BqAAvAa0ALwJUAC8DkAAvAjIALwNWAC8C0AAvATQALwE0AC8BpQAvAaUALwFLAC8BSwAvAWQALwFkAC8BbwAvAW8ALwGlAC8BpQAvAYwALwGMAC8CCwAvAgsALwGMADABjAAvAY0ALwGNAC8BZwAvAWcALwFLAC8BSwAvATQALwE0AC8AzAAxAWUAMQFlADEBZQAxAMwAMQDMADECFwAvAhcALwFNAC8BTQAvAWAAMQC5ADEB1ABBAn8AXASwAD4HCAA+CWAAPgcHAD4DQAAvA0AALwOTADECfAAxAkgAIwItADsDRAAxAlsAMQJbADEDegBcAYgALwD5AC8BcQAvAQUAXAEFAFwCOQBcAjkAXARCAFwDVwAxAicALwJJADEChwA7At8AOwKhADsCzQAtAqUAXAMEAFwCZwA7AnQAFQI6AC8COgAvAeUALwI6AC8ClQBcAjoALwIpADECJQAvAjoALwI6AC8COgAvAhcALwIXAC8B5QAvAY4ALwNKAC8BeQAAAosAFQJoABkCEQAbAmIAFgJVAC8CUABaAv4ALwQ/AC8C0QAxAnUAMQMoADECdQAxAtEAMQJ1ADEDKAAxAnUAMQQTADEC0QAxApAAMQKlADECpQAxApcAMQKXADECnQAxAp0AMQKdADECogAxAp0AMQMZABUBoQAxAl0AMQMGADECXQAxAaEAMQJdADIDBgAxAl0AMQNLADEBoQAyA1QAMQNUADEDVAAxAhkAMQNdABUDOABcA10AFQM4ABYDXQAVAzgAXANdABUDOAAWAAAALwAAAC8AAAAvAAAALwAAAC8AAAAvAAAALwAAAC8AAAAvAAAALwAAAC8AAAAvAAAALwAAAC8AAAAvAAAALwAAAC8AAAAvAAAALwFDAC8AtAAvAPkALwD5AC8BcAAvAW8ALwFvAC8BeAAvARYALwGsAC8BXQAvATQALwECAC8BZAAvAMUALwJYAAADQAAvAC8AAAABAAADmP8kAGQJYP/X/oMJIgABAAAAAAAAAAAAAAAAAAACkwAEAkwBkAAFAAgCigJYAAAASwKKAlgAAAFeADIBCQAAAAAAAAAAAAAAAKEAAP8AAeT7AAAAEAAAAABVS1dOAMAAIP9dA5j/JABkA5gA3CAAAJMAAAAAAhICxgAAACAABAAAABYBDgABAAAAAAABAAUAAAABAAAAAAACAAcABQABAAAAAAAEAA0ADAABAAAAAAAFACEAGQABAAAAAAAGAA0AOgADAAEECQABAAoARwADAAEECQACAA4AUQADAAEECQADADAAXwADAAEECQAEABoAjwADAAEECQAFAEIAqQADAAEECQAGABoA6wADAAEECQAQAAoARwADAAEECQARAA4AUQADAAEECQEAABIBBQADAAEECQEBAAoBFwADAAEECQECAAoBIQADAAEECQEDAAoBKwADAAEECQEEAAoBNQADAAEECQEFAAoBPwADAAEECQEGABQBSQADAAEECQEHABYBXQADAAEECQEIABYBc0dlaXN0UmVndWxhckdlaXN0IFJlZ3VsYXJWZXJzaW9uIDEuMDAyO0dseXBocyAzLjEuMiAoMzE1MSlHZWlzdC1SZWd1bGFyAEcAZQBpAHMAdABSAGUAZwB1AGwAYQByADEALgAwADAAMgA7AFUASwBXAE4AOwBHAGUAaQBzAHQALQBSAGUAZwB1AGwAYQByAEcAZQBpAHMAdAAgAFIAZQBnAHUAbABhAHIAVgBlAHIAcwBpAG8AbgAgADEALgAwADAAMgA7AEcAbAB5AHAAaABzACAAMwAuADEALgAyACAAKAAzADEANQAxACkARwBlAGkAcwB0AC0AUgBlAGcAdQBsAGEAcgBOAG8AIAB0AGEAaQBsACAAYQBBAGwAdAAgAGEAQQBsAHQAIABsAEEAbAB0ACAAUgBBAGwAdAAgAEkAQQBsAHQAIABHAEEAbAB0ACAAYQByAHIAbwB3AHMAUgBvAHUAbgBkAGUAZAAgAGQAbwB0AEEAbAB0ACAAbgB1AG0AYgBlAHIAcwAAAAACAAAAAwAAABQAAwABAAAAFAAEBlAAAADEAIAABgBEAC8AOQB+ARMBKwE3AT4BSAFNAWUBfgGPAZIBzgIbAjcCWQLHAt0DBAMIAwwDEgMoA6kDwA4/HiEehR6eHr0e8x75IBQgGiAeICIgJiAwIDMgOiBEIHAgeSCJIKogrCC0ILkgvSEXISIhVSFeIZkhnSGqIbEhtSHlIeciAiIGIg8iEiIaIh4iKyJIImAiZSPOJGgk6iT/JbMltyW9JcElzCXPJjonfjADMBEwFzAcp4z/A/8K/w//G/8g/z3/P/9b/13//wAAACAAMAA6AKABFgEuATkBQQFMAVABaAGPAZIBzQIYAjcCWQLGAtgDAAMGAwoDEgMmA6kDwA4/HiAegB6eHrwe8h74IBMgGCAcICAgJiAwIDIgOSBEIHAgdCCAIKogrCC0ILkgvSEWISIhUyFbIZAhnSGpIbAhsyHkIeciAiIGIg8iESIaIh4iKyJIImAiZCPOJGAk6iT/JbIltiW8JcAlyiXPJjkndjACMAgwFDAcp4v/Af8F/wz/Gv8f/zv/P/9b/13//wAAAS8AAAAAAAAAAAAAAAAAAAAAAAD+lAB2AAAAAP6o/m//wQAAAAAAAAAA/2n/Vv20/Z7zygAAAADhwgAAAAAAAOHKAAAAAAAA4YviE+Hn4cvhReEu4S7hFOF+4XjhceFu4WkAAOD1AADgNQAA4LHgqOCj4KLga+Bx4D7gNuAuAADgJeAc4BDf7t/QAADeUt0U3IncagAAAAAAAAAAAADclNvV2fQAAAAAAADRxAAAAAAAAAAAAAAAAAAAApYCkQKQAAEAxAAAAOABaAJOAngCigKUAqICpALOAAAAAAL2AvgAAAAAAAAC+AMCAwoDDgAAAAAAAAAAAAADCAMKAAADEgMUAxYAAAMWAxoDHgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAwgAAAMIAAADCgAAAAAAAAAAAAAAAAAAAAAAAAMKAAAAAAAAAAAAAAMCAAAAAAAAAAAC/AL+AwADAgMEAAAAAAAAAwIDBAMWAAADGgMcAyADKgMwAzIDNAAAAAAAAAAAAAEBsgIGAboCIwJCAhECBwHiAeMBuAIrAa4B2wGtAbsBrwGwAjICLwIxAbQCEAACAA4ADwAVABkAJAAlACsALgA4ADsAPQBCAEMASABSAFQAVQBZAGEAZQBwAHEAdgB3AH0B5gG8AecCOQHfAoQApwCzALQAugC+AMkAygDQANMA3gDiAOQA6QDqAO8A+QD7APwBAAEIAQwBFwEYAR0BHgEkAeQCGwHlAjcBqAGzAiECKQIiAioCHAITAoICFAFbAgICOAHcAhUCjAIYAjUBoAGhAoUCQQISAbYCjQGfAVwCAwGNAYoBjgG1AAgAAwAGAAwABwALAA0AEgAfABoAHAAdADQAMAAxADIAFgBHAEwASQBKAFAASwItAE8AagBmAGgAaQB4AFMBBwCtAKgAqwCxAKwAsACyALcAxAC/AMEAwgDZANUA1gDXALsA7gDzAPAA8QD3APICLgD2AREBDQEPARABHwD6ASEACQCuAAQAqQAKAK8AEAC1ABMAuAAUALkAEQC2ABcAvAAYAL0AIADFAB4AwwAhAMYAGwDAACcAzAAmAMsAKQDOACgAzQAtANIALADRADcA3QA1ANsANgDcADMA1AAvANoAOgDhADwA4wA+AOUAQADnAD8A5gBBAOgARADrAEYA7QBFAOwATgD1AE0A9ABRAPgAVgD9AFgA/wBXAP4AWgEBAF4BBQBdAQQAXAEDAGMBCgBiAQkAbwEWAGwBEwBnAQ4AbgEVAGsBEgBtARQAcwEaAHkBIAB6AH4BJQCAAScAfwEmAAUAqgBfAQYAZAELAokCgwKKAo4CiwKGAnECcgJ1AnkCegJ3AnACbwJ4AnMCdgAqAM8AdQEcAHIBGQB0ARsAIgDHAHsBIgB8ASMCAAIBAfwB/gH/Af0CHQIeAbcCHwIWAYsBjAGPAkoCRAJGAkgCTAJNAksCRQJHAkkCPgIsAjQCMwJnAmsCaAJsAmkCbQJqAm4CZgJkAmUBqQG5AegB6QHwAfEB7gHvAfQB9QHqAesB8gHzAfYB9wBbAQIBwwHIAcQBxQG9AckB+gH7Ab4BwgHhAcYBywHBAcoBxwG/AfgBwAH5AAMAAAAAAAD/nAAyAAAAAAAAAAAAAAAAAAAAAAAAAAABAAQCAAEBAQ5HZWlzdC1SZWd1bGFyAAEBASn4EQD5zAH5zQL4GAT7EQwDYvtvHAki+koFHCnHDxwsuRGpHQAAiQwSAbMCAAEABwAOABUAHAAiACgAMwA9AEMASQBPAFkAYABnAG4AdQB7AIYAjQCXAJ4AogCtAK8AuQDAAMcAzQDYAOMA6gDwAPYA/QEDAQkBEAEdASQBKgEwATcBPQFEAUwBVwFeAWUBawFyAXkBfwGMAZMBmgGfAaUBqwG2Ab8BxQHQAdYB3QHjAe0B/AILAhECHAInAjMCOQJEAlQCYgJxAnwCiAKUAp8CpQKwAsACzALbAucC9QMEAxIDIQMwAz4DTQNbA2kDdwOFA5QDpwO7A88D1wPfA+UD7APzA/oEAAQGBBEEGwQhBCcELQQ3BD4ERQRMBFMEWQRkBGsEdQR8BIAEiwSUBJYEnQSkBKoEsQS8BMcEzgTUBNoE4QTnBO0E9AUBBQgFDgUUBRsFIQUoBTAFOwVCBUgFTwVWBVwFaQVwBXcFfAWCBYgFkwWcBaIFrQWzBboFwAXKBdkF6AXuBfkGBAYQBiAGLgY5BkUGUQZbBmYGbAZ3BoIGjgaeBqwGtwbDBs8G2QbkBuoG9QcABwwHFwclBzQHQgdRB2AHZgd0B4IHiQeVB5sHqQe3B8UH0wfiB/UICAgQCBgIHwgmCC0ILwg2CD0IRAhLCFIIWQhgCGcIbgh1CHwIgwiKCJEImAifCKYIrQi0CLsIxAjMCNMI2QjfCOcI7gj1CPsJAwkLCRIJGQkgCScJLgk1CTwJQwlKCVEJWAlfCWYJbQl0CXsJggmJCZAJlwmeCaUJrAmzCboJwQniCfwKDwoWCh0KJAorCjIKOQpACkcKTgpVClwKYwpqCnEKeAp/CooKlAqiCq8KugrJCtYK5wr6CwELDQsZCyULMQs9C0QLSwtSC1kLYAtnC24LdQt8C4MLiguRC5gLnwumC60LtAu7C8ILyQvQC9cL3gvlC/UMDAwqDEIMSQxSDFkMXwxlDGwMcwx3DH4MhQyMDJMMmwynDLAMuwzDDMsM0gzZDOIM6Qz0DPsNAg0JDRMNGg0jDSoNMw06DUMNTA1TDVoNYQ1oDW8Ndg19DYQNiw2ZDaANrA24DccN0w3hDe0N+w4HDhUOIw4qDjAONw4+DkUOTA5TDloOYQ5oDm8Odg59DoQOjQ6WDp0OqA6vDrYOvQ7EDs0O1A7bDuIO6Q7wDv8PCw8XDyQPMg88D0gPWg9rD3hBYnJldmV1bmkwMUNEQW1hY3JvbkFvZ29uZWtDYWN1dGVDY2Fyb25DY2lyY3VtZmxleENkb3RhY2NlbnREY2Fyb25EY3JvYXRFY2Fyb25FZG90YWNjZW50RW1hY3JvbkVvZ29uZWt1bmkxRUJDdW5pMDE4RkdicmV2ZUdjaXJjdW1mbGV4dW5pMDEyMkdkb3RhY2NlbnR1bmkxRTIwSGJhckhjaXJjdW1mbGV4SUpJZG90YWNjZW50SW1hY3JvbklvZ29uZWtJdGlsZGV1bmkwMDRBMDMwMUpjaXJjdW1mbGV4dW5pMDEzNkxhY3V0ZUxjYXJvbnVuaTAxM0JOYWN1dGVOY2Fyb251bmkwMTQ1T2h1bmdhcnVtbGF1dE9tYWNyb25SYWN1dGVSY2Fyb251bmkwMTU2U2FjdXRldW5pQTc4QlNjZWRpbGxhU2NpcmN1bWZsZXh1bmkwMjE4dW5pMUU5RVRjYXJvbnVuaTAxNjJ1bmkwMjFBVWJyZXZlVWh1bmdhcnVtbGF1dFVtYWNyb25Vb2dvbmVrVXJpbmdVdGlsZGVXYWN1dGVXY2lyY3VtZmxleFdkaWVyZXNpc1dncmF2ZVljaXJjdW1mbGV4WWdyYXZldW5pMUVGOFphY3V0ZVpkb3RhY2NlbnR1bmkwMTNCLmxvY2xNQUh1bmkwMTQ1LmxvY2xNQUhSLnNzMDRSYWN1dGUuc3MwNFJjYXJvbi5zczA0dW5pMDE1Ni5zczA0SS5zczA1SWFjdXRlLnNzMDVJY2lyY3VtZmxleC5zczA1SWRpZXJlc2lzLnNzMDVJZG90YWNjZW50LnNzMDVJZ3JhdmUuc3MwNUltYWNyb24uc3MwNUlvZ29uZWsuc3MwNUl0aWxkZS5zczA1Ry5zczA2R2JyZXZlLnNzMDZHY2lyY3VtZmxleC5zczA2dW5pMDEyMi5zczA2R2RvdGFjY2VudC5zczA2dW5pMUUyMC5zczA2QWRpZXJlc2lzLnNzMDhDZG90YWNjZW50LnNzMDhFZGllcmVzaXMuc3MwOEVkb3RhY2NlbnQuc3MwOEdkb3RhY2NlbnQuc3MwOElkaWVyZXNpcy5zczA4SWRvdGFjY2VudC5zczA4T2RpZXJlc2lzLnNzMDhVZGllcmVzaXMuc3MwOFdkaWVyZXNpcy5zczA4WWRpZXJlc2lzLnNzMDhaZG90YWNjZW50LnNzMDhJZGllcmVzaXMuc3MwNS5zczA4SWRvdGFjY2VudC5zczA1LnNzMDhHZG90YWNjZW50LnNzMDYuc3MwOEFfSS5kbGlnVV9JLmRsaWdhYnJldmV1bmkwMUNFYW1hY3JvbmFvZ29uZWtjYWN1dGVjY2Fyb25jY2lyY3VtZmxleGNkb3RhY2NlbnRkY2Fyb25kY3JvYXRlY2Fyb25lZG90YWNjZW50ZW1hY3JvbmVvZ29uZWt1bmkxRUJEdW5pMDI1OWdicmV2ZWdjaXJjdW1mbGV4dW5pMDEyM2dkb3RhY2NlbnR1bmkxRTIxaGJhcmhjaXJjdW1mbGV4aS5sb2NsVFJLaWppbWFjcm9uaW9nb25la2l0aWxkZXVuaTAyMzd1bmkwMDZBMDMwMWpjaXJjdW1mbGV4dW5pMDEzN2xhY3V0ZWxjYXJvbnVuaTAxM0NuYWN1dGVuY2Fyb251bmkwMTQ2b2h1bmdhcnVtbGF1dG9tYWNyb25yYWN1dGVyY2Fyb251bmkwMTU3c2FjdXRldW5pQTc4Q3NjZWRpbGxhc2NpcmN1bWZsZXh1bmkwMjE5dGNhcm9udW5pMDE2M3VuaTAyMUJ1YnJldmV1aHVuZ2FydW1sYXV0dW1hY3JvbnVvZ29uZWt1cmluZ3V0aWxkZXdhY3V0ZXdjaXJjdW1mbGV4d2RpZXJlc2lzd2dyYXZleWNpcmN1bWZsZXh5Z3JhdmV1bmkxRUY5emFjdXRlemRvdGFjY2VudHVuaTAxM0MubG9jbE1BSHVuaTAxNDYubG9jbE1BSGEuc3MwMWFhY3V0ZS5zczAxYWJyZXZlLnNzMDF1bmkwMUNFLnNzMDFhY2lyY3VtZmxleC5zczAxYWRpZXJlc2lzLnNzMDFhZ3JhdmUuc3MwMWFtYWNyb24uc3MwMWFvZ29uZWsuc3MwMWFyaW5nLnNzMDFhdGlsZGUuc3MwMWEuc3MwMmFhY3V0ZS5zczAyYWJyZXZlLnNzMDJ1bmkwMUNFLnNzMDJhY2lyY3VtZmxleC5zczAyYWRpZXJlc2lzLnNzMDJhZ3JhdmUuc3MwMmFtYWNyb24uc3MwMmFvZ29uZWsuc3MwMmFyaW5nLnNzMDJhdGlsZGUuc3MwMmwuc3MwM2xhY3V0ZS5zczAzbGNhcm9uLnNzMDN1bmkwMTNDLnNzMDNsc2xhc2guc3MwM2FkaWVyZXNpcy5zczA4Y2RvdGFjY2VudC5zczA4ZWRpZXJlc2lzLnNzMDhlZG90YWNjZW50LnNzMDhnZG90YWNjZW50LnNzMDhpLnNzMDhpZGllcmVzaXMuc3MwOGkubG9jbFRSSy5zczA4aWouc3MwOGlvZ29uZWsuc3MwOGouc3MwOG9kaWVyZXNpcy5zczA4dWRpZXJlc2lzLnNzMDh3ZGllcmVzaXMuc3MwOHlkaWVyZXNpcy5zczA4emRvdGFjY2VudC5zczA4YWRpZXJlc2lzLnNzMDEuc3MwOGFkaWVyZXNpcy5zczAyLnNzMDhmX2YubGlnYXRfdC5saWdhZmkubGlnYWZsLmxpZ2F1bmkwM0E5cGl1bmkyNEZGdW5pMjc3NnVuaTI3Nzd1bmkyNzc4dW5pMjc3OXVuaTI3N0F1bmkyNzdCdW5pMjc3Q3VuaTI3N0R1bmkyNzdFdW5pMjRFQXVuaTI0NjB1bmkyNDYxdW5pMjQ2MnVuaTI0NjN1bmkyNDY0dW5pMjQ2NXVuaTI0NjZ1bmkyNDY3dW5pMjQ2OHplcm8uc3MwOW9uZS5zczA5emVyby50Zm9uZS50ZnR3by50ZnRocmVlLnRmZm91ci50ZmZpdmUudGZzaXgudGZzZXZlbi50ZmVpZ2h0LnRmbmluZS50ZnVuaTIxNTN1bmkyMTU0dW5pMjE1NXVuaTIwODB1bmkyMDgxdW5pMjA4MnVuaTIwODN1bmkyMDg0dW5pMjA4NXVuaTIwODZ1bmkyMDg3dW5pMjA4OHVuaTIwODl1bmkyMDcwdW5pMDBCOXVuaTAwQjJ1bmkwMEIzdW5pMjA3NHVuaTIwNzV1bmkyMDc2dW5pMjA3N3VuaTIwNzh1bmkyMDc5dW5pMDBBMHVuaTMwMDJoeXBoZW5faHlwaGVuX2h5cGhlbl9ncmVhdGVyLmxpZ2FoeXBoZW5faHlwaGVuX2dyZWF0ZXIubGlnYWh5cGhlbl9ncmVhdGVyLmxpZ2F1bmkzMDAzdW5pRkYwNnVuaUZGMEF1bmlGRjIwdW5pRkYzQ3VuaUZGMUF1bmlGRjBDdW5pRkYwMXVuaUZGMDN1bmlGRjA1dW5pRkYwRXVuaUZGMUZ1bmlGRjAydW5pRkYwN3VuaUZGMUJ1bmlGRjBGcGVyaW9kLnNzMDhjb2xvbi5zczA4c2VtaWNvbG9uLnNzMDhlbGxpcHNpcy5zczA4ZXhjbGFtLnNzMDhleGNsYW1kb3duLnNzMDhxdWVzdGlvbi5zczA4cXVlc3Rpb25kb3duLnNzMDhwZXJpb2RjZW50ZXJlZC5zczA4dW5pRkYzRnVuaUZGMUEuc3MwOHVuaUZGMDEuc3MwOHVuaUZGMEUuc3MwOHVuaUZGMUYuc3MwOHVuaUZGMUIuc3MwOHVuaTAwQUR1bmkzMDFDdW5pRkYwRHVuaTMwMDh1bmkzMDA5dW5pMzAxMHVuaTMwMTF1bmlGRjVCdW5pRkY1RHVuaTMwMEN1bmkzMDBEdW5pMzAwQXVuaTMwMEJ1bmkzMDE0dW5pMzAxNXVuaTMwMEV1bmkzMDBGdW5pMzAxNnVuaTMwMTd1bmlGRjNCdW5pRkYzRHVuaUZGMDh1bmlGRjA5dW5pMEUzRmxlc3NfaHlwaGVuLmxpZ2FsZXNzX2h5cGhlbl9oeXBoZW4ubGlnYWxlc3NfaHlwaGVuX2h5cGhlbl9oeXBoZW4ubGlnYWxlc3NfaHlwaGVuX2dyZWF0ZXIubGlnYXVuaTI2MzlzbWlsZWZhY2V1bmkyMTE3bWludXRlc2Vjb25kdW5pMjExNnVuaTIzQ0VFdXJvdW5pMjBCNHVuaTIwQkR1bmkyMEI5dW5pMjBBQW5vdGVxdWFsZ3JlYXRlcmVxdWFsbGVzc2VxdWFsYXBwcm94ZXF1YWxpbmZpbml0eWludGVncmFsdW5pMjIwNnByb2R1Y3RzdW1tYXRpb25yYWRpY2FscGFydGlhbGRpZmZ1bmkwMEI1YXJyb3d1cHVuaTIxOTdhcnJvd3JpZ2h0dW5pMjE5OGFycm93ZG93bnVuaTIxOTlhcnJvd2xlZnR1bmkyMTk2YXJyb3dib3RoYXJyb3d1cGRudW5pMjE5RHVuaTIxRTR1bmkyMUU1dW5pMjFBOXVuaTIxQUF1bmkyMUIwdW5pMjFCMXVuaTIxQjN1bmkyMUI0Y2FycmlhZ2VyZXR1cm51bmkyMUU3YXJyb3d1cC5zczA3dW5pMjE5Ny5zczA3YXJyb3dyaWdodC5zczA3dW5pMjE5OC5zczA3YXJyb3dkb3duLnNzMDd1bmkyMTk5LnNzMDdhcnJvd2xlZnQuc3MwN3VuaTIxOTYu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ClwHgggAClwH+ggAClwH+ggAClwH+ggAClwH+ggAClwH+ggAClwH+ggAClwH+ggAClwH+ggAAAAHiAAAAAAHiAAAAAAHiAAAAAAHjgeUAAAHjgeUAAAH+gfKAAAH+gfKAAAH+gfKAAAH+gfKAAAHmgegAAAH0AfWAAAH0AfWAAAH0AfWAAAH0AfWAAAH0AfWAAAIPAhCAAAIPAhCAAAIPAhCAAAIPAhCAAAIPAhCAAAIPAhCAAAIPAhCAAAHpgesAAAIPAhCAAAIPAhCAAAHsge4AAAHsge4AAAHsge4AAAHsge4AAAHvgfiAAAHvgfiAAAHvgfiAAAHvgfiAAAHvgfiAAAHvgfiAAAHxAmMAAAHxAmMAAAHxAmMAAAHxAmMCrYKvArCCrYKvArCCrYKvArCCrYKvArCCrYKvArCCrYKvArCCrYKvArCCrYKvArCCrYKvArCCrYKvArCCrYKvArCAAAIBggMAAAIBggMAAAIBggMAAAIBggMAAAIBggMAAAIEggYAAAIEggYAAAIEggYAAAIEggYAAAIEggYAAAIEggYAAAIHggkAAAIHggkAAAIHggkAAAIHggkAAAH+gfKAAAH0AfWAAAH3AfiAAAH3AfiAAAH3AfiAAAH3AfiCCoIMAg2CCoIMAg2CCoIMAg2CCoIMAg2CCoIMAg2CCoIMAg2CCoIMAg2CCoIMAg2CCoIMAg2AAAIPAhCAAAIPAhCAAAIPAhCAAAIPAhCAAAIPAhCAAAIPAhCCooKkAAAAAAIPAhCB+gH7gf0B+gH7gf0AAAIPAhCClwH+ggAClwH+ggAAAAIPAhCCrYKvArCAAAIBggMAAAIEggYAAAIHggkCCoIMAg2CCoIMAg2AAAIPAhCCXQJegmACXQJegmACXQJegmACXQJegmACXQJegmACXQJegmACXQJegmACXQJegmACXQJegmACXQJegmACXQJegmACEgITghUAAAJhgmMAAAJhgmMAAAJhgmMAAAJhgmMAAAJhgmMAAAJhgmMCPAI9gmMCPAI9gmMCPAI9gmMCPAI9gmMCPAI9gmMCPAI9gmMCPAI9gmMCPAI9gmMCPAI9gmMCPAI9gmMCFoIYAhmAAAI/AAAAAAI/AAAAAAI/AAAAAAI/AAAAAAI/AAAAAAI/AAAAAAIbAAAAAAIbAAAAAAIbAAACQ4JFAAACQ4JFAAA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BkBmd2lkBkBmd2lkBkBsaWdhBkZsaWdhBkZsaWdhBkZsaWdhBkZsaWdhBkZsaWdhBkZsaWdhBkZsaWdhBkZsaWdhBkZsaWdhBkZsaWdhBkZsaWdhBkZsb2NsBkxsb2NsBmRsb2NsBmRsb2NsBmRsb2NsBlJsb2NsBl5sb2NsBlhsb2NsBl5sb2NsBmRsb2NsBmRvcmRuBmpvcmRuBmpvcmRuBmpvcmRuBmpvcmRuBmpvcmRuBmpvcmRuBmpvcmRuBmpvcmRuBmpvcmRuBmpvcmRuBmpvcmRuBmpwbnVtBnJwbnVtBnJwbnVtBnJwbnVtBnJwbnVtBnJwbnVtBnJwbnVtBnJwbnVtBnJwbnVtBnJwbnVtBnJwbnVtBnJwbnVtBnJzaW5mBnhzaW5mBnhzaW5mBnhzaW5mBnhzaW5mBnhzaW5mBnhzaW5mBnhzaW5mBnhzaW5mBnhzaW5mBnhzaW5mBnhzaW5mBnhzczAxBn5zczAxBn5zczAxBn5zczAxBn5zczAxBn5zczAxBn5zczAxBn5zczAxBn5zczAxBn5zczAxBn5zczAxBn5zczAxBn5zczAyBohzczAyBohzczAyBohzczAyBohzczAyBohzczAyBohzczAyBohzczAyBohzczAyBohzczAyBohzczAyBohzczAyBohzczAzBpJzczAzBpJzczAzBpJzczAzBpJzczAzBpJzczAzBpJzczAzBpJzczAzBpJzczAzBpJzczAzBpJzczAzBpJzczAzBpJzczA0BpxzczA0BpxzczA0BpxzczA0BpxzczA0BpxzczA0BpxzczA0BpxzczA0BpxzczA0BpxzczA0BpxzczA0BpxzczA0BpxzczA1BqZzczA1BqZzczA1BqZzczA1BqZzczA1BqZzczA1BqZzczA1BqZzczA1BqZzczA1BqZzczA1BqZzczA1BqZzczA1BqZzczA2BrBzczA2BrBzczA2BrBzczA2BrBzczA2BrBzczA2BrBzczA2BrBzczA2BrBzczA2BrBzczA2BrBzczA2BrBzczA2BrBzczA3BrpzczA3BrpzczA3BrpzczA3BrpzczA3BrpzczA3BrpzczA3BrpzczA3BrpzczA3BrpzczA3BrpzczA3BrpzczA3BrpzczA4BsRzczA4BsRzczA4BsRzczA4BsRzczA4BsRzczA4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', + 'base64' + ); + } +}; diff --git a/src/assets/index.ts b/src/assets/index.ts index 306e5057..a618f1e4 100644 --- a/src/assets/index.ts +++ b/src/assets/index.ts @@ -1,3 +1,4 @@ export * from './Font'; export * from './AssetsFactory'; export * from './TemplateFactory'; +export * from './fonts/fonts'; diff --git a/src/components/LeaderboardBuilder.tsx b/src/components/LeaderboardBuilder.tsx new file mode 100644 index 00000000..df2e9704 --- /dev/null +++ b/src/components/LeaderboardBuilder.tsx @@ -0,0 +1,197 @@ +import { JSX, loadImage, StyleSheet } from '../helpers'; +import { ImageSource } from '../helpers'; +import { fixed } from '../helpers/utils'; +import { Builder } from '../templates'; + +const DefaultColors = { + Yellow: '#FFAA00', + Blue: '#009BD6', + Green: '#00D95F' +}; + +export interface LeaderboardProps { + background: ImageSource | null; + backgroundColor: string; + header?: { + title: string; + subtitle: string; + image: ImageSource; + }; + players: { + displayName: string; + username: string; + level: number; + xp: number; + rank: number; + avatar: ImageSource; + }[]; +} + +const Crown = () => { + return ( + + + + ); +}; + +const MAX_RENDER_HEIGHT = 1080; +const MIN_RENDER_HEIGHT = 1000; + +export class LeaderboardBuilder extends Builder { + public constructor() { + super(500, MIN_RENDER_HEIGHT); + + this.bootstrap({ + background: null, + backgroundColor: '#7c563c', + players: [] + }); + + this.setStyle({ + borderRadius: '1.5rem' + }); + } + + public setBackground(background: ImageSource) { + this.options.set('background', background); + return this; + } + + public setBackgroundColor(color: string) { + this.options.set('backgroundColor', color); + return this; + } + + public setHeader(data: LeaderboardProps['header'] & {}) { + this.options.set('header', data); + return this; + } + + public setPlayers(players: LeaderboardProps['players']) { + const items = players.slice(0, 10); + this.options.set('players', items); + + if (items.length <= 7) { + this.height = MIN_RENDER_HEIGHT; + } else if (items.length > 7) { + this.height = MAX_RENDER_HEIGHT; + } + + this.adjustCanvas(); + + return this; + } + + public async render() { + const options = this.options.getOptions(); + + let background, headerImg; + + if (options.background) { + background = await loadImage(options.background); + } + + if (options.header) { + headerImg = await loadImage(options.header.image); + } + + const winners = [options.players[1], options.players[0], options.players[2]].filter(Boolean); + + return ( +
+ {background && } +
+ {options.header && headerImg ? ( +
+ +

{options.header.title}

+

{options.header.subtitle}

+
+ ) : null} +
+ {await Promise.all(winners.map((winner) => this.renderTop(winner)))} +
+ {this.renderPlayers( + await Promise.all(options.players.filter((f) => !winners.includes(f)).map((m) => this.renderPlayer(m))) + )} +
+
+ ); + } + + public renderPlayers(players: JSX.Element[]) { + return
{players}
; + } + + public async renderTop({ avatar, displayName, level, rank, username, xp }: LeaderboardProps['players'][number]) { + const image = await loadImage(avatar); + const currentColor = DefaultColors[rank === 1 ? 'Yellow' : rank === 2 ? 'Blue' : 'Green']; + const crown = rank === 1; + + return ( +
+ {crown && ( +
+ +
+ )} +
+ +
+ {rank} +
+
+
+

{displayName}

+

@{username}

+

Level {level}

+

{fixed(xp)} XP

+
+
+ ); + } + + public async renderPlayer({ avatar, displayName, level, rank, username, xp }: LeaderboardProps['players'][number]) { + const image = await loadImage(avatar); + + return ( +
+
+
+

{rank}

+

Rank

+
+ +
+

{displayName}

+

@{username}

+
+
+
+

Level {level}

+

{fixed(xp)} XP

+
+
+ ); + } +} diff --git a/src/components/RankCardBuilder.tsx b/src/components/RankCardBuilder.tsx new file mode 100644 index 00000000..3ba89500 --- /dev/null +++ b/src/components/RankCardBuilder.tsx @@ -0,0 +1,329 @@ +import { Font, FontFactory } from '../assets'; +import { CSSPropertiesLike, ImageSource, JSX, loadImage, StyleSheet } from '../helpers'; +import { fixed, getDefaultFont } from '../helpers/utils'; +import { Builder } from '../templates/Builder'; + +type StatusType = 'online' | 'idle' | 'dnd' | 'invisible'; + +interface RankCardBuilderProps { + avatar: ImageSource | null; + style: CSSPropertiesLike | null; + fonts: Partial<{ + username: string; + progress: string; + stats: string; + }>; + status: StatusType; + currentXP: number; + requiredXP: number; + username: string; + displayName: string; + discriminator: string; + level: number; + rank: number; + background: ImageSource; + tw: { + username: string; + discriminator: string; + displayName: string; + level: string; + rank: string; + xp: string; + progress: { + track: string; + thumb: string; + }; + overlay: string; + percentage: string; + avatar: string; + status: string; + }; + renders: { + avatar: boolean; + background: boolean; + level: boolean; + rank: boolean; + status: boolean; + username: boolean; + displayName: boolean; + discriminator: boolean; + progress: boolean; + xp: boolean; + progressbar: boolean; + constants: { + rank: string; + level: string; + xp: string; + statusColors: { + LightGray: string; + Gray: string; + DarkGray: string; + White: string; + Green: string; + Yellow: string; + Red: string; + Blue: string; + }; + }; + }; +} + +export class RankCardBuilder extends Builder { + public constructor() { + super(2000, 512); + + this.bootstrap({ + avatar: null, + style: null, + tw: { + username: '', + discriminator: '', + displayName: '', + level: '', + rank: '', + xp: '', + progress: { + track: '', + thumb: '' + }, + overlay: '', + percentage: '', + avatar: '', + status: '' + }, + level: 0, + rank: 0, + username: '', + displayName: '', + discriminator: '', + currentXP: 0, + requiredXP: 0, + status: 'invisible', + background: '', + fonts: {}, + renders: { + constants: { + rank: 'RANK', + level: 'LEVEL', + xp: 'XP', + statusColors: { + LightGray: '#A0A1A3', + Gray: '#474B4E', + DarkGray: '#272A2D', + White: '#FFFFFF', + Green: '#22A559', + Yellow: '#F0B332', + Red: '#F24043', + Blue: '#8ACDFF' + } + }, + avatar: true, + background: true, + level: true, + rank: true, + status: true, + username: true, + discriminator: true, + progress: true, + xp: true, + progressbar: true, + displayName: true + } + }); + } + + public setFonts(fontConfig: Required) { + this.options.set('fonts', fontConfig); + return this; + } + + public setAvatar(image: ImageSource) { + this.options.set('avatar', image); + return this; + } + + public setBackground(image: ImageSource) { + this.options.set('background', image); + return this; + } + + public setStatus(status: StatusType) { + this.options.set('status', status); + return this; + } + + public setUsername(name: string) { + this.options.set('username', name); + return this; + } + + public setDisplayName(name: string) { + this.options.set('displayName', name); + return this; + } + + public setDiscriminator(discriminator: string) { + this.options.set('discriminator', discriminator); + return this; + } + + public setCurrentXP(xp: number) { + this.options.set('currentXP', xp); + return this; + } + + public setRequiredXP(xp: number) { + this.options.set('requiredXP', xp); + return this; + } + + public setLevel(level: number) { + this.options.set('level', level); + return this; + } + + public setRank(rank: number) { + this.options.set('rank', rank); + return this; + } + + public configureRenderer(config: Partial) { + this.options.merge('renders', config); + return this; + } + + public async render() { + const options = this.options.getOptions(); + + if (!options.avatar) throw new Error('Avatar is required.'); + if (!FontFactory.size) throw new Error('No fonts are loaded.'); + + const avatar = await loadImage(options.avatar); + + let background; + if (options.background) { + background = await loadImage(options.background); + } + + const firstFont = getDefaultFont(); + + if (firstFont) { + options.fonts.username ??= firstFont.name; + options.fonts.progress ??= firstFont.name; + options.fonts.stats ??= firstFont.name; + } + + const { currentXP: xp, requiredXP, status, level, rank } = options; + const username = options.username || options.discriminator; + const displayName = options.displayName || options.username; + + const percentage = ((xp / requiredXP) * 100).toFixed(0); + const config = options.renders; + const tws = options.tw; + const colors = config.constants.statusColors; + + const statusColor = + status === 'online' + ? colors.Green + : status === 'idle' + ? colors.Yellow + : status === 'dnd' + ? colors.Red + : colors.Gray; + + return ( +
+
+
+ {config.avatar ? ( + <> + avatar + {config.status ? ( +
+ ) : null} + + ) : null} +
+
+
+
+ {config.displayName && ( +

+ {displayName} +

+ )} + {username && ( +

+ @{username} +

+ )} +
+ {config.progress &&

{percentage}%

} +
+ {config.progressbar && ( +
+
+
+ )} +
+ {config.level && ( +

+ {config.constants.level}: + {level} +

+ )} + {config.xp && ( +

+ {config.constants.xp}: + + {fixed(xp)}/{fixed(requiredXP)} + +

+ )} + {config.rank && ( +

+ {config.constants.rank}: + #{rank} +

+ )} +
+
+
+
+ ); + } +} diff --git a/src/components/index.ts b/src/components/index.ts new file mode 100644 index 00000000..5ad8a64e --- /dev/null +++ b/src/components/index.ts @@ -0,0 +1,2 @@ +export * from './LeaderboardBuilder'; +export * from './RankCardBuilder'; diff --git a/src/fabric/ContainerNode.tsx b/src/fabric/ContainerNode.tsx deleted file mode 100644 index 54bd4d78..00000000 --- a/src/fabric/ContainerNode.tsx +++ /dev/null @@ -1,18 +0,0 @@ -import { Node, NodeProps } from './Node'; -import { Element, JSX, render } from '../helpers'; - -export class ContainerNode extends Node { - public toElement(): Element { - return ( -
- {render(this.children as unknown[])} -
- ); - } -} - -export function Container(props: NodeProps) { - const node = new ContainerNode(props); - - return node.toElement(); -} diff --git a/src/fabric/ImageNode.tsx b/src/fabric/ImageNode.tsx deleted file mode 100644 index d9d3c874..00000000 --- a/src/fabric/ImageNode.tsx +++ /dev/null @@ -1,30 +0,0 @@ -import { Node, NodeProps } from './Node'; -import { JSX } from '../helpers'; -import { CanvacordImage } from '../helpers/image'; - -export interface ImageNodeProps { - src: CanvacordImage; - alt?: string; - width?: number; - height?: number; -} - -export class ImageNode extends Node { - public toElement(): JSX.Element { - return ( - {this.getProperty('alt')} - ); - } -} - -export function Image(props: NodeProps) { - const node = new ImageNode(props); - return node.toElement(); -} diff --git a/src/fabric/Node.tsx b/src/fabric/Node.tsx deleted file mode 100644 index 54c13467..00000000 --- a/src/fabric/Node.tsx +++ /dev/null @@ -1,41 +0,0 @@ -import type { CSSProperties } from 'react'; -import { Element, JSX, render } from '../helpers/jsx'; - -export interface NodeProperties { - style?: CSSProperties; - children?: Node | Element | Node[] | Element[]; - tw?: string; -} - -export type NodeProps = NodeProperties & T; - -export class Node { - public constructor(public props: NodeProps) { - this.props.style ??= {}; - this.props.style.display ??= 'flex'; - } - - public get children() { - return this.getProperty('children'); - } - - public get style() { - return this.props.style || {}; - } - - public set style(style: CSSProperties) { - this.props.style = style; - } - - public getProperty>(propertyName: K): NodeProps[K] { - return this.props[propertyName]; - } - - public setProperty>(propertyName: K, value: NodeProps[K]) { - this.props[propertyName] = value; - } - - public toElement(): Element { - return <>{render(this.children as unknown[])}; - } -} diff --git a/src/fabric/TextNode.tsx b/src/fabric/TextNode.tsx deleted file mode 100644 index 0563e20a..00000000 --- a/src/fabric/TextNode.tsx +++ /dev/null @@ -1,34 +0,0 @@ -import { Node, NodeProps } from './Node'; -import { JSX } from '../helpers/jsx'; - -export interface TextNodeProps { - data: string; -} - -export class TextNode extends Node { - public setValue(newValue: string) { - this.setProperty('data', newValue); - } - - public get value() { - return this.getProperty('data'); - } - - public set value(value: string) { - this.setValue(value); - } - - public toElement() { - return ( -

- {this.getProperty('data')} -

- ); - } -} - -export function Text(props: NodeProps) { - const node = new TextNode(props); - - return node.toElement(); -} diff --git a/src/fabric/index.ts b/src/fabric/index.ts deleted file mode 100644 index 1a8bbff7..00000000 --- a/src/fabric/index.ts +++ /dev/null @@ -1,4 +0,0 @@ -export * from './Node'; -export * from './TextNode'; -export * from './ImageNode'; -export * from './ContainerNode'; diff --git a/src/helpers/image.ts b/src/helpers/image.ts index 20503757..ad276312 100644 --- a/src/helpers/image.ts +++ b/src/helpers/image.ts @@ -1,22 +1,42 @@ -// import { renderAsync } from '@resvg/resvg-js'; +import { renderAsync, type ResvgRenderOptions } from '@resvg/resvg-js'; import { EncodingFormat } from '../canvas/Encodable'; import { AvifConfig, PngEncodeOptions, Transformer } from '@napi-rs/image'; export type RenderSvgOptions = PngEncodeOptions | AvifConfig | number | null; -export async function renderSvg( - svg: string, - format: EncodingFormat, - options?: RenderSvgOptions, - signal?: AbortSignal | null -): Promise { - const transformer = Transformer.fromSvg(svg); +export async function renderSvg({ + svg, + format, + options, + signal +}: { + svg: string; + format: EncodingFormat; + options?: RenderSvgOptions; + signal?: AbortSignal | null; +}): Promise { + const opts: ResvgRenderOptions = { + font: { + loadSystemFonts: false + }, + logLevel: 'off' + }; + + // Transformer.fromSvg gives weird output for some reason + const output = await renderAsync(svg, opts); + + if (format === 'png') { + return output.asPng(); + } + + const transformer = Transformer.fromRgbaPixels(output.pixels, output.width, output.height); + options ??= null; signal ??= null; switch (format) { - case 'png': - return transformer.png(options as PngEncodeOptions, signal); + // case 'png': + // return transformer.png(options as PngEncodeOptions, signal); case 'avif': return transformer.avif(options as AvifConfig, signal); case 'jpeg': diff --git a/src/helpers/jsx.ts b/src/helpers/jsx.ts index 888fc7c5..ff7da808 100644 --- a/src/helpers/jsx.ts +++ b/src/helpers/jsx.ts @@ -1,6 +1,10 @@ import type * as React from 'react'; -import { Node } from '../fabric'; import { performObjectCleanup, StyleSheet } from './StyleSheet'; +import { Node } from '..'; + +const isNode = (node: unknown): node is Node => { + return typeof node === 'object' && node != null && 'toElement' in node; +}; export type ElementInit = { type: string; @@ -33,17 +37,14 @@ export const JSX = { createElement(type: string | Element, props: Record, ...children: Element[]): Element { if (type instanceof Element) return type; + props ??= {}; + // monkey-patch layout issues if ('className' in props) props.tw ??= props.className; if (type === 'div') { - if ('tw' in props) { + if (!('tw' in props) && !('style' in props)) { props.tw = StyleSheet.cn('flex flex-col content-start shrink-0', props.tw as string); - } else if ('style' in props) { - props.style = StyleSheet.compose( - { display: 'flex', flexDirection: 'column', alignContent: 'flex-start', flexShrink: 0 }, - props.style as Record - ); } } @@ -66,7 +67,7 @@ export function render(components: (Node | Element | unknown)[]) { .map((component) => { if (component == null) return []; if (component instanceof Element) return component; - if (component instanceof Node) return component.toElement(); + if (isNode(component)) return component.toElement(); const child = String(component) as unknown as Element; return JSX.createElement('span', { children: child }, child); diff --git a/src/helpers/utils.ts b/src/helpers/utils.ts new file mode 100644 index 00000000..38d10264 --- /dev/null +++ b/src/helpers/utils.ts @@ -0,0 +1,10 @@ +import { Font, FontFactory } from '../assets'; + +export const fixed = (v: number) => { + const formatter = new Intl.NumberFormat('en-US', { notation: 'compact' }); + return formatter.format(v); +}; + +export const getDefaultFont = () => { + return (FontFactory.values().next().value ?? null) as Font | null; +}; diff --git a/src/index.ts b/src/index.ts index 31c309a6..40365a4e 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,5 +1,5 @@ export * from './assets'; -export * from './fabric'; +export * from './components'; export * from './helpers'; export * from './templates'; export * from './canvas'; diff --git a/src/templates/Builder.tsx b/src/templates/Builder.tsx index 0f53cbdd..a4e8efa8 100644 --- a/src/templates/Builder.tsx +++ b/src/templates/Builder.tsx @@ -1,10 +1,10 @@ -import { CSSProperties } from 'react'; +import type { CSSProperties } from 'react'; import satori, { SatoriOptions } from 'satori'; import { FontFactory } from '../assets/AssetsFactory'; -import { Node } from '../fabric/Node'; import { CSSPropertiesLike, StyleSheet } from '../helpers'; import { renderSvg, RenderSvgOptions } from '../helpers/image'; import { JSX, Element } from '../helpers/jsx'; +import { BuilderOptionsManager } from './BuilderOptionsManager'; export interface BuilderTemplate { components: Array; @@ -21,17 +21,32 @@ export type BuilderBuildOptions = { signal?: AbortSignal; } & SatoriOptions; -export class Builder { +export interface Node { + toElement(): Element; +} + +export class Builder = Record> { #style: CSSPropertiesLike = {}; + public tw: string = ''; public components = new Array(); + public options = new BuilderOptionsManager(); - public constructor(public readonly width: number, public readonly height: number) { + public constructor(public width: number, public height: number) { + this.adjustCanvas(); + } + + public bootstrap(data: T) { + this.options.setOptions(data); + } + + public adjustCanvas() { this.#style = StyleSheet.create({ root: { width: `${this.width}px`, height: `${this.height}px` } }); + return this; } public get style() { @@ -51,7 +66,7 @@ export class Builder { } public setStyle(newStyle: CSSProperties) { - StyleSheet.compose(this.#style.root, newStyle); + StyleSheet.compose(this.#style.root || {}, newStyle || {}); return this; } @@ -60,7 +75,7 @@ export class Builder { .map((component) => { if (component == null) return []; if (component instanceof Element) return component; - if (component instanceof Node) return component.toElement(); + if (component.toElement) return component.toElement(); return {String(component)}; }) .flat(1); @@ -73,15 +88,25 @@ export class Builder { public async build(options: Partial = {}) { options.format ??= 'png'; - const svg = await satori(await this.render(), { + const fonts = Array.from(FontFactory.values()).map((font) => font.getData()); + const element = await this.render(); + + const svg = await satori(element, { + ...options, height: this.height, width: this.width, - fonts: Array.from(FontFactory.values()).map((font) => font.getData()), - embedFont: true, - ...options + fonts, + embedFont: true }); - return options?.format === 'svg' ? svg : renderSvg(svg, options.format, options.options, options.signal); + return options?.format === 'svg' + ? svg + : renderSvg({ + svg, + format: options.format, + options: options.options, + signal: options.signal + }); } public static from(template: BuilderTemplate) { diff --git a/src/templates/BuilderOptionsManager.ts b/src/templates/BuilderOptionsManager.ts new file mode 100644 index 00000000..920735d5 --- /dev/null +++ b/src/templates/BuilderOptionsManager.ts @@ -0,0 +1,23 @@ +export class BuilderOptionsManager> { + constructor(private options: T = {} as T) {} + + public getOptions(): T { + return this.options; + } + + public setOptions(options: T): void { + this.options = options; + } + + public get(key: K): T[K] { + return this.options[key]; + } + + public set(key: K, value: T[K]): void { + this.options[key] = value; + } + + public merge(key: K, value: Partial): void { + this.options[key] = { ...this.options[key], ...value }; + } +} diff --git a/src/templates/RankCardBuilder.tsx b/src/templates/RankCardBuilder.tsx deleted file mode 100644 index 657032f0..00000000 --- a/src/templates/RankCardBuilder.tsx +++ /dev/null @@ -1,585 +0,0 @@ -import { Font, FontFactory } from '../assets'; -import { Container, Image, Text } from '../fabric'; -import { CSSPropertiesLike, ImageSource, JSX, loadImage, StyleSheet } from '../helpers'; -import { Builder } from './Builder'; - -type StatusType = 'online' | 'idle' | 'dnd' | 'invisible'; - -interface CanvacordRankCardBuilderState { - avatar: ImageSource | null; - style: CSSPropertiesLike | null; - fonts: Partial<{ - username: string; - progress: string; - stats: string; - }>; - status: StatusType; - currentXP: number; - requiredXP: number; - username: string; - displayName: string; - discriminator: string; - level: number; - rank: number; - background: ImageSource; - variant: RankCardVariant; - tw: { - username: string; - discriminator: string; - displayName: string; - level: string; - rank: string; - xp: string; - progress: { - track: string; - thumb: string; - }; - overlay: string; - percentage: string; - avatar: string; - status: string; - }; - renders: { - avatar: boolean; - background: boolean; - level: boolean; - rank: boolean; - status: boolean; - username: boolean; - displayName: boolean; - discriminator: boolean; - progress: boolean; - xp: boolean; - progressbar: boolean; - constants: { - rank: string; - level: string; - xp: string; - statusColors: { - LightGray: string; - Gray: string; - DarkGray: string; - White: string; - Green: string; - Yellow: string; - Red: string; - Blue: string; - }; - }; - }; -} - -const createDefaultCSS = (config: CanvacordRankCardBuilderState) => { - const colors = { - LightGray: '#A0A1A3', - Gray: '#474B4E', - DarkGray: '#272A2D', - White: '#FFFFFF', - Green: '#22A559', - Yellow: '#F0B332', - Red: '#F24043', - Blue: '#8ACDFF' - }; - - const baseStyle = StyleSheet.create({ - text: { - color: colors.White, - lineHeight: '10%' - }, - progress: { - borderRadius: '20px', - height: '29px', - width: '591px' - } - }); - - const styles = StyleSheet.create({ - root: { - backgroundColor: colors.Gray, - display: 'flex', - alignItems: 'center', - justifyContent: 'center' - }, - overlay: { - backgroundColor: colors.DarkGray, - borderRadius: '10px', - height: 208, - width: 809, - display: 'flex', - flexDirection: 'column' - }, - avatar: { - width: '144px', - height: '144px', - borderRadius: '50%', - border: '6px solid' - }, - username: StyleSheet.compose( - { - display: 'flex', - alignItems: 'center', - justifyContent: 'center', - fontWeight: 'bold', - fontSize: '36px', - marginBottom: '30px', - fontFamily: config.fonts.username - }, - baseStyle.text - ), - discriminator: { - fontSize: '30px', - color: colors.LightGray, - marginBottom: '-5px', - marginLeft: '5px' - }, - progress: StyleSheet.compose( - { - fontWeight: 'lighter', - fontSize: '24px', - fontFamily: config.fonts.progress - }, - baseStyle.text - ), - stats: StyleSheet.compose( - { - textTransform: 'uppercase', - fontSize: '32px', - fontWeight: 'bold', - marginRight: '2rem', - lineHeight: '10%', - fontFamily: config.fonts.stats - }, - baseStyle.text - ), - progressbarTrack: StyleSheet.compose( - { - backgroundColor: colors.Gray - }, - baseStyle.progress - ), - progressbarThumb: { - backgroundColor: colors.Blue, - width: `${(config.currentXP / config.requiredXP) * 100}%`, - borderRadius: '20px' - }, - statsContainer: { - display: 'flex', - flexDirection: 'row-reverse', - marginTop: '1rem' - }, - statsSection: { - display: 'flex', - gap: '0.75rem', - alignItems: 'center' - }, - body: { - display: 'flex', - marginLeft: '1rem', - gap: '1.5rem', - alignItems: 'center', - position: 'absolute', - marginTop: '1.8rem' - }, - bodyContent: { - display: 'flex', - alignItems: 'center', - flexDirection: 'column', - marginTop: '2rem' - }, - infoContainer: { - display: 'flex', - flexDirection: 'row', - justifyContent: 'space-between', - alignItems: 'center', - width: '100%' - }, - progressContainer: { - marginTop: '0.3rem' - } - }); - - return styles; -}; - -export type RankCardVariant = 'classic' | 'modern'; - -export class RankCardBuilder extends Builder { - #data: CanvacordRankCardBuilderState = { - avatar: null, - style: null, - tw: { - username: '', - discriminator: '', - displayName: '', - level: '', - rank: '', - xp: '', - progress: { - track: '', - thumb: '' - }, - overlay: '', - percentage: '', - avatar: '', - status: '' - }, - level: 0, - rank: 0, - username: '', - displayName: '', - discriminator: '', - currentXP: 0, - requiredXP: 0, - status: 'invisible', - background: '', - fonts: { - username: undefined, - stats: undefined, - progress: undefined - }, - variant: 'modern', - renders: { - constants: { - rank: 'RANK', - level: 'LEVEL', - xp: 'XP', - statusColors: { - LightGray: '#A0A1A3', - Gray: '#474B4E', - DarkGray: '#272A2D', - White: '#FFFFFF', - Green: '#22A559', - Yellow: '#F0B332', - Red: '#F24043', - Blue: '#8ACDFF' - } - }, - avatar: true, - background: true, - level: true, - rank: true, - status: true, - username: true, - discriminator: true, - progress: true, - xp: true, - progressbar: true, - displayName: true - } - }; - - public constructor() { - super(832, 228); - } - - public get style() { - return this.#data.style || {}; - } - - public setStyle(style: CSSPropertiesLike) { - this.#data.style = style; - return this; - } - - public setVariant(variant: RankCardVariant) { - this.#data.variant = variant; - return this; - } - - public setFonts(fontConfig: Required) { - this.#data.fonts = fontConfig; - return this; - } - - public setAvatar(image: ImageSource) { - this.#data.avatar = image; - return this; - } - - public setBackground(image: ImageSource) { - this.#data.background = image; - return this; - } - - public setStatus(status: StatusType) { - this.#data.status = status; - return this; - } - - public setUsername(name: string) { - this.#data.username = name; - return this; - } - - public setDisplayName(name: string) { - this.#data.displayName = name; - return this; - } - - public setDiscriminator(discrim: string) { - this.#data.discriminator = discrim; - return this; - } - - public setCurrentXP(xp: number) { - this.#data.currentXP = xp; - return this; - } - - public setRequiredXP(xp: number) { - this.#data.requiredXP = xp; - return this; - } - - public setLevel(level: number) { - this.#data.level = level; - return this; - } - - public setRank(rank: number) { - this.#data.rank = rank; - return this; - } - - public configureRenderer(config: Partial) { - this.#data.renders = { ...this.#data.renders, ...config }; - return this; - } - - private async renderClassic() { - if (!this.#data.avatar) throw new Error('Avatar is required.'); - if (!FontFactory.size) throw new Error('No fonts are loaded.'); - - const firstFont = FontFactory.values().next().value as Font; - const avatar = await loadImage(this.#data.avatar); - - let background; - if (this.#data.background) { - background = await loadImage(this.#data.background); - } - - this.#data.fonts.username ??= firstFont.name; - this.#data.fonts.progress ??= firstFont.name; - this.#data.fonts.stats ??= firstFont.name; - - this.#data.style ??= createDefaultCSS(this.#data); - - const { status, renders } = this.#data; - - const colors = renders.constants.statusColors; - - const avatarBorderColor = - status === 'online' - ? colors.Green - : status === 'idle' - ? colors.Yellow - : status === 'dnd' - ? colors.Red - : colors.Gray; - - return ( - - - {background ? : <>} - - - - - - - - - - - - - - -

- {this.#data.username} - - {this.#data.discriminator ? `#${this.#data.discriminator}` : ''} - -

-
- - - - -
- - - - - - -
-
-
-
- ); - } - - private async renderModern() { - if (!this.#data.avatar) throw new Error('Avatar is required.'); - if (!FontFactory.size) throw new Error('No fonts are loaded.'); - - const avatar = await loadImage(this.#data.avatar); - - let background; - if (this.#data.background) { - background = await loadImage(this.#data.background); - } - - const firstFont = FontFactory.values().next().value as Font; - - this.#data.fonts.username ??= firstFont.name; - this.#data.fonts.progress ??= firstFont.name; - this.#data.fonts.stats ??= firstFont.name; - - const fixed = (v: number) => { - const formatter = new Intl.NumberFormat('en-US', { notation: 'compact' }); - return formatter.format(v); - }; - - const { currentXP: xp, requiredXP, status, level, rank } = this.#data; - const username = this.#data.username || this.#data.discriminator; - const displayName = this.#data.displayName || this.#data.username; - - const percentage = ((xp / requiredXP) * 100).toFixed(0); - const config = this.#data.renders; - const tws = this.#data.tw; - const colors = config.constants.statusColors; - - const statusColor = - status === 'online' - ? colors.Green - : status === 'idle' - ? colors.Yellow - : status === 'dnd' - ? colors.Red - : colors.Gray; - - return ( -
-
-
- {config.avatar ? ( - <> - avatar - {config.status ? ( -
- ) : null} - - ) : null} -
-
-
-
- {config.displayName && ( -

- {displayName} -

- )} - {username && ( -

- @{username} -

- )} -
- {config.progress &&

{percentage}%

} -
- {config.progressbar && ( -
-
-
- )} -
- {config.level && ( -

- {config.constants.level}: - {level} -

- )} - {config.xp && ( -

- {config.constants.xp}: - - {fixed(xp)}/{fixed(requiredXP)} - -

- )} - {config.rank && ( -

- {config.constants.rank}: - #{rank} -

- )} -
-
-
-
- ); - } - - public async render() { - switch (this.#data.variant) { - case 'modern': - return this.renderModern(); - default: - return this.renderClassic(); - } - } -} diff --git a/src/templates/index.ts b/src/templates/index.ts index 10a88707..b4fa2dd5 100644 --- a/src/templates/index.ts +++ b/src/templates/index.ts @@ -1,2 +1,2 @@ export * from './Builder'; -export * from './RankCardBuilder'; +export * from './BuilderOptionsManager'; diff --git a/test/bg.png b/test/bg.png new file mode 100644 index 00000000..dde4650c Binary files /dev/null and b/test/bg.png differ diff --git a/test/index.ts b/test/index.ts index 7b3e58c3..b98c2862 100644 --- a/test/index.ts +++ b/test/index.ts @@ -4,7 +4,8 @@ import { manropeBold } from './common'; async function main() { const card = new RankCardBuilder() - .setUsername('@wumpus') + .setUsername('wumpus') + .setDisplayName('Wumpus') .setDiscriminator('1234') .setAvatar('https://cdn.discordapp.com/embed/avatars/0.png?size=256') .setCurrentXP(300) @@ -18,9 +19,13 @@ async function main() { username: manropeBold.name }); - card.build().then((data) => { - writeFileSync(`${__dirname}/normal/rankCard.png`, data); - }); + card + .build({ + format: 'png' + }) + .then((data) => { + writeFileSync(`${__dirname}/normal/rankCard.png`, data); + }); card .build({ diff --git a/test/leaderboard.png b/test/leaderboard.png new file mode 100644 index 00000000..4c1a6f03 Binary files /dev/null and b/test/leaderboard.png differ diff --git a/test/leaderboard.svg b/test/leaderboard.svg new file mode 100644 index 00000000..9f5ef5a8 --- /dev/null +++ b/test/leaderboard.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/test/leaderboard.ts b/test/leaderboard.ts new file mode 100644 index 00000000..974d0980 --- /dev/null +++ b/test/leaderboard.ts @@ -0,0 +1,104 @@ +import { Font, LeaderboardBuilder } from '../src'; +import { writeFileSync } from 'fs'; + +Font.loadDefault(); + +const lb = new LeaderboardBuilder() + .setHeader({ + title: 'NeplexLabs', + image: 'https://github.com/neplextech.png', + subtitle: '3258 members' + }) + .setPlayers([ + { + avatar: 'https://github.com/twlite.png', + username: 'twlite', + displayName: 'Archaeopteryx', + level: 32, + xp: 2420, + rank: 1 + }, + { + avatar: 'https://github.com/notunderctrl.png', + username: 'avrajs', + displayName: 'Avraj', + level: 30, + xp: 2390, + rank: 2 + }, + { + avatar: 'https://github.com/insypher.png', + username: 'insypher01', + displayName: 'insypher', + level: 29, + xp: 2280, + rank: 3 + }, + { + avatar: 'https://github.com/Luna-devv.png', + username: 'mwlica', + displayName: 'Luna', + level: 27, + xp: 2280, + rank: 4 + }, + { + avatar: 'https://github.com/insypher.png', + username: 'com6235', + displayName: 'CatGPT', + level: 24, + xp: 2280, + rank: 5 + }, + { + avatar: 'https://github.com/insypher.png', + username: 'talyzman', + displayName: 'Talisman', + level: 21, + xp: 2280, + rank: 6 + }, + { + avatar: 'https://github.com/insypher.png', + username: 'madaleine', + displayName: 'Madaleine Sakurai', + level: 20, + xp: 2280, + rank: 7 + }, + { + avatar: 'https://github.com/insypher.png', + username: 'tempest0006', + displayName: 'Tempest', + level: 17, + xp: 2280, + rank: 8 + }, + { + avatar: 'https://github.com/insypher.png', + username: 'rinceri', + displayName: 'bottle', + level: 16, + xp: 2280, + rank: 9 + }, + { + avatar: 'https://cdn.discordapp.com/embed/avatars/0.png', + username: 'mrcrack_', + displayName: 'MrCRACK', + level: 14, + xp: 2280, + rank: 10 + } + ]) + .setBackground(`${__dirname}/bg.png`); + +lb.build({ + format: 'svg' +}).then((res) => { + writeFileSync(`${__dirname}/leaderboard.svg`, res); +}); + +lb.build().then((res) => { + writeFileSync(`${__dirname}/leaderboard.png`, res); +}); diff --git a/test/normal/leaderboard.png b/test/normal/leaderboard.png new file mode 100644 index 00000000..83adfd09 Binary files /dev/null and b/test/normal/leaderboard.png differ diff --git a/test/normal/rankCard.jpg b/test/normal/rankCard.jpg new file mode 100644 index 00000000..187d3817 Binary files /dev/null and b/test/normal/rankCard.jpg differ diff --git a/test/normal/rankCard.png b/test/normal/rankCard.png index c4166213..8c9ed186 100644 Binary files a/test/normal/rankCard.png and b/test/normal/rankCard.png differ diff --git a/test/normal/rankCard.svg b/test/normal/rankCard.svg index 8d5b27ff..67daaf2a 100644 --- a/test/normal/rankCard.svg +++ b/test/normal/rankCard.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/yarn.lock b/yarn.lock index 0db4430c..74116f23 100644 --- a/yarn.lock +++ b/yarn.lock @@ -721,6 +721,135 @@ __metadata: languageName: node linkType: hard +"@resvg/resvg-js-android-arm-eabi@npm:2.6.0": + version: 2.6.0 + resolution: "@resvg/resvg-js-android-arm-eabi@npm:2.6.0" + conditions: os=android & cpu=arm + languageName: node + linkType: hard + +"@resvg/resvg-js-android-arm64@npm:2.6.0": + version: 2.6.0 + resolution: "@resvg/resvg-js-android-arm64@npm:2.6.0" + conditions: os=android & cpu=arm64 + languageName: node + linkType: hard + +"@resvg/resvg-js-darwin-arm64@npm:2.6.0": + version: 2.6.0 + resolution: "@resvg/resvg-js-darwin-arm64@npm:2.6.0" + conditions: os=darwin & cpu=arm64 + languageName: node + linkType: hard + +"@resvg/resvg-js-darwin-x64@npm:2.6.0": + version: 2.6.0 + resolution: "@resvg/resvg-js-darwin-x64@npm:2.6.0" + conditions: os=darwin & cpu=x64 + languageName: node + linkType: hard + +"@resvg/resvg-js-linux-arm-gnueabihf@npm:2.6.0": + version: 2.6.0 + resolution: "@resvg/resvg-js-linux-arm-gnueabihf@npm:2.6.0" + conditions: os=linux & cpu=arm + languageName: node + linkType: hard + +"@resvg/resvg-js-linux-arm64-gnu@npm:2.6.0": + version: 2.6.0 + resolution: "@resvg/resvg-js-linux-arm64-gnu@npm:2.6.0" + conditions: os=linux & cpu=arm64 & libc=glibc + languageName: node + linkType: hard + +"@resvg/resvg-js-linux-arm64-musl@npm:2.6.0": + version: 2.6.0 + resolution: "@resvg/resvg-js-linux-arm64-musl@npm:2.6.0" + conditions: os=linux & cpu=arm64 & libc=musl + languageName: node + linkType: hard + +"@resvg/resvg-js-linux-x64-gnu@npm:2.6.0": + version: 2.6.0 + resolution: "@resvg/resvg-js-linux-x64-gnu@npm:2.6.0" + conditions: os=linux & cpu=x64 & libc=glibc + languageName: node + linkType: hard + +"@resvg/resvg-js-linux-x64-musl@npm:2.6.0": + version: 2.6.0 + resolution: "@resvg/resvg-js-linux-x64-musl@npm:2.6.0" + conditions: os=linux & cpu=x64 & libc=musl + languageName: node + linkType: hard + +"@resvg/resvg-js-win32-arm64-msvc@npm:2.6.0": + version: 2.6.0 + resolution: "@resvg/resvg-js-win32-arm64-msvc@npm:2.6.0" + conditions: os=win32 & cpu=arm64 + languageName: node + linkType: hard + +"@resvg/resvg-js-win32-ia32-msvc@npm:2.6.0": + version: 2.6.0 + resolution: "@resvg/resvg-js-win32-ia32-msvc@npm:2.6.0" + conditions: os=win32 & cpu=ia32 + languageName: node + linkType: hard + +"@resvg/resvg-js-win32-x64-msvc@npm:2.6.0": + version: 2.6.0 + resolution: "@resvg/resvg-js-win32-x64-msvc@npm:2.6.0" + conditions: os=win32 & cpu=x64 + languageName: node + linkType: hard + +"@resvg/resvg-js@npm:^2.6.0": + version: 2.6.0 + resolution: "@resvg/resvg-js@npm:2.6.0" + dependencies: + "@resvg/resvg-js-android-arm-eabi": 2.6.0 + "@resvg/resvg-js-android-arm64": 2.6.0 + "@resvg/resvg-js-darwin-arm64": 2.6.0 + "@resvg/resvg-js-darwin-x64": 2.6.0 + "@resvg/resvg-js-linux-arm-gnueabihf": 2.6.0 + "@resvg/resvg-js-linux-arm64-gnu": 2.6.0 + "@resvg/resvg-js-linux-arm64-musl": 2.6.0 + "@resvg/resvg-js-linux-x64-gnu": 2.6.0 + "@resvg/resvg-js-linux-x64-musl": 2.6.0 + "@resvg/resvg-js-win32-arm64-msvc": 2.6.0 + "@resvg/resvg-js-win32-ia32-msvc": 2.6.0 + "@resvg/resvg-js-win32-x64-msvc": 2.6.0 + dependenciesMeta: + "@resvg/resvg-js-android-arm-eabi": + optional: true + "@resvg/resvg-js-android-arm64": + optional: true + "@resvg/resvg-js-darwin-arm64": + optional: true + "@resvg/resvg-js-darwin-x64": + optional: true + "@resvg/resvg-js-linux-arm-gnueabihf": + optional: true + "@resvg/resvg-js-linux-arm64-gnu": + optional: true + "@resvg/resvg-js-linux-arm64-musl": + optional: true + "@resvg/resvg-js-linux-x64-gnu": + optional: true + "@resvg/resvg-js-linux-x64-musl": + optional: true + "@resvg/resvg-js-win32-arm64-msvc": + optional: true + "@resvg/resvg-js-win32-ia32-msvc": + optional: true + "@resvg/resvg-js-win32-x64-msvc": + optional: true + checksum: 27744f3954b7b0af1578db0c8a2fee19a1751c0d791596b67990c48d8921a0d31436f206a143d0c6bb2bcdd7daa0a8c81c599a5d4f18d357884d5d89000c6a75 + languageName: node + linkType: hard + "@shuding/opentype.js@npm:1.4.0-beta.0": version: 1.4.0-beta.0 resolution: "@shuding/opentype.js@npm:1.4.0-beta.0" @@ -1060,13 +1189,14 @@ __metadata: dependencies: "@napi-rs/canvas": ^0.1.41 "@napi-rs/image": ^1.7.0 + "@resvg/resvg-js": ^2.6.0 "@skyra/gifenc": ^1.0.1 "@types/node": ^20.3.1 "@types/react": ^18.2.12 benny: ^3.7.1 file-type: 16.5.4 prettier: ^2.8.8 - satori: ^0.10.1 + satori: ^0.10.9 tailwind-merge: ^1.14.0 tailwindcss: ^3.3.3 tsup: ^7.2.0 @@ -2784,21 +2914,21 @@ __metadata: languageName: node linkType: hard -"satori@npm:^0.10.1": - version: 0.10.1 - resolution: "satori@npm:0.10.1" +"satori@npm:^0.10.9": + version: 0.10.9 + resolution: "satori@npm:0.10.9" dependencies: - "@shuding/opentype.js": "npm:1.4.0-beta.0" - css-background-parser: "npm:^0.1.0" - css-box-shadow: "npm:1.0.0-3" - css-to-react-native: "npm:^3.0.0" - emoji-regex: "npm:^10.2.1" - escape-html: "npm:^1.0.3" - linebreak: "npm:^1.1.0" - parse-css-color: "npm:^0.2.1" - postcss-value-parser: "npm:^4.2.0" - yoga-wasm-web: "npm:^0.3.3" - checksum: fd6df0f80002bb1387bbec413f0d07414c1c1d6825abecf79a59f17283ca87db88c6928898ff494230946b9ee4773e389e71e6c4ed8ce5964323ef3baf2ed884 + "@shuding/opentype.js": 1.4.0-beta.0 + css-background-parser: ^0.1.0 + css-box-shadow: 1.0.0-3 + css-to-react-native: ^3.0.0 + emoji-regex: ^10.2.1 + escape-html: ^1.0.3 + linebreak: ^1.1.0 + parse-css-color: ^0.2.1 + postcss-value-parser: ^4.2.0 + yoga-wasm-web: ^0.3.3 + checksum: 56cb35e553cf8a65ee08ec29357e441a10adcc7c0cd68977c4e24c613f8999b0862ae05fe3c648498c4bda8dfc5a1c15d883cfbc30c815a9117fd99531ee4355 languageName: node linkType: hard