<div id="richtext-13709-88957-wrapper" class="richtext">
    <input id="richtext-13709-88957" type="hidden" value="">

    <trix-toolbar id="richtext-13709-88957-toolbar" class="richtext__toolbar">
        <div class="richtext__toolbar-buttons">
            <button class="richtext__toolbar-button" type="button" title="Fett" data-trix-attribute="bold" data-trix-key="b" tabindex="-1">
                <svg class="icon icon--bold richtext__toolbar-button-icon" viewBox="0 0 200 200" aria-hidden="true">
                    <use xlink:href="/assets/icons/icons.3bafb6df0d.svg#bold"></use>
                </svg> </button>
            <button class="richtext__toolbar-button" type="button" title="Kursiv" data-trix-attribute="italic" data-trix-key="i" tabindex="-1">
                <svg class="icon icon--italic richtext__toolbar-button-icon" viewBox="0 0 200 200" aria-hidden="true">
                    <use xlink:href="/assets/icons/icons.3bafb6df0d.svg#italic"></use>
                </svg> </button>
            <button class="richtext__toolbar-button" type="button" title="Durchgestrichen" data-trix-attribute="strikethrough" data-trix-key="s" tabindex="-1">
                <svg class="icon icon--strikethrough richtext__toolbar-button-icon" viewBox="0 0 200 200" aria-hidden="true">
                    <use xlink:href="/assets/icons/icons.3bafb6df0d.svg#strikethrough"></use>
                </svg> </button>
            <button class="richtext__toolbar-button" type="button" title="Als Überschrift der Ebene 1 formattieren" data-trix-attribute="heading2" data-trix-key="h" tabindex="-1">
                <svg class="icon icon--heading-1 richtext__toolbar-button-icon" viewBox="0 0 200 200" aria-hidden="true">
                    <use xlink:href="/assets/icons/icons.3bafb6df0d.svg#heading-1"></use>
                </svg> </button>
            <button class="richtext__toolbar-button" type="button" title="Als Überschrift der Ebene 2 formattieren" data-trix-attribute="heading3" data-trix-key="n" tabindex="-1">
                <svg class="icon icon--heading-2 richtext__toolbar-button-icon" viewBox="0 0 200 200" aria-hidden="true">
                    <use xlink:href="/assets/icons/icons.3bafb6df0d.svg#heading-2"></use>
                </svg> </button>
            <button class="richtext__toolbar-button" type="button" title="Als Zitat formattieren" data-trix-attribute="quote" data-trix-key="q" tabindex="-1">
                <svg class="icon icon--blockquote richtext__toolbar-button-icon" viewBox="0 0 200 200" aria-hidden="true">
                    <use xlink:href="/assets/icons/icons.3bafb6df0d.svg#blockquote"></use>
                </svg> </button>
            <button class="richtext__toolbar-button" type="button" title="Ungeordnete Liste" data-trix-attribute="bullet" data-trix-key="l" tabindex="-1">
                <svg class="icon icon--unordered-list richtext__toolbar-button-icon" viewBox="0 0 200 200" aria-hidden="true">
                    <use xlink:href="/assets/icons/icons.3bafb6df0d.svg#unordered-list"></use>
                </svg> </button>
            <button class="richtext__toolbar-button" type="button" title="Nummerierte Liste" data-trix-attribute="number" data-trix-key="o" tabindex="-1">
                <svg class="icon icon--ordered-list richtext__toolbar-button-icon" viewBox="0 0 200 200" aria-hidden="true">
                    <use xlink:href="/assets/icons/icons.3bafb6df0d.svg#ordered-list"></use>
                </svg> </button>
            <button class="richtext__toolbar-button" type="button" title="Als Quellcode formattieren" data-trix-attribute="code" data-trix-key="c" tabindex="-1">
                <svg class="icon icon--code richtext__toolbar-button-icon" viewBox="0 0 200 200" aria-hidden="true">
                    <use xlink:href="/assets/icons/icons.3bafb6df0d.svg#code"></use>
                </svg> </button>
            <button class="richtext__toolbar-button" type="button" title="Link" data-trix-attribute="href" data-trix-action="link" data-trix-key="a" tabindex="-1">
                <svg class="icon icon--link richtext__toolbar-button-icon" viewBox="0 0 200 200" aria-hidden="true">
                    <use xlink:href="/assets/icons/icons.3bafb6df0d.svg#link"></use>
                </svg> </button>
        </div>

        <div class="richtext__toolbar-dialogs" data-trix-dialogs>
            <div class="richtext__toolbar-dialog richtext__toolbar-dialog--link" data-trix-dialog="href" data-trix-dialog-attribute="href">
                <input type="url" data-name="href" class="richtext__toolbar-dialog-input" placeholder="https://beispiel-url.de" aria-label="URL" data-trix-validate-href required data-trix-input>

                <button class="richtext__toolbar-button" type="button" data-trix-method="setAttribute">
                    <svg class="icon icon--link richtext__toolbar-button-icon" viewBox="0 0 200 200" aria-hidden="true">
                        <use xlink:href="/assets/icons/icons.3bafb6df0d.svg#link"></use>
                    </svg>
                    <span class="richtext__toolbar-button-text">
                        Link speichern
                    </span>
                </button>

                <button class="richtext__toolbar-button" title="Link entfernen" type="button" data-trix-method="removeAttribute">
                    <svg class="icon icon--unlink richtext__toolbar-button-icon" viewBox="0 0 200 200" aria-hidden="true">
                        <use xlink:href="/assets/icons/icons.3bafb6df0d.svg#unlink"></use>
                    </svg> </button>
            </div>
        </div>
    </trix-toolbar>

    <trix-editor class="richtext__input" input="richtext-13709-88957" toolbar="richtext-13709-88957-toolbar">&nbsp;</trix-editor>
</div>
{% set id = id ??? html_id('richtext') %}

{% set richtextActions = {
  bold: {
    title: 'Bold' | t('site'),
    icon: 'bold',
    htmlTags: ['b', 'strong'],
    key: 'b',
  },
  italic: {
    title: 'Italic' | t('site'),
    icon: 'italic',
    htmlTags: ['em', 'i'],
    key: 'i',
  },
  strikethrough: {
    title: 'Strikethrough' | t('site'),
    icon: 'strikethrough',
    htmlTags: ['s'],
    key: 's',
  },
  heading2: {
    title: 'Format as headline level 1' | t('site'),
    icon: 'heading-1',
    htmlTags: ['h2'],
    key: 'h',
  },
  heading3: {
    title: 'Format as headline level 2' | t('site'),
    icon: 'heading-2',
    htmlTags: ['h3'],
    key: 'n',
  },
  quote: {
    title: 'Format as quote' | t('site'),
    icon: 'blockquote',
    htmlTags: ['blockquote', 'cite'],
    key: 'q',
  },
  ulist: {
    title: 'Unordered list' | t('site'),
    icon: 'unordered-list',
    attribute: 'bullet',
    htmlTags: ['ul', 'li'],
    key: 'l',
  },
  olist: {
    title: 'Ordered list' | t('site'),
    icon: 'ordered-list',
    attribute: 'number',
    htmlTags: ['ol', 'li'],
    key: 'o',
  },
  code: {
    title: 'Format as code' | t('site'),
    icon: 'code',
    htmlTags: ['code'],
    key: 'c',
  },
  link: {
    title: 'Link' | t('site'),
    icon: 'link',
    action: 'link',
    attribute: 'href',
    htmlTags: ['a'],
    key: 'a',
  },
} %}

{% set buttons = buttons | default(richtextActions|keys) %}

<div {{ html_attributes({
  id: 'wrapper' | namespaceInputId(id),
  class: 'richtext',
}, attrs ?? {}) }}>
  <input {{ html_attributes({
    id,
    type: 'hidden',
    name: name ?? null,
    value: value | default('') | raw,
  }, inputAttrs ?? {}) }}>

  <trix-toolbar id="{{ 'toolbar' | namespaceInputId(id) }}" class="richtext__toolbar">
    <div class="richtext__toolbar-buttons">
      {% for button in buttons %}
        {% if button in richtextActions|keys %}
          <button {{ html_attributes({
            class: 'richtext__toolbar-button',
            type: 'button',
            title: richtextActions[button].title,
            'data-trix-attribute': richtextActions[button].attribute ?? button,
            'data-trix-action': richtextActions[button].action ?? null,
            'data-trix-key': richtextActions[button].key ?? null,
            tabindex: '-1',
          }) }}>
            {% include '@icon' with {
              icon: richtextActions[button].icon,
              class: 'richtext__toolbar-button-icon',
            } only %}
          </button>
        {% endif %}
      {% endfor %}
    </div>

    <div class="richtext__toolbar-dialogs" data-trix-dialogs>
      <div class="richtext__toolbar-dialog richtext__toolbar-dialog--link" data-trix-dialog="href" data-trix-dialog-attribute="href">
        <input type="url" data-name="href" class="richtext__toolbar-dialog-input" placeholder="{{ 'https://example.com' | t('site') }}" aria-label="{{ 'URL' | t('site') }}" data-trix-validate-href required data-trix-input>

        <button class="richtext__toolbar-button" type="button" data-trix-method="setAttribute">
          {% include '@icon' with {
            icon: 'link',
            class: 'richtext__toolbar-button-icon',
          } only %}

          <span class="richtext__toolbar-button-text">
            {{ 'Save link' | t('site') }}
          </span>
        </button>

        <button class="richtext__toolbar-button" title="{{ 'Remove link' | t('site') }}" type="button"  data-trix-method="removeAttribute">
          {% include '@icon' with {
            icon: 'unlink',
            class: 'richtext__toolbar-button-icon',
          } only %}
        </button>
      </div>
    </div>
  </trix-toolbar>

  <trix-editor {{ html_attributes({
    class: 'richtext__input',
    input: id | namespaceInputId,
    toolbar: 'toolbar' | namespaceInputId(id) | namespaceInputId,
  }, inputAttrs ?? {}) }}>&nbsp;</trix-editor>
</div>
/* No context defined. */
  • Content:
    .richtext {
      --focus-outline-offset: 0;
      --focus-outline-width: 3px;
      --focus-outline-color: var(--richtext-focus-outline-color, var(--form-focus-color));
    
      background-color: var(--richtext-background-color, var(--color-white));
      border-color: var(--richtext-border-color, var(--form-color));
      border-style: solid;
      border-width: 2px;
      color: var(--richtext-color, var(--text-color));
    
      &:has(:not(.richtext__toolbar-dialog-input, .richtext__toolbar-button):focus-visible) {
        @include use-focus-outline();
      }
    }
    
    .richtext__toolbar {
      background-color: var(--richtext-toolbar-background-color, var(--color-midnight-50));
      border-block-end: 1px solid var(--richtext-toolbar-border-color, var(--color-midnight-100));
    }
    
    .richtext__toolbar-buttons {
      display: flex;
      flex-wrap: wrap;
      padding-inline: 1.2rem;
    }
    
    .richtext__toolbar-button {
      align-items: center;
      color: var(--richtext-toolbar-color, var(--color-midnight-900));
      display: flex;
      flex-shrink: 0;
      font-size: 2rem;
      gap: 0.8rem;
      justify-content: center;
      padding: 0.8rem;
      transition-property: background-color;
    
      &:is(:hover, :focus-visible, [data-trix-active]) {
        background-color: var(--richtext-toolbar-background-color, var(--color-midnight-100));
      }
    }
    
    .richtext__toolbar-button-text {
      font-size: 1.6rem;
    }
    
    .richtext__toolbar-dialog .richtext__toolbar-button {
      background-color: var(--color-midnight-100);
      padding: 1.6rem;
    
      &:is(:hover, :focus-visible, [data-trix-active]) {
        background-color: var(--color-midnight-200);
      }
    
      &:not(:first-of-type) {
        border-inline-start: 1px solid var(--color-midnight-300);
      }
    }
    
    .richtext__toolbar-dialog {
      border-block: 1px solid var(--richtext-toolbar-border-color, var(--color-midnight-300));
      display: none;
      margin-block-end: -1px;
    
      &:is([data-trix-active]) {
        display: flex !important;
      }
    }
    
    .richtext__toolbar-dialog-input {
      --focus-outline-offset: -3px;
    
      flex-grow: 1;
      padding-block: 1.6rem;
      padding-inline: 2.4rem;
    }
    
    .richtext__input {
      --focus-outline-color: transparent;
      --focus-outline-width: 0;
    
      font-size: 1.8rem;
      line-height: 2.4rem;
      max-block-size: calc(10lh + 2.4rem);
      min-block-size: calc(3lh + 2.4rem);
      overflow: auto;
      padding-block: 1.2rem;
      padding-inline: 2rem;
    
      > * + * {
        margin-block-start: 1.5rem;
      }
    
      :is(h2) {
        font-size: 1.3em;
        font-weight: bold;
      }
    
      :is(h3) {
        font-size: 1.1em;
        font-weight: bold;
      }
    
      :is(blockquote) {
        border-inline-start: 0.5rem solid currentColor;
        padding-inline-start: 1.5rem;
      }
    
      :is(ul, ol) {
        padding-inline-start: 2rem;
      }
    
      :is(pre) {
        font-family: monospace;
        white-space: nowrap;
      }
    
      :is(hr) {
        border-block-start: 1px solid currentColor;
      }
    
      :is(a) {
        color: var(--hyperlink-color);
        text-decoration-color: var(--hyperlink-color);
        text-decoration-line: underline;
        text-decoration-style: solid;
        text-decoration-thickness: 1px;
      }
    }
    
  • URL: /components/raw/richtext/richtext.scss
  • Filesystem Path: src/components/2-molecules/richtext/richtext.scss
  • Size: 3 KB
  • Content:
    import type Trix from 'trix';
    import onLoad from '../../../javascripts/utils/onLoad';
    
    onLoad('.richtext', async () => {
      document.querySelectorAll<HTMLInputElement>('input[data-trix-validate-href]').forEach(($input) => {
        $input.name = $input.dataset.name ?? '';
      });
    
      const { default: trix } = await import(/* webpackChunkName: "trix" */ 'trix') as { default: Trix };
    
      trix.config.blockAttributes.heading2 = {
        tagName: 'h2',
        terminal: true,
        breakOnReturn: true,
        group: false,
      };
    
      trix.config.blockAttributes.heading3 = {
        tagName: 'h3',
        terminal: true,
        breakOnReturn: true,
        group: false,
      };
    
      trix.config.blockAttributes.default = {
        tagName: 'p',
        parse: false,
        breakOnReturn: true,
      };
    
      trix.Block.prototype.breaksOnReturn = function breaksOnReturn() {
        const attr = this.getLastAttribute();
        const config = trix.config.blockAttributes[attr || "default"];
    
        return config ? config.breakOnReturn : false;
      };
    
      trix.LineBreakInsertion.prototype.shouldInsertBlockBreak = function shouldInsertBlockBreak() {
        if (this.block.hasAttributes() && this.block.isListItem() && !this.block.isEmpty()) {
            return this.startLocation.offset > 0;
        }
    
        return !this.shouldBreakFormattedBlock() ? this.breaksOnReturn : false;
      };
    });
    
    document.addEventListener('trix-attachment-add', (event) => {
      event.preventDefault();
    });
    
  • URL: /components/raw/richtext/richtext.ts
  • Filesystem Path: src/components/2-molecules/richtext/richtext.ts
  • Size: 1.4 KB

No notes defined.