@stacksjs/image 0.74.65 → 0.74.67

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/social.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import type { ImagesConfig } from '@stacksjs/types';
1
+ import type { ImagesConfig, SocialCardTextConfig } from '@stacksjs/types';
2
2
  import type { SocialCardPreset } from 'ts-images';
3
3
  /**
4
4
  * Name a card after its route.
@@ -9,6 +9,11 @@ import type { SocialCardPreset } from 'ts-images';
9
9
  * regenerations.
10
10
  */
11
11
  export declare function socialCardName(path: string): string;
12
+ /**
13
+ * The type sizes for one card: the page's, falling back key by key to the
14
+ * set's, falling back to the renderer's own defaults when neither says.
15
+ */
16
+ export declare function textSizes(set: SocialCardTextConfig | undefined, page?: SocialCardTextConfig): { titleSize?: number, eyebrowSize?: number, subtitleSize?: number };
12
17
  export declare function generateSocialCardSet(images: ImagesConfig, root?: string): Promise<SocialCardResult[]>;
13
18
  /**
14
19
  * Draw one card and hand back the bytes, without touching the disk.
package/dist/social.js CHANGED
@@ -1 +1 @@
1
- import{mkdir}from"node:fs/promises";import process from"node:process";import{generateSocialCards,renderSocialCard}from"ts-images";import{loadFonts}from"./fonts";import{background,color,device,markPainter,projectFile,requireProjectFile,themed}from"./theme";const PRESET_SIZES={og:{width:1200,height:630},twitter:{width:1200,height:600},square:{width:1200,height:1200},portrait:{width:1200,height:1500}};export function socialCardName(path){const trimmed=path.replace(/^\/+|\/+$/g,"");return trimmed===""?"og":trimmed.replace(/[^a-z0-9]+/gi,"-").toLowerCase()}async function socialCardTheme(images,root){const social=themed(images,images.social),fonts=await loadFonts(images.fonts,root),mark=await markPainter(social.mark,root),presets=social.presets?.length?social.presets:["og"];return{social,presets,deviceOptions:device(social.device),shared:{titleFont:fonts.title,bodyFont:fonts.body,brand:social.brand,drawMark:mark?.draw,markAspect:mark?.aspect,markPlate:social.markPlate===!1?null:color(social.markPlate),surface:background(social.background,root),color:color(social.color),mutedColor:color(social.mutedColor),accent:color(social.accent),format:social.format??"jpeg",quality:social.quality,presets}}}function cardForeground(shot,deviceOptions,root,label){if(!shot)return;return{image:requireProjectFile(shot,root,label),radius:deviceOptions?.radius,borderColor:deviceOptions?.borderColor,shadow:deviceOptions?.shadow,scale:deviceOptions?.scale}}export async function generateSocialCardSet(images,root=process.cwd()){if(images.social?.enabled!==!0)return[];const{social,presets,deviceOptions,shared}=await socialCardTheme(images,root),outputDir=projectFile(social.outputDir??"public/social",root),publicPath=`/${(social.publicPath??"/social").replace(/^\/+|\/+$/g,"")}`;await mkdir(outputDir,{recursive:!0});const pages=social.pages?.length?social.pages:[{path:"/",title:social.brand??"Home"}],results=[];for(const page of pages){const name=socialCardName(page.path),shot=page.foreground??social.foreground,files=await generateSocialCards(outputDir,{...shared,name,title:page.title,eyebrow:page.eyebrow,subtitle:page.subtitle,foreground:cardForeground(shot,deviceOptions,root,`Product shot for ${page.path}`)}),urls=Object.fromEntries(Object.entries(files).map(([preset,file])=>[preset,`${publicPath}/${file.slice(file.lastIndexOf("/")+1)}`]));results.push({path:page.path,name,files,urls,width:PRESET_SIZES[presets[0]].width,height:PRESET_SIZES[presets[0]].height,title:page.title})}return results}export async function renderOnDemandSocialCard(images,card,root=process.cwd()){if(images.social?.enabled!==!0)return null;const{social,presets,deviceOptions,shared}=await socialCardTheme(images,root),preset=card.preset??presets[0],{width,height}=PRESET_SIZES[preset],format=shared.format,{presets:_presets,...cardOptions}=shared;return{bytes:await renderSocialCard({...cardOptions,width,height,title:card.title,eyebrow:card.eyebrow,subtitle:card.subtitle,foreground:cardForeground(card.foreground??social.foreground,deviceOptions,root,"On-demand product shot")}),contentType:format==="jpeg"?"image/jpeg":`image/${format}`,width,height}}export function socialMetaTags(card,siteUrl,format="jpeg"){const primary=`${siteUrl.replace(/\/+$/,"")}${card.urls.og??Object.values(card.urls)[0]}`,mimeType=format==="jpeg"?"image/jpeg":`image/${format}`;return[`<meta property="og:image" content="${primary}">`,`<meta property="og:image:type" content="${mimeType}">`,`<meta property="og:image:width" content="${card.width}">`,`<meta property="og:image:height" content="${card.height}">`,`<meta property="og:image:alt" content="${escapeAttribute(card.title)}">`,'<meta name="twitter:card" content="summary_large_image">',`<meta name="twitter:image" content="${primary}">`,`<meta name="twitter:image:alt" content="${escapeAttribute(card.title)}">`]}function escapeAttribute(value){return value.replace(/&/g,"&amp;").replace(/"/g,"&quot;").replace(/</g,"&lt;").replace(/>/g,"&gt;")}
1
+ import{mkdir}from"node:fs/promises";import process from"node:process";import{generateSocialCards,renderSocialCard}from"ts-images";import{loadFonts}from"./fonts";import{background,color,device,markPainter,projectFile,requireProjectFile,themed}from"./theme";const PRESET_SIZES={og:{width:1200,height:630},twitter:{width:1200,height:600},square:{width:1200,height:1200},portrait:{width:1200,height:1500}};export function socialCardName(path){const trimmed=path.replace(/^\/+|\/+$/g,"");return trimmed===""?"og":trimmed.replace(/[^a-z0-9]+/gi,"-").toLowerCase()}async function socialCardTheme(images,root){const social=themed(images,images.social),fonts=await loadFonts(images.fonts,root),mark=await markPainter(social.mark,root),presets=social.presets?.length?social.presets:["og"];return{social,presets,deviceOptions:device(social.device),shared:{titleFont:fonts.title,bodyFont:fonts.body,brand:social.brand,drawMark:mark?.draw,markAspect:mark?.aspect,markPlate:social.markPlate===!1?null:color(social.markPlate),surface:background(social.background,root),color:color(social.color),mutedColor:color(social.mutedColor),accent:color(social.accent),format:social.format??"jpeg",quality:social.quality,presets}}}export function textSizes(set,page){return{titleSize:page?.titleSize??set?.titleSize,eyebrowSize:page?.eyebrowSize??set?.eyebrowSize,subtitleSize:page?.subtitleSize??set?.subtitleSize}}function cardForeground(shot,deviceOptions,root,label){if(!shot)return;return{image:requireProjectFile(shot,root,label),radius:deviceOptions?.radius,borderColor:deviceOptions?.borderColor,shadow:deviceOptions?.shadow,scale:deviceOptions?.scale}}export async function generateSocialCardSet(images,root=process.cwd()){if(images.social?.enabled!==!0)return[];const{social,presets,deviceOptions,shared}=await socialCardTheme(images,root),outputDir=projectFile(social.outputDir??"public/social",root),publicPath=`/${(social.publicPath??"/social").replace(/^\/+|\/+$/g,"")}`;await mkdir(outputDir,{recursive:!0});const pages=social.pages?.length?social.pages:[{path:"/",title:social.brand??"Home"}],results=[];for(const page of pages){const name=socialCardName(page.path),shot=page.foreground??social.foreground,files=await generateSocialCards(outputDir,{...shared,...textSizes(social.text,page.text),name,title:page.title,eyebrow:page.eyebrow,subtitle:page.subtitle,foreground:cardForeground(shot,deviceOptions,root,`Product shot for ${page.path}`)}),urls=Object.fromEntries(Object.entries(files).map(([preset,file])=>[preset,`${publicPath}/${file.slice(file.lastIndexOf("/")+1)}`]));results.push({path:page.path,name,files,urls,width:PRESET_SIZES[presets[0]].width,height:PRESET_SIZES[presets[0]].height,title:page.title})}return results}export async function renderOnDemandSocialCard(images,card,root=process.cwd()){if(images.social?.enabled!==!0)return null;const{social,presets,deviceOptions,shared}=await socialCardTheme(images,root),preset=card.preset??presets[0],{width,height}=PRESET_SIZES[preset],format=shared.format,{presets:_presets,...cardOptions}=shared;return{bytes:await renderSocialCard({...cardOptions,...textSizes(social.text),width,height,title:card.title,eyebrow:card.eyebrow,subtitle:card.subtitle,foreground:cardForeground(card.foreground??social.foreground,deviceOptions,root,"On-demand product shot")}),contentType:format==="jpeg"?"image/jpeg":`image/${format}`,width,height}}export function socialMetaTags(card,siteUrl,format="jpeg"){const primary=`${siteUrl.replace(/\/+$/,"")}${card.urls.og??Object.values(card.urls)[0]}`,mimeType=format==="jpeg"?"image/jpeg":`image/${format}`;return[`<meta property="og:image" content="${primary}">`,`<meta property="og:image:type" content="${mimeType}">`,`<meta property="og:image:width" content="${card.width}">`,`<meta property="og:image:height" content="${card.height}">`,`<meta property="og:image:alt" content="${escapeAttribute(card.title)}">`,'<meta name="twitter:card" content="summary_large_image">',`<meta name="twitter:image" content="${primary}">`,`<meta name="twitter:image:alt" content="${escapeAttribute(card.title)}">`]}function escapeAttribute(value){return value.replace(/&/g,"&amp;").replace(/"/g,"&quot;").replace(/</g,"&lt;").replace(/>/g,"&gt;")}
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "@stacksjs/image",
3
3
  "type": "module",
4
4
  "sideEffects": false,
5
- "version": "0.74.65",
5
+ "version": "0.74.67",
6
6
  "description": "Native responsive image delivery for Stacks.",
7
7
  "author": "Chris Breuer",
8
8
  "license": "MIT",
@@ -31,8 +31,8 @@
31
31
  "prepublishOnly": "bun run build"
32
32
  },
33
33
  "dependencies": {
34
- "@stacksjs/types": "0.74.65",
35
- "ts-images": "^0.2.11"
34
+ "@stacksjs/types": "0.74.67",
35
+ "ts-images": "^0.2.21"
36
36
  },
37
37
  "devDependencies": {
38
38
  "better-dx": "^0.2.24"