Nachbildung des CodePen Gutenberg Embed Blocks für Sanity.io

Avatar of Knut Melvær
Knut Melvær am

DigitalOcean bietet Cloud-Produkte für jede Phase Ihrer Reise. Starten Sie mit 200 $ kostenlosem Guthaben!

Chris hat kürzlich einen netten CodePen Embed Block für den Gutenberg-Editor in WordPress veröffentlicht. Er ermöglicht es Ihnen, einen Pen einzubetten, indem Sie einfach seine URL einfügen. Von dort aus haben Sie Zugriff auf die Steuerung der Größe, des Themas und der Standard-Tabs, die beim erstmaligen Laden gerendert werden. Super nett!

Eine Live-Vorschau des eingebetteten Pens während des Schreibens ist so praktisch!

Aber es hat mich zum Nachdenken gebracht: Wie schwierig wäre es, ihn mit dem Portable Text Editor von Sanity Studio nachzubilden? (Spoiler: Nicht so schwierig). Da ich bereits wusste, wie es geht, hat es mich von Anfang bis Ende weniger als sieben Minuten gekostet. Dieses Tutorial führt Sie durch die Einrichtung eines Studios und die Hinzufügung der Schemata und der benutzerdefinierten Vorschaukomponente für einen CodePen-Embed.

Das fühlte sich so cool an, dass ich Ihnen auch beibringen möchte, wie es geht. Tauchen wir direkt ein.

Sanity Studio lokal einrichten und ausführen

Zuerst müssen Sie Sanity Studio lokal auf Ihrem Rechner installieren. In diesem Tutorial verwenden wir das Blog-Studio, das Sie über die Kommandozeile starten können, aber Sie können sich auch die verschiedenen Starter unter sanity.io/create ansehen. Mit denen sollten Sie auch zurechtkommen.

Dieses Tutorial setzt voraus, dass Sie über Grundkenntnisse in JavaScript verfügen. Es wird ein wenig React verwendet, aber nur ein kleiner Teil. Sie sollten Node und npm installiert haben, falls noch nicht geschehen.

Und Sie benötigen die Sanity CLI, die Sie über die Kommandozeile erhalten können

npm install --global @sanity/cli

Sobald die Installation abgeschlossen ist, können Sie ein neues Sanity Studio mit einem neuen Projekt starten, indem Sie den Befehl sanity init ausführen. Sie werden sich mit Ihrem Google- oder GitHub-Konto anmelden können (oder ein neues Konto mit E-Mail/Passwort erstellen). Geben Sie Ihrem Projekt einen Namen und folgen Sie den Anweisungen. Wenn Sie die Auswahl für eine Projektvorlage erhalten, wählen Sie die Blog-Vorlage.

? Select project template
  Movie project (schema + sample data)
  E-commerce (schema + sample data)
❯ Blog (schema)
  Clean project with no predefined schemas

Nach Abschluss der Schritte wechseln Sie in den Ordner des neuen Projekts (cd) und öffnen Sie ihn in Ihrem bevorzugten Code-Editor. Um den Entwickler-Server zu starten, der Ihr Studio bei Änderungen auch per Hot Reload aktualisiert, führen Sie sanity start aus. Um diesen Server zu stoppen, drücken Sie ctrl + C in den meisten Kommandozeilen-Tools.

Hinzufügen der Schemata für einen CodePen-Embed

Schemata definieren, welche Dokumenttypen im Studio verfügbar sind und welche Eingabefelder sie haben. Diese Schemata werden in JavaScript-Objekten definiert, die Sie in die Datei schemas.js importieren, wo sie als Funktion exportiert werden, die das Studio in seine Benutzeroberfläche übersetzt. Mit diesen Schemata kann man viel machen, aber in diesem Tutorial halten wir es einigermaßen einfach.

Beginnen Sie damit, eine neue Datei in /yourproject/schemas mit dem Namen codepen.js hinzuzufügen. Geben Sie dann diesen Code ein

export default {
  name: "codepen",
  type: "object",
  title: "CodePen Embed",
  fields: [
    {
      name: "url",
      type: "url",
      title: "CodePen URL"
    }
  ]
};

Dann können Sie zu /yourproject/schemas/schema.js gehen und die folgenden beiden Codezeilen hinzufügen

import createSchema from "part:@sanity/base/schema-creator";
import schemaTypes from "all:part:@sanity/base/schema-type";

import blockContent from "./blockContent";
import category from "./category";
import post from "./post";
import author from "./author";
import codepen from "/codepen.js"; // <= first import the object

export default createSchema({
  name: "default",
  types: schemaTypes.concat([
    post,
    author,
    category,
    blockContent,
    codepen // <= add it to the schema types array
  ])
});

Was haben wir gerade getan? Nun, wir haben dieses CodePen-Objekt als type in anderen Schemata im Studio verfügbar gemacht. Mit anderen Worten, Sie können jetzt type: 'codepen' hinzufügen, um diese Felder überall dort zu erhalten, wo Sie in den Schema-Code Felder hinzufügen. Das Hinzufügen dieses Typs zum Rich-Text-Feld ist auch unser nächster Schritt. Warten Sie!

Hinzufügen des CodePen-Feldes zum Rich-Text-Editor

Bevor wir uns dem Code zuwenden, machen wir einen Schritt zurück und schauen uns an, was mit den Datenformaten passiert, mit denen wir arbeiten, und wie sich WordPress und Sanity leicht unterscheiden.

Während Gutenberg Rich-Text zur Laufzeit als JSON speichert (was großartig ist!), ist das, womit Entwickler letztendlich zu tun haben, meistens dieser Inhalt als HTML und JSON-Objekte innerhalb von HTML-Kommentaren.

Sanity speichert und verteilt Rich-Text-Inhalte als Portable Text, das Entwickler dann in ihren Frontends serialisieren. Das bedeutet, dass Sie die volle Kontrolle darüber haben, wie Rich-Text-Inhalte gerendert werden, indem Sie benutzerdefinierte Komponenten für Ihr bevorzugtes Framework verwenden, sei es ReactVueSvelte, oder .NETPHP, oder sogar Markdown.

Mit anderen Worten, Sie speichern Ihre Inhalte als strukturierte Daten im Sanity-Backend und entscheiden dann, wie Sie die Daten in Ihren Frontend-Komponenten verwenden möchten. Aber genug der Ausführungen, zurück zum Code!

Öffnen Sie /schemas/blockContent.js und bemerken Sie, dass es vom Typ array ist. Ja, Rich-Text ist ein Array verschiedener Typen, von denen einer vom Typ block sein muss (in dem Textabsätze gespeichert werden). Der einfachste Weg, Rich-Text zu erstellen, ist also die folgende Schema-Definition

export default {
  name: "body",
  type: "array",
  title: "Body",
  of: [
    {
      type: "block"
    }
  ]
};

Nun hat blockContent.js noch einiges mehr zu bieten. Sie sehen styles, lists, marks, und so weiter. Alle definieren, welche Eigenschaften dem Autor zur Verfügung stehen sollten. Im oberen Array gibt es zwei Typen: block und image. Wir werden den dritten hinzufügen: codepen

export default {
  title: "Block Content",
  name: "blockContent",
  type: "array",
  of: [
    {
      type: "block"
      // ...
    },
    {
      type: "image",
      options: { hotspot: true }
    },
    {
      type: "codepen"
    }
  ]
};

Speichern Sie die Datei, und das war's! Wenn Sie jetzt sanity start in Ihrer Kommandozeile ausführen (vorausgesetzt, Sie haben dies noch nicht getan) und das Studio unter https://:3333 öffnen, sollten Sie Ihr neues Feld im Rich-Text-Editor unter dem Typ "post" finden.

Sanity Studio with a CodePen button in the Rich Text editor.

Wenn Sie den neuen Button ausprobieren, erhalten Sie ein Modal mit dem Feld für die URL, das Sie im vorherigen Abschnitt definiert haben. Fügen Sie gerne die URL eines coolen CodePens ein, den Sie gefunden haben. Wir werden diesen von der legendären Sara Drasner verwenden; er ist ziemlich cool.

Nur den URL-Wert im Editor anzuzeigen, ist jedoch nicht besonders inspirierend. Lassen Sie uns also den tatsächlichen CodePen-Embed hinzufügen, damit wir direkt im Editor damit interagieren können!

Hinzufügen des CodePen-Embeds als Vorschau

Öffnen Sie /yourproject/schemas/codepen.js erneut. Jetzt erstellen wir eine kleine React-Komponente für unsere Vorschau. Beginnen Sie damit, React oben zu importieren, und die Vorlage für die React-Komponente, die wir in den Embed umwandeln werden

import React from "react";

const CodePenPreview = ({ value }) => {
  return <pre>{JSON.stringify(value, null, 2)}</pre>;
};

export default {
  name: "codepen",
  type: "object",
  title: "CodePen Embed",
  fields: [
    {
      name: "url",
      type: "url",
      title: "CodePen URL"
    }
  ]
};

Die JSON.stringify -Sache ist eine vorübergehende kleine Methode, um die eingehenden Daten lesbar auszugeben. Sie könnten auch console.log(value) verwenden, aber wer hat schon Zeit, die Entwicklerkonsole zu öffnen?

Jetzt müssen Sie Sanity mitteilen, wie diese Komponente für die Vorschau verwendet werden soll. Sowie welche Felder im Objekt es für den value in der Vorschaukomponente selecten soll.

import React from "react";

const CodePenPreview = ({ value }) => {
  return <pre>{JSON.stringify(value, null, 2)}</pre>;
};

export default {
  name: "codepen",
  type: "object",
  title: "CodePen Embed",
  preview: {
    select: {
      url: "url"
    },
    component: CodePenPreview
  },
  fields: [
    {
      name: "url",
      type: "url",
      title: "CodePen URL"
    }
  ]
};

Der Editor sollte nach dem Speichern Ihrer Änderungen etwa so aussehen

Kühl! Jetzt wollen wir den url-Wert nehmen und ihn irgendwie mit einem CodePen-Embed integrieren. Der einfachste Weg, dies zu tun, ist, das Markup für CodePens iFrame-Embed anzupassen und es in unsere Vorschaukomponente in React einzufügen.

Das ursprüngliche iFrame-Element sieht so aus

<iframe height="265" style="width: 100%;" scrolling="no" title="React Animated Page Transitions" src="https://codepen.io/sdras/embed/gWWQgb?height=265&theme-id=dark&default-tab=js,result" frameborder="no" allowtransparency="true" allowfullscreen="true">
  See the Pen <a href='https://codepen.io/sdras/pen/gWWQgb'>React Animated Page Transitions</a> by Sarah Drasner
  (<a href='https://codepen.io/sdras'>@sdras</a>) on <a href='https://codepen.io'>CodePen</a>.
</iframe>

Wenn wir diesen Ausschnitt in unsere Vorschaukomponente einfügen, wird er *fast* funktionieren. Um ihn JSX-kompatibel zu machen, müssen Sie einige Änderungen an einigen HTML-Attributen vornehmen. Stellen Sie sicher, dass Sie Folgendes ändern:

  • style="width: 100%;" zu style={{width: "100%"}}
  • frameborder="no" zu frameBorder="no"
  • allow-transparency="true" zu allowTransparency
  • allow-fullscreen="true" zu allowFullScreen

Sie können den Inhalt (Links usw.) innerhalb des Iframes entfernen, da er im Studio nicht besonders nützlich ist. Was wir am Ende haben sollten, ist etwa so etwas

import React from "react";
import Codepen from "react-codepen-embed";

const CodePenPreview = ({ value }) => {
  return (
    <iframe
      height="265"
      style={{ width: '100%' }}
      scrolling="no"
      title="React Animated Page Transitions"
      src="https://codepen.io/sdras/embed/gWWQgb?height=370&theme-id=dark&default-tab=js,result"
      frameBorder="no"
      allowTransparency
      allowFullScreen
    />);
};

// ...

Nach dem Speichern sollten wir den CodePen-Embed im Rich-Text-Editor sehen können

Beachten Sie, dass der iFrame eine Embed-URL mit einigen Parametern für die Anzeige enthält. Natürlich könnten wir jemanden gebeten haben, sich CodePen anzusehen, um diese URL zu erhalten, aber es ist wahrscheinlich besser für uns, die reguläre zu verwenden. Wir werden uns die Mühe machen, sie zu dem zusammenzusetzen, was wir brauchen

Der letzte Teil ist, die URL aus dem Feld zu nehmen und den hash und user daraus zu extrahieren.

Wir teilen die URL-Zeichenkette anhand von Schrägstrichen in ein Array auf. Dann verwenden wir Array-Destrukturierung, um die verschiedenen Array-Elemente einer Variablen zuzuweisen. Da wir nur den user und den hash benötigen, lassen wir die anderen Positionen leer. Diese Methode ist nicht narrensicher, da sie ein bestimmtes URL-Format voraussetzt, aber für dieses Beispiel funktioniert sie. Dann setzen wir die embedUrl mit Template-Literalen wieder zusammen.

import React from "react";

const CodePenPreview = ({ value }) => {
  const { url } = value;
  if (!url) {
    return (<div>Add a CodePen URL</div>)
  }
  const splitURL = url.split("/");
  // [ 'https:', '', 'codepen.io', 'sdras', 'pen', 'gWWQgb' ]
  const [, , , user, , hash] = splitURL;
  const embedUrl = `https://codepen.io/${user}/embed/${hash}?height=370&theme-id=dark&default-tab=result`;
  return (
    <iframe
      height="370"
      style={{ width: '100%' }}
      scrolling="no"
      title="CodePen Embed"
      src={embedUrl}
      frameBorder="no"
      allowTransparency
      allowFullScreen
    />
  );
};
// ...

Speichern Sie die Änderungen und voilà; wir sind so gut wie fertig mit dem benutzerdefinierten CodePen-Block!

Weiterführend

Nun, Sie haben wahrscheinlich bemerkt, dass Chris weitere Einstellungen in seinen benutzerdefinierten Block integriert hat. Nichts hindert uns daran, dasselbe zu tun! Wenn wir die Dokumentation für die React CodePen Embed Komponente, die wir installiert haben, nachschlagen, finden wir eine Tabelle mit Eigenschaften, die sie übernehmen kann. Wir können diese als Felder in der Schema-Definition hinzufügen. Zum Beispiel, wenn wir den themeId hinzufügen wollten, könnten wir es so tun

import React from "react";
import Codepen from "react-codepen-embed";

const CodePenPreview = ({ value }) => {
  const { url, themeId = "dark" } = value; // <= add themeId here, default it to "dark"
  if (!url) {
    return (<div>Add a CodePen URL</div>)
  }
  const splitURL = url.split("/");
  // [ 'https:', '', 'codepen.io', 'sdras', 'pen', 'gWWQgb' ]
  const [, , , user, , hash] = splitURL;
  const embedUrl = `https://codepen.io/${user}/embed/${hash}?height=370&theme-id=${themeId}&default-tab=result`; // <= add themeId here
  return (
    <iframe
      height="370"
      style={{ width: '100%' }}
      scrolling="no"
      title="CodePen Embed"
      src={embedUrl}
      frameBorder="no"
      allowTransparency
      allowFullScreen
    />
  );
};

export default {
  name: "codepen",
  type: "object",
  title: "CodePen Embed",
  preview: {
    select: {
      url: "url",
      themeId: "themeId" // <= add themeId here
    },
    component: CodePenPreview
  },
  fields: [
    {
      name: "url",
      type: "url",
      title: "CodePen URL"
    },
    // Add the new field below
    {
      name: "themeId",
      type: "string",
      title: "Theme ID",
      description: 'You can use "light" and "dark" also.'
    }
  ]
};

Fazit

Wir haben gerade die Funktionsweise von Schemata für Sanity Studio betrachtet und gelernt, wie man Vorschauen für benutzerdefinierte Komponenten erstellt. Hoffentlich wissen Sie jetzt genug, um mit diesen Prinzipien so gut wie *jede* benutzerdefinierte Komponente mit einer Vorschau zu erstellen. Wenn ja, würde ich es gerne entweder auf Twitter oder in den Kommentaren erfahren.