All files / app/util storyboard.ts

100% Statements 47/47
100% Branches 39/39
100% Functions 8/8
100% Lines 38/38

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 8977x                                           77x 77x     42x 11x 11x 11x 11x 1x 10x       25x 7x 25x 25x 6x       8x 1x 1x       9x 9x       8x 8x 2x 2x 1x 1x       9x 9x 2x 2x       8x 8x 2x 2x       8x 8x 1x 1x              
import { generateStoryboardKeyframes } from '../mods/thumbnail';
 
type Storyboard = {
  cols?: unknown;
  rows?: unknown;
  width?: unknown;
  height?: unknown;
};
 
type StoryboardGrid = {
  cols: number;
  rows: number;
  totalFrames: number;
};
 
export type StoryboardAnimation = {
  name: string;
  styleId: string;
  keyframes: string;
  value: string;
};
 
const THUMBNAIL_SIZE = 48;
const MAX_FRAMES = 10_000;
 
function getGrid(storyboard: Storyboard | null): StoryboardGrid | null {
  if (!storyboard?.cols || !storyboard?.rows) return null;
  const cols = Math.trunc(Number(storyboard.cols));
  const rows = Math.trunc(Number(storyboard.rows));
  const totalFrames = cols * rows;
  if (!Number.isFinite(cols) || !Number.isFinite(rows)
    || cols <= 0 || rows <= 0 || totalFrames > MAX_FRAMES) return null;
  return { cols, rows, totalFrames };
}
 
function getDimensions(storyboard: Storyboard | null) {
  if (!getGrid(storyboard)) return null;
  const width = Number(storyboard?.width);
  const height = Number(storyboard?.height);
  if (!Number.isFinite(width) || width <= 0 || !Number.isFinite(height) || height <= 0) return null;
  return { width, height };
}
 
export function storyboardUrl(url: string | null): string | null {
  if (!url) return null;
  const escapedUrl = url.replace(/\\/g, '\\\\').replace(/"/g, '\\"');
  return `url("${escapedUrl}")`;
}
 
export function storyboardSize(storyboard: Storyboard | null): string | null {
  const grid = getGrid(storyboard);
  return grid ? `${grid.cols * 100}% ${grid.rows * 100}%` : null;
}
 
export function storyboardMargin(storyboard: Storyboard | null): string | null {
  const dimensions = getDimensions(storyboard);
  if (!dimensions) return null;
  const { width, height } = dimensions;
  if (width > height) return `${(THUMBNAIL_SIZE - THUMBNAIL_SIZE * height / width) / 2}px 10px 0 0`;
  const margin = (THUMBNAIL_SIZE - THUMBNAIL_SIZE * width / height) / 2;
  return `0 ${margin + 10}px 0 ${margin}px`;
}
 
export function storyboardWidth(storyboard: Storyboard | null): string | null {
  const dimensions = getDimensions(storyboard);
  if (!dimensions) return null;
  const { width, height } = dimensions;
  return width > height ? `${THUMBNAIL_SIZE}px` : `${THUMBNAIL_SIZE * width / height}px`;
}
 
export function storyboardHeight(storyboard: Storyboard | null): string | null {
  const dimensions = getDimensions(storyboard);
  if (!dimensions) return null;
  const { width, height } = dimensions;
  return width > height ? `${THUMBNAIL_SIZE * height / width}px` : `${THUMBNAIL_SIZE}px`;
}
 
export function storyboardAnimation(storyboard: Storyboard | null): StoryboardAnimation | null {
  const grid = getGrid(storyboard);
  if (!grid || grid.totalFrames < 2) return null;
  const name = `storyboard-slide-${grid.cols}x${grid.rows}`;
  return {
    name,
    styleId: `style-${name}`,
    keyframes: generateStoryboardKeyframes(name, grid.cols, grid.rows),
    value: `${name} ${(grid.totalFrames * 0.4).toFixed(2)}s linear infinite`,
  };
}