Skip to content
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
.firebase/
.DS_Store
.firebase/*
80 changes: 68 additions & 12 deletions js/global.js
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,20 @@
const VALID_BUBBLE_SUBTYPES = new Set(['tip', 'warning', 'note'])
const VALID_INLINE_IMAGE_FLOWS = new Set(['around', 'over', 'under'])
const VALID_SPACER_VARIANTS = new Set(['blank', 'line', 'page', 'container'])
/** Alternate JSON `type` strings from older exports or external templates → spacer variant default */
const IMPORT_SPACER_TYPE_ALIASES = new Map([
['separator', 'line'],
['hr', 'line'],
['horizontal_rule', 'line'],
['horizontalrule', 'line'],
['rule', 'line'],
['pagebreak', 'page'],
['page_break', 'page'],
['whitespace', 'blank'],
['empty', 'blank'],
['gap', 'blank'],
['space', 'blank']
])
const VALID_CONTAINER_LAYOUTS = new Set(['flow', 'grid'])
const DEFAULT_RECIPE_SETTINGS = Object.freeze({ ...recipeData.settings })
const PRINT_MODAL_ACTION_PRINT = 'print'
Expand All @@ -91,6 +105,30 @@
name: 'All Item Types',
subtitle: 'One sample for every item type',
path: 'templates/default/all-items.cookie'
},
{
slot: 2,
name: "Grandma & Co's Basic Cake Recipe",
subtitle: 'A simple recipe with a title and description',
path: 'templates/default/cake.cookie'
},
{
slot: 3,
Comment thread
kiyarose marked this conversation as resolved.
name: 'Assignment',
subtitle: 'A simple essay builder assignment template with references',
path: 'templates/default/assignment.cookie'
},
{
slot: 4,
name: 'Safety Plan',
subtitle: 'A quick 2 page safety plan that covers essentials...',
path: 'templates/default/safeplan.cookie'
},
{
slot: 5,
name: 'Basic Email with Signature',
subtitle: 'A basic email with a signature and some template details.',
path: 'templates/default/emailsig.cookie'
}
])
let printModalAction = PRINT_MODAL_ACTION_PRINT
Expand Down Expand Up @@ -417,6 +455,13 @@
return normalized
}

function normalizeImportedItemTypeKey (rawType) {
return toStringOrFallback(rawType, '')
.trim()
.toLowerCase()
.replace(/-/g, '_')

Check warning on line 462 in js/global.js

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Prefer `String#replaceAll()` over `String#replace()`.

See more on https://sonarcloud.io/project/issues?id=SillyLittleTech_CookieCut&issues=AZ3sXUEttP2ORy9FxaFI&open=AZ3sXUEttP2ORy9FxaFI&pullRequest=71
}

function normalizeImportedSpacerItem (rawItem, normalized) {
let variant = toStringOrFallback(rawItem.variant, 'blank')
if (!VALID_SPACER_VARIANTS.has(variant)) variant = 'blank'
Expand All @@ -438,35 +483,46 @@

function normalizeImportedItem (rawItem, fallbackId) {
if (!rawItem || typeof rawItem !== 'object') return null
const type = toStringOrFallback(rawItem.type, '')
if (!VALID_ITEM_TYPES.has(type)) return null
let typeKey = normalizeImportedItemTypeKey(rawItem.type)
let spacerVariantWhenAlias = null
const aliasDefaultVariant = IMPORT_SPACER_TYPE_ALIASES.get(typeKey)
if (aliasDefaultVariant !== undefined) {
typeKey = 'spacer'
spacerVariantWhenAlias = aliasDefaultVariant
}
if (!VALID_ITEM_TYPES.has(typeKey)) return null

const normalized = {
...rawItem,
id: rawItem.id ?? fallbackId,
type
type: typeKey
}

if (type === 'image') {
if (typeKey === 'image') {
return normalizeImportedImageItem(rawItem, normalized)
}

if (type === 'spacer') {
return normalizeImportedSpacerItem(rawItem, normalized)
if (typeKey === 'spacer') {
const rawVariant = toStringOrFallback(rawItem.variant, '')
const spacerSource =
spacerVariantWhenAlias != null && !VALID_SPACER_VARIANTS.has(rawVariant)
? { ...rawItem, variant: spacerVariantWhenAlias }
: rawItem
return normalizeImportedSpacerItem(spacerSource, normalized)
}

normalized.content = toStringOrFallback(rawItem.content, '')

if (type === 'bubble') {
if (typeKey === 'bubble') {
normalized.subtype = VALID_BUBBLE_SUBTYPES.has(rawItem.subtype)
? rawItem.subtype
: 'note'
}
if (type === 'link') {
if (typeKey === 'link') {
normalized.href = toStringOrFallback(rawItem.href, '')
}
applyImportedParentId(normalized, rawItem.parentId)
if (type === 'button') {
if (typeKey === 'button') {
normalized.href = toStringOrFallback(rawItem.href, '')
const VALID_BUTTON_STYLES = new Set([
'primary',
Expand All @@ -478,13 +534,13 @@
? rawItem.buttonStyle
: 'primary'
}
if (type === 'navmenu') {
if (typeKey === 'navmenu') {
normalized.links = toStringOrFallback(rawItem.links, '[]')
}
if (type === 'dropdown') {
if (typeKey === 'dropdown') {
normalized.options = toStringOrFallback(rawItem.options, '')
}
if (type === 'frame') {
if (typeKey === 'frame') {
normalized.src = toStringOrFallback(rawItem.src, '')
normalized.frameHeight = toFiniteNumberOrFallback(rawItem.frameHeight, 400)
}
Expand Down
Binary file added templates/.DS_Store
Binary file not shown.
30 changes: 30 additions & 0 deletions templates/default/all-items.cookie
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,36 @@
"type": "codescript",
"content": "<script>/* Example only — not executed in CookieCut preview */\nconsole.log('Hello');\n</script>",
"scale": 100
},
{
"id": 1013,
"type": "spacer",
"variant": "blank",
"size": 48,
"scale": 100
},
{
"id": 1014,
"type": "spacer",
"variant": "line",
"size": 0,
"scale": 100
},
{
"id": 1015,
"type": "spacer",
"variant": "page",
"size": 0,
"scale": 100
},
{
"id": 1016,
"type": "spacer",
"variant": "container",
"size": 0,
"containerLayout": "flow",
"containerColumns": 2,
"scale": 100
}
],
"settings": {
Expand Down
84 changes: 84 additions & 0 deletions templates/default/assignment.cookie
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
{
"app": "CookieCut",
"format": "cookie_document",
"version": 1,
"exportedAt": "2026-05-03T04:29:38.753Z",
"recipeData": {
"title": "A great assignment!",
"description": "The story of the seagull that could.",
"items": [
{
"id": 1777782163624,
"type": "heading",
"content": "Introducing our friends",
"scale": 105,
"inlineWidth": 673,
"inlineMinHeight": 48
},
{
"id": 1777782216640,
"type": "text",
"content": "The undisputed kings of the boardwalk, seagulls are less \"majestic seabirds\" and more \"highly organized snack-heist specialists.\" With an uncanny ability to hear a chip bag opening from three miles away, they patrol the coastline with a piercing gaze and zero respect for personal boundaries. Whether they’re performing a mid-air acrobatic feat to intercept a tourist’s fry or simply standing on a pier post looking vaguely judgmental, the seagull remains the ocean’s most chaotic—and loud—ambassador.",
"scale": 80,
"inlineWidth": 667
},
{
"id": 1777782278373,
"type": "bullet",
"content": "The Rain Dance (Worm Charming)If you ever see a seagull frantically tapping its feet on a patch of grass like it’s practicing for a talent show, it isn't \"dancing\"—it's simulating a rainstorm. By rapidly drumming their feet, gulls create vibrations in the soil that mimic the sound of falling rain. This tricks earthworms into thinking a flood is coming, driving them to the surface to avoid drowning. Once the worms pop up to \"safety,\" the seagull has a gourmet dinner served without ever having to dig.",
"scale": 65,
"inlineWidth": 604
},
{
"id": 1777782344239,
"type": "bullet",
"content": "They Track Your Taste Buds: Recent studies have shown that urban seagulls are more likely to steal food that they have specifically seen a human handling. If you’re eating a blue bag of chips, they are significantly more likely to target a blue bag than a green one. They don't just want food; they want your food.",
"scale": 65
},
{
"id": 1777782374505,
"type": "bullet",
"content": "Built-in Desalinization: Seagulls can drink salt water. They have specialized supraorbital glands located above their eyes that act like tiny desalination plants, filtering the salt out of their blood and \"sneezing\" it out through their nostrils.",
"scale": 65
},
{
"id": 1777782399555,
"type": "text",
"content": "Grudge Holders: They are highly intelligent and can recognize individual human faces. If you’ve shooed one away aggressively or, conversely, shared a fry, they are likely to remember you the next time you walk down the boardwalk.",
"scale": 80,
"inlineWidth": 653,
"inlineMinHeight": 98
},
{
"id": 1777782520904,
"type": "heading",
"content": "References",
"scale": 100
},
{
"id": 1777782461187,
"type": "text",
"content": "Gulliver, Finnegan. The Coastal Heist: Behavioral Patterns of Urban Laridae. Seaside University Press, 2024.\n\nLarson, Sandra. \"Vibrational Foraging: The Mechanics of the Seagull Rain Dance.\" Journal of Avian Intelligence, vol. 42, no. 3, 2025, pp. 112-128.\n",
"scale": 100,
"inlineWidth": 631,
"inlineMinHeight": 171
}
],
"settings": {
"fontStyle": "serif",
"fontApplyToText": false,
"fontApplyToTips": false,
"editorMode": "inline",
"showHtmlTools": false,
"previewMode": "paged",
"fileName": "assignment",
"hideTitle": false,
"hideDescription": false
}
},
"marketplaceTemplate": {
"isTemplate": true,
"title": "Assignment",
"summary": "A simple essay builder assignment template with references."
}
}
Loading
Loading