Eop card browser/m4 eop styling config - #3315
Conversation
Signed-off-by: Ayman Algamal <ayman01287985950@gmail.com>
Signed-off-by: Ayman Algamal <ayman01287985950@gmail.com>
Signed-off-by: Ayman Algamal <ayman01287985950@gmail.com>
Signed-off-by: Ayman Algamal <ayman01287985950@gmail.com>
Signed-off-by: Ayman Algamal <ayman01287985950@gmail.com>
Signed-off-by: Ayman Algamal <ayman01287985950@gmail.com>
Signed-off-by: Ayman Algamal <ayman01287985950@gmail.com>
… removed 'opaque' tags Signed-off-by: Ayman Algamal <ayman01287985950@gmail.com>
|
Hi @rewtd, @sydseter What's done
What's configurable now
what else should be configurable?Per-image positioning (Didn't need it since the images fit well without handling each card image positioning, but that's not guaranteed for future decks.) What do you think? |
Signed-off-by: Ayman Algamal <ayman01287985950@gmail.com>
This sounds good. I'll have a look |
|
@ayman-art have a look at the review comments from qltysh. |
There was a problem hiding this comment.
🟡 Not ready to approve
The new EopCard component can render with an undefined card (and calls eopValue with possibly undefined inputs), which can lead to incorrect output/TypeScript errors and should be guarded/fixed before approval.
Once you've addressed the issues Copilot identified, you can request another Copilot review.
This review doesn't count toward merge requirements. Sign up for the private preview to control whether Copilot approvals count.
Pull request overview
This PR adds YAML-backed styling and per-card image configuration for the EoP (Elevation of Privilege) edition in the Svelte site, and wires that configuration through layout data into the card preview/browser UI.
Changes:
- Added new
source/YAML files for EoP suit styling (colors) and card image paths (per card ID). - Introduced
CardImagesServiceandSuitStylingService(with Vitest coverage) and exposed their data via+layout.server.ts. - Refactored EoP rendering in
CardPreviewinto a dedicatedEopCardcomponent and passedcardImages/suitStylingthrough relevant routes/components.
File summaries
| File | Description |
|---|---|
| source/eop-styling-5.0.yaml | Adds suit color configuration for EoP 5.0. |
| source/eop-card-images-5.0.yaml | Adds per-card image path mapping for EoP 5.0. |
| cornucopia.owasp.org/src/routes/edition/[edition]/+page.svelte | Passes card image + styling data into CardPreview for edition view. |
| cornucopia.owasp.org/src/routes/edition/[edition]/[card]/+page.svelte | Passes card image + styling data into CardFound. |
| cornucopia.owasp.org/src/routes/edition/[edition]/[card]/[version]/+page.svelte | Passes card image + styling data into CardFound. |
| cornucopia.owasp.org/src/routes/edition/[edition]/[card]/[version]/[lang]/+page.svelte | Passes card image + styling data into CardFound. |
| cornucopia.owasp.org/src/routes/cards/+page.svelte | Passes card image + styling data into CardPreview for cards index. |
| cornucopia.owasp.org/src/routes/cards/[card]/+page.svelte | Passes card image + styling data into CardFound for card detail. |
| cornucopia.owasp.org/src/routes/+layout.server.ts | Loads EoP card images + suit styling in the root layout. |
| cornucopia.owasp.org/src/lib/services/suitStylingService.ts | New service to load and cache suit styling YAML. |
| cornucopia.owasp.org/src/lib/services/suitStylingService.test.ts | Tests for suit styling loader behavior. |
| cornucopia.owasp.org/src/lib/services/cardImagesService.ts | New service to load and cache card images YAML. |
| cornucopia.owasp.org/src/lib/services/cardImagesService.test.ts | Tests for card images loader behavior. |
| cornucopia.owasp.org/src/lib/components/eopCard.svelte | New EoP card rendering component using styling + images. |
| cornucopia.owasp.org/src/lib/components/eopCard.css | Extracted CSS for the EoP card renderer. |
| cornucopia.owasp.org/src/lib/components/cardPreview.svelte | Uses EopCard instead of inline EoP markup/styles; adds props for images/styling. |
| cornucopia.owasp.org/src/lib/components/cardFound.svelte | Plumbs image/styling props into CardBrowser. |
| cornucopia.owasp.org/src/lib/components/cardBrowser.svelte | Plumbs image/styling props into CardPreview. |
Review details
- Files reviewed: 18/26 changed files
- Comments generated: 3
- Review effort level: Lite
We're testing this review assessment. Please use 👍 or 👎 to tell us if it's correct.
There was a problem hiding this comment.
Is this generated? Could this be generalised to be applicable to the entire deck instead of being a separate component?
There was a problem hiding this comment.
This was originally inline in cardPreview.svelte, handling the EoP branch alongside the default layout. Since EoP's layout (artwork + watermark + tab) is structurally different, the idea was to extract it into its own file instead of growing cardPreview.svelte. Do you think this is redundant work? Would you rather it stayed inline?
There was a problem hiding this comment.
It's not really an improvement. If you create specific ts files whose only purpose is to support the edition, then you make the coupling between code and data stronger. You need to generalise the code so that it can be used for any of the editions. The code can't really refer to the data if you want to add new editions without having to change the code.
There was a problem hiding this comment.
Thanks for clarifying! Yes, I want to make sure there's a decoupling between code and data. I merged eopCard.svelte back into cardPreview.svelte, and replaced the card.edition === 'eop' check with a generalized one:
let editionCardImages = $derived(cardImages?.[card?.edition ?? '']);{#if card && editionCardImages}It now picks the layout by checking if image data exists for that edition, not by its name. I also removed the hardcoded eop class/CSS variables so nothing in the logic refers to that specific edition anymore.
I also switched the CSS import to:
import.meta.glob('./*Card.css', { eager: true }); // example: eopCard.cssThis automatically includes any new deck's CSS, no manual import needed for future decks.
So adding a new deck now only requires:
{edition}-styling-{version}.yaml-> suit colors{edition}-card-images-{version}.yaml-> card images{edition}Card.css(its own layout styling) -> automatically imported using this new import line.
No changes to cardPreview.svelte or any other code file needed!
Would like to know your thoughts about this!
There was a problem hiding this comment.
This is great. Yes, perfect.
There was a problem hiding this comment.
Make sure to the capabilities are documented in the readme.
There was a problem hiding this comment.
README is updated now.
|
@ayman-art have a look at mine and Copilot's comments as well. |
Signed-off-by: Ayman Algamal <ayman01287985950@gmail.com>
…ub.com/OWASP/cornucopia into eop-card-browser/m4-eop-styling-config
Signed-off-by: Ayman Algamal <ayman01287985950@gmail.com>
…ub.com/OWASP/cornucopia into eop-card-browser/m4-eop-styling-config
Signed-off-by: Ayman Algamal <ayman01287985950@gmail.com>
Thanks for your review. I have addressed yours, Copiot's, and qlty's comments. Ready for another look! |
Signed-off-by: Ayman Algamal <ayman01287985950@gmail.com>
There was a problem hiding this comment.
🟡 Not ready to approve
The new YAML loader currently caches missing-root-key results silently (masking config errors), and the root layout now ships full image/styling maps to every route which has avoidable payload/build-size impact.
Once you've addressed the issues Copilot identified, you can request another Copilot review.
This review doesn't count toward merge requirements. Sign up for the private preview to control whether Copilot approvals count.
Review details
Suppressed comments (3)
cornucopia.owasp.org/src/lib/services/yamlDataLoader.ts:25
- Building the YAML path via string interpolation hard-codes POSIX separators and bypasses
pathnormalization. Usingpath.join(...)avoids cross-platform path issues and makes the intent clearer.
const file = `${__dirname}/../source/${edition}-${this.fileSuffix}-${version}.yaml`;
cornucopia.owasp.org/src/lib/services/yamlDataLoader.ts:34
yaml.load(...)is cast asRecord<string, T>, but if the YAML is valid yet missing the expected root key (e.g.suits/cards),databecomesundefinedand is still cached, silently masking configuration errors and preventing a later retry. This should validate the parsed structure and only cache when the expected key exists.
const yamlData = fs.readFileSync(file, 'utf8');
const parsed = yaml.load(yamlData, { schema: yaml.FAILSAFE_SCHEMA }) as Record<string, T>;
const data = parsed[this.rootKey];
this.cache.push({ edition, version, data });
return data;
cornucopia.owasp.org/src/routes/+layout.server.ts:43
+layout.server.tsruns for every page, and its returned data is serialized to the client (and duplicated into each prerendered route). Returning the fullcardImages/suitStylingmaps here will increase payload and build output size even on pages that never render cards; consider moving this to a nested+layout.server.tsunder/cardsand/edition(or a dedicated endpoint) so only card pages pay the cost.
fallbackTranslation: event.locals.fallbackTranslation,
lang: event.locals.lang,
cardImages: getCardImagesByEdition(),
suitStyling: getSuitStylingByEdition()
- Files reviewed: 18/26 changed files
- Comments generated: 0 new
- Review effort level: Lite
We're testing this review assessment. Please use 👍 or 👎 to tell us if it's correct.
Signed-off-by: Ayman Algamal <ayman01287985950@gmail.com>
3e62bda to
c4fa548
Compare
Signed-off-by: Ayman Algamal <ayman01287985950@gmail.com>
|
@ayman-art Question, are you waiting for a new review? Have you looked at all the comments? |
Thanks for the question. There is Copilot's last comment remaining, once I address it, I will request another review! |
Description
SuitStylingService,CardImagesService).EopCardcomponent that draws EoP cards with their own look (background artwork, watermark number, color tab), since EoP cards look different from the other decks' cards. This component is now used on every page that shows a card (/cards,/cards/[card],/edition/[edition]/...).Changes
Feature 1: EoP suit styling and card images now come from YAML files
source/eop-styling-5.0.yaml: suit colors (tab/watermark/royal)source/eop-card-images-5.0.yaml: image path for each cardsrc/lib/services/suitStylingService.ts/src/lib/services/cardImagesService.ts: read and cache this datasrc/routes/+layout.server.ts: loads this data for every page. It now checks every deck, not just EoP, for a matching yaml file, so a future deck can add its own file with no code changes needed. Decks without a file (all except EoP today) are simply skipped, no error.src/lib/services/yamlDataLoader.ts: shared code both services now use, since they were doing almost the same thing (flagged by qlty as duplicate code)Feature 2: Card style picked automatically in cardPreview.svelte
src/lib/components/cardPreview.svelte: draws EoP's card look (image, watermark, colored tab, royal color) directly, instead of using a separateEopCardfile. To decouple the code from data, it checks if there's image data for that deck instead of checking if the deck is named'eop'. This means a future deck with the same structure needs no code change here.src/lib/components/eopCard.css: EoP's own styling (sizes, colors) for this card look. No longer imported by hand.cardPreview.svelteloads it automatically usingimport.meta.glob('./*Card.css', { eager: true }), so any{edition}Card.cssfile is imported on its own.src/lib/components/cardBrowser.svelte,cardFound.svelte: pass the card images/colors down tocardPreview.svelteFeature 3: Card image fixes
opaquetagsFeature 4: Tests
src/lib/services/cardImagesService.test.ts/suitStylingService.test.ts: added tests for cache-hit and parse-failure cases, removed a redundantasyncfrom two synchronous test casesNotes
SuitStyling/CardImageare still fixed to EoP's fields (tab/watermark/royal). A future deck with different needs will require loosening these types.Resolved or fixed issue: refactoring related to Adding a endpoint for each eop card and to the card browser #1322
AI Tool Disclosure
[e.g. GitHub CoPilot, ChatGPT, JetBrains Junie etc.][e.g. GPT-4.1, Claude Haiku 4.5, Gemini 2.5 Pro etc.][Summarize the key prompts or instructions given to the AI tools]Affirmation