scratch/.agents/instructions/graphics-components/llms.md
2026-05-11 22:00:11 -04:00

14 KiB

applyTo
**/*.svelte

Graphics components

The @reuters-graphics/graphics-components library includes pre-styled components for easily adding graphics or other elements to a page.

Adding new components to a page

Components from the @reuters-graphics/graphics-components library are often added to the #each loop in src/lib/App.svelte that loops over content.blocks.

content represents text content pulled from our CMS as JSON that is passed into components via props.

Each block in content.blocks (i.e., "content block") is usually an object with a type property and additional properties specific to the block type. For example:

  • Text Block:
    {
      "type": "text",
      "text": "This is a text block."
    }
    
  • AI Graphic Block
    {
      "type": "ai-graphic",
      "chart": "AiMap",
      "width": "normal",
      "textWidth": "normal",
      "title": "Optional title of the graphic",
      "description": "Optional chatter describes more about the graphic.",
      "notes": "Note: Optional note clarifying something in the data.\r\n\r\nSource: Optional source of the data.",
      "altText": "Add a description of the graphic for screen readers. This is invisible on the page."
    }
    

To add a new component to the loop:

  1. Import the component in the script portion of the Svelte component.
  2. Add a new else if condition in the {#each content.blocks as block} loop to handle the new block type.
  3. Pass the required props to the component, ensuring they match the structure of the content block object.

For example, to add a new FeaturePhoto:

<script lang="ts">
  // ...

  import { assets } from '$app/paths';

  import {
    Article,
    Analytics,
    BodyText,
    EndNotes,
    SiteHeadline,
    GraphicBlock,
    InlineAd,
    FeautePhoto, // Add the component to others already imported
  } from '@reuters-graphics/graphics-components';

  // ...
</script>

{#each content.blocks as block}
  <!-- Text block -->
  {#if block.type === 'text'}
    <BodyText text={block.text} />

    <!-- Other block types -->

    <!-- Add new FeaturePhoto block -->
  {:else if block.type === 'feature-photo'}
    <FeaturePhoto
      src="{assets}/{block.src}"
      alt={block.alt}
      caption={block.caption}
      credit={block.credit}
    />
  {:else}
    <LogBlock message={`Unknown block type: "${block.type}"`} />
  {/if}
{/each}

Paths to multimedia files

Notice in the example above, we append the assets variable from SvelteKit's $app/paths module to the src path we got from the content block.

Always assume that paths to local multimedia files including images and videos specified in content blocks are relative and must be prefixed with the assets variable to make them absolute. For example:

<FeaturePhoto
  src="{assets}/{block.src}"
  alt={block.alt}
  caption={block.caption}
  credit={block.credit}
/>

Adding AI Graphics

AI (i.e., Adobe Illustrator) graphics are added to the page by importing a component from the src/lib/ai2svelte/ directory and then adding that graphic to the aiCharts object in src/lib/App.svelte. Then the object key for that chart is included in the content block's chart property.

For example, to use an AI graphic from src/lib/ai2svelte/map.svelte:

  • The AI graphic component is imported and added to the aiCharts object in src/lib/App.svelte:

    <script lang="ts">
      // ...
      import Map from './ai2svelte/map.svelte';
    
      // ...
    
      const aiCharts = {
        // Other AI graphics ...
        Map, // Added to the object
      };
    </script>
    
  • Now the content block will specify the key to the chart in aiCharts in the chart property:

    {
      "type": "ai-graphic",
      "chart": "Map",
      "width": "normal",
      "textWidth": "normal",
      "title": "My map",
      "description": "A map of the area",
      "notes": "Source: DataSource.org",
      "altText": "A map of a specific area showing something interesting"
    }
    
  • Now the {:else if block.type === 'ai-graphic'} block in src/lib/App.svelte uses that key to get the component:

    {#each content.blocks as block}
      <!-- Text block -->
      {#if block.type === 'text'}
        <BodyText text={block.text} />
    
        <!-- Ai2svelte graphic block -->
      {:else if block.type === 'ai-graphic'}
        {#if !aiCharts[block.chart]}
          <LogBlock message={`Unable to find "${block.chart}" in aiCharts`} />
        {:else}
          {@const AiChart = aiCharts[block.chart]}
          <GraphicBlock
            id={block.chart}
            width={containerWidth(block.width)}
            title={block.title}
            description={block.description}
            notes={block.notes}
            ariaDescription={block.altText}
          >
            <AiChart assetsPath={assets || '/'} />
          </GraphicBlock>
        {/if}
    
        <!-- Other block types -->
      {/if}
    {/each}
    

Refer to graphics components Storybook

If you're unsure how to implement a particular graphics component, suggest the user check the Storybook documentation site, which is hosted on GitHub at https://reuters-graphics.github.io/graphics-components/.

Writing content blocks in our CMS

While the text content in the content object is formatted as JSON, that data is written into our CMS (which is called "RNGS.io") using ArchieML syntax.

When suggesting what content blocks to add for components, please also suggest how to write that content in our CMS (RNGS.io) using ArchieML.

ArchieML

ArchieML is a lightweight and intuitive markup language that allows for easy structuring of data within text documents. It is designed to be human-readable, very flexible, and is particularly useful for creating structured data by users who may never have seen ArchieML or any other markup language before.

Basic Syntax
  • Keys and Values

    • Definition: Key-value pairs are defined by a line starting with a key followed by a colon. Keys can include any unicode character except whitespace and specific characters used within ArchieML ({ } [ ] : . +).

    • Example:

      key: This is a value
      ☃: Unicode Snowman for you and you and you!
      
    • Parsed JSON:

      {
        "key": "This is a value",
        "☃": "Unicode Snowman for you and you and you!"
      }
      
    • Whitespace around keys and values is ignored. Keys are case-sensitive.

  • Multi-line Values: Multi-line values are anchored with :end. All whitespace is preserved.

    • Example:

      key: value
      More value
      
      Even more value
      :end
      
    • Parsed JSON:

      {
        "key": "value\n More value\n\nEven more value"
      }
      
    • Escape Characters: Lines that would be interpreted as keys or commands can be escaped with a backslash \.

      • Example:
        key: value
        \:end
        :end
        
      • Parsed JSON:
        {
          "key": "value\n:end"
        }
        
  • Nested Structures

    • Dot-Notation: Use dot-notation for creating nested objects.

      • Example:
        colors.red: #f00
        colors.green: #0f0
        colors.blue: #00f
        
      • Parsed JSON:
        {
          "colors": {
            "red": "#f00",
            "green": "#0f0",
            "blue": "#00f"
          }
        }
        
    • Object Blocks: Group keys using object blocks defined by {}. Close an object with {} or by starting a new object.

      • Example:

        {colors}
        red: #f00
        green: #0f0
        blue: #00f
        {}
        
        {numbers}
        one: 1
        ten: 10
        one-hundred: 100
        {}
        
      • Parsed JSON:

        {
          "colors": {
            "red": "#f00",
            "green": "#0f0",
            "blue": "#00f"
          },
          "numbers": {
            "one": "1",
            "ten": "10",
            "one-hundred": "100"
          }
        }
        
  • Arrays

    • Arrays of Objects: Define arrays with brackets [arrayName]. New objects start when the first key is re-encountered.

      • Example:

        [arrayName]
        name: Amanda
        age: 26
        
        name: Tessa
        age: 30
        []
        
      • Parsed JSON:

        {
          "arrayName": [
            {
              "name": "Amanda",
              "age": "26"
            },
            {
              "name": "Tessa",
              "age": "30"
            }
          ]
        }
        
    • Arrays of Strings: Simple arrays use _ for elements. If _ is first, the array ignores key-value pairs.

      • Example:
        [days]
        * Sunday
        * Monday
        * Tuesday
        * Wednesday
        * Thursday
        * Friday
        * Saturday
        []
        
      • Parsed JSON:
        {
          "days": [
            "Sunday",
            "Monday",
            "Tuesday",
            "Wednesday",
            "Thursday",
            "Friday",
            "Saturday"
          ]
        }
        
    • Nested Arrays: Nested arrays use dot notation and are closed with [].

      • Example:

        [days]
        name: Monday
        [.tasks]
        * Clean dishes
        * Pick up room
        []
        
        name: Tuesday
        [.tasks]
        * Buy milk
        []
        
      • Parsed JSON:

        {
          "days": [
            {
              "name": "Monday",
              "tasks": ["Clean dishes", "Pick up room"]
            },
            {
              "name": "Tuesday",
              "tasks": ["Buy milk"]
            }
          ]
        }
        

ArchieML conventions in our CMS

Usually, content blocks are written in our CMS as objects inside an ArchieML array called blocks and always start with a type: key/value pair that defines the type of the content block object.

For example, a user adding a content block for a FeaturePhoto component, might add the following to the existing [blocks] array in our CMS:

[blocks]

type: feature-photo
src: images/myPhoto.jpg
alt: Alt text for my photo...

... which extends over multiple lines.
:end
caption: A photo of something interesting.
credit: Jane Doe

[]

Graphics components style tokens

As well as Svelte components, the graphics components library includes a tailwind-like style system that can be used to style components and other page elements by adding a class or through SCSS mixins.

These classes and mixins are defined as individual "tokens" representing the value for an individual style rule, like font-size or color. Each token sets just one style rule, and multiple tokens are combined together to style an element, like a <div>.

Each set of tokens has several levels that represent the different values a style rule can take in our design system and are grouped in how they're named to make them easier to remember.

For example, font weight tokens include font-thin, font-light, and font-bold which correspond to the style rules font-weight: 100;, font-weight: 300;, and font-weight: 700;, respectively. And those tokens can be applied via class name or SCSS mixin. For example:

<!-- Bold text applied via class -->
<p class="font-bold">Here is some bold text with some <span>thin text</span> in it!</p>

<style lang="scss">
  @use '@reuters-graphics/graphics-components/scss/mixins' as mixins;
  
  // Thin text applied via SCSS mixin
  span {
    @include mixins.font-thin;
  }
</style>

Not all our style tokens have both class names as well as SCSS mixins available to apply them.

Please use the tokens defined in the SCSS partials in the @reuters-graphics/graphics-components/dist/scss/tokens/ directory liberally in instructions and code samples, BUT be sure the token exists before suggesting it. DO NOT MAKE UP TOKENS, CLASS NAMES OR SCSS MIXINS!

If you're not sure if there is a token to apply a particular style, you can refer the user to our Storybook documentation site for them at: https://reuters-graphics.github.io/graphics-components/?path=/docs/styles-intro--docs.

Using style tokens

To use a token to style an element, you can apply it directly to the element through a class name. For example, to apply the text-primary token (controlling font colour) you can apply it like this:

<p class="text-primary">Lorem ipsum...</p>

OR you can apply some tokens via an SCSS mixin. For example:

<p>Lorem ipsum...</p>

<style lang="scss">
  @use '@reuters-graphics/graphics-components/scss/mixins' as mixins;

  p {
    @include mixins.text-primary;
  }
</style>

Be sure to always include the @use line that imports the SCSS mixins from the library in your SCSS/styling suggestions.

Please consider the SCSS mixins and classes defined in the @reuters-graphics/graphics-components/dist/scss/tokens/ directory.

Spacing tokens

We have a special set of tokens to control spacing, i.e., paddings and margins. They operate like tailwind's padding and margin system. For example, mt-1 represents margin-top: 0.25rem; and px-2 represents padding-right: 0.5rem; padding-left: 0.5rem;, etc. These tokens can be applied only through a class.

These tokens are all defined as a combination of a prefix and a level. The prefix is something like mb for bottom margin or py for padding top and bottom. The level is a number representing how large the padding are margin should be. The levels go like this: 0, 0.5, 1, 1.5, 2, 2.5, 3, 3.5, 4, 5, 6, 7, 8, 9, 10, 11, 12, 14, 16, then increasing by 4 each time up to 96. For example, the full token set for top margin would be mt-0, mt-0.5, mt-1, mt-1.5, and so on.

We also have a set of spacing tokens designed to work with fluid typography. These are prefixed beginning with the letter f, for example, fmb-1 represents a fluid margin bottom, margin-bottom: clamp(0.31rem, 0.31rem + 0vw, 0.31rem);. These tokens can be applied through a class AND an SCSS mixin. For example:

<p class="fmy-3">Some text with margin and padding</p>

<style lang="scss">
  @use '@reuters-graphics/graphics-components/scss/mixins' as mixins;

  p {
    @include mixins.fpx-1;
  }
</style>

You should recommend fluid margin and padding tokens for spacing fluidly-sized typographical elements or elements that are spaced next to fluidly-sized typographical elements. Typographical elements include page headings, paragraphs or elements containing text, generally.