diff --git a/playbook-website/app/controllers/pages_controller.rb b/playbook-website/app/controllers/pages_controller.rb index f77d856a7d..89f1c6f87a 100755 --- a/playbook-website/app/controllers/pages_controller.rb +++ b/playbook-website/app/controllers/pages_controller.rb @@ -16,6 +16,9 @@ class PagesController < ApplicationController before_action :set_category, only: %i[kit_category_show_rails kit_category_show_react] before_action :delete_dark_mode_cookie, only: %i[home getting_started visual_guidelines] + include Playbook::PbDocHelper + include Playbook::PbKitHelper + def disable_dark_mode cookies[:dark_mode] = { value: "false", @@ -79,10 +82,39 @@ def kit_show_react render template: "pages/kit_show", layout: "layouts/kits" end - def kit_show_new + def kit_playground_rails + @kit = "avatar" + @examples = pb_doc_kit_examples(@kit, "rails") + @raw_example = view_context.pb_rails("docs/kit_example", props: { + kit: @kit, + example_title: @examples.first.values.first, + example_key: @examples.first.keys.first, + type: "rails", + dark: false, + code_only: true, + }) + render "pages/rails_in_react_playground", layout: "layouts/fullscreen" + end + + def rails_pg_render + render inline: erb_code_params + rescue => e + render json: { error: e }, status: 400 + end + + def rails_in_react @kit = params[:name] - @examples = kit_examples - render "pages/kit_show_new", layout: "layouts/kits" + @examples = pb_doc_kit_examples(@kit, "rails") + @raw_example = view_context.pb_rails("docs/kit_example", props: { + kit: @kit, + example_title: @examples.first.values.first, + example_key: @examples.first.keys.first, + show_code: false, + type: "rails", + dark: false, + show_raw: true, + }) + render "pages/rails_in_react", layout: "layouts/kits" end def kit_show_demo @@ -91,7 +123,20 @@ def kit_show_demo render "pages/kit_show_demo", layout: "layouts/kits" end - def principles; end + def rails_raw + @kit = params[:name] + example = pb_doc_kit_examples(@kit, "rails").first + raw_example = view_context.pb_rails("docs/kit_example", props: { + kit: @kit, + example_title: example.values.first, + example_key: example.keys.first, + show_code: false, + type: "rails", + dark: false, + show_raw: true, + }) + render inline: raw_example, layout: false + end # TODO: rename this method once all guidelines are completed def visual_guidelines @@ -169,6 +214,10 @@ def kit_examples pb_doc_kit_examples(params[:name], "rails") end + def erb_code_params + params.require(:erb_code) + end + def read_kit_file(*args) path = ::Playbook.kit_path(@kit, "docs", *args) path.exist? ? path.read : "" diff --git a/playbook-website/app/javascript/components/KitDemo/index.tsx b/playbook-website/app/javascript/components/KitDemo/index.tsx deleted file mode 100644 index c42c573b20..0000000000 --- a/playbook-website/app/javascript/components/KitDemo/index.tsx +++ /dev/null @@ -1,57 +0,0 @@ -import React from "react" -import { - SandpackProvider, - SandpackLayout, - SandpackCodeEditor, - SandpackPreview, -} from "@codesandbox/sandpack-react" - -import { Card, Caption } from "playbook-ui" - -const KitDemo = ({ source, exampleTitle }) => { - const updatedFileContent = source.replace(/\'..\/..\/?\'/g, "'playbook-ui'").replace(/\"..\/..\/?\"/g, "'playbook-ui'") - const files = { - "/App.js": { - code: updatedFileContent, - }, - } - - return ( - <> - - - -
-
- - - -
-
-
-
-
- - ) -} - -export default KitDemo diff --git a/playbook-website/app/javascript/components/PbKitFetch/index.tsx b/playbook-website/app/javascript/components/PbKitFetch/index.tsx new file mode 100644 index 0000000000..b78e0fcc7c --- /dev/null +++ b/playbook-website/app/javascript/components/PbKitFetch/index.tsx @@ -0,0 +1,45 @@ +import React, { useEffect, useState } from 'react' + +import { Title, LoadingInline } from 'playbook-ui' + +const PbKitFetch = ({ kit }) => { + const [serverData, setServerData] = useState(null) + const [loading, setLoading] = useState(true) + const [error, setError] = useState(null) + + useEffect(() => { + fetch('/kits/avatar/rails_raw') + .then((response) => response.text()) + .then((data) => { + console.log(data) + debugger + setLoading(false) + setServerData(data) + }) + .catch((err) => { + console.log(err) + setLoading(false) + setError(err) + }) + }, []) + + const unescapeHtml = function (value) { + var div = document.createElement('div') + div.innerHTML = value + return div.textContent + } + + return ( + <> + + { loading && <LoadingInline align="center" /> } + <span dangerouslySetInnerHTML={{__html: serverData}} /> + </> + ) +} + +export default PbKitFetch diff --git a/playbook-website/app/javascript/components/PbKitPlayground/index.tsx b/playbook-website/app/javascript/components/PbKitPlayground/index.tsx new file mode 100644 index 0000000000..825ada93bf --- /dev/null +++ b/playbook-website/app/javascript/components/PbKitPlayground/index.tsx @@ -0,0 +1,137 @@ +/* eslint-disable flowtype/no-types-missing-file-annotation */ +/* eslint-disable comma-dangle */ +/* eslint-disable jsx-control-statements/jsx-use-if-tag */ +/* eslint-disable react/no-danger */ +import React, { useEffect, useState } from 'react' + +import Editor from 'react-simple-code-editor' +import { highlight, languages } from 'prismjs/components/prism-core' +import 'prismjs/components/prism-clike' +import 'prismjs/components/prism-javascript' +import 'prismjs/components/prism-markup-templating' +import 'prismjs/components/prism-ruby' +import 'prismjs/components/prism-erb' +import 'prismjs/plugins/unescaped-markup/prism-unescaped-markup' +import 'prismjs/themes/prism-okaidia.css' + +import { LoadingInline, FixedConfirmationToast } from 'playbook-ui' + +const PbKitPlayground = () => { + const [previewData, setPreviewData] = useState(null) + const [loading, setLoading] = useState(true) + const [error, setError] = useState(null) + const [code, setCode] = React.useState('<%= pb_rails("title", props: { text: "Welcome to Playbook", size: 1 }) %>') + const [token, setToken] = useState(null) + const [throttleFetch, setThrottleFetch] = useState(false) + + useEffect(() => { + var throttleTimer + if (throttleTimer) clearTimeout(throttleTimer) + setThrottleFetch(true) + throttleTimer = setTimeout(() => { + if (token) getPreview(code) + }, 2000) + return () => clearInterval(throttleTimer) + }, [code]) + + useEffect(() => { + if (token) { + getPreview(code) + } else { + const getToken = document.querySelector('[name="csrf-token"]').content + setToken(getToken) + } + }, [token]) + + const saveCode = (code: string) => { + setCode(code) + } + + const getPreview = (code: string) => { + const requestOptions = { + method: 'POST', + headers: { + 'X-CSRF-Token': token, + 'Content-Type': 'application/json', + }, + body: JSON.stringify({ erb_code: code }) + } + setError(null) + setLoading(true) + fetch('/rails_pg_render', requestOptions) + .then((response) => { + if (response.ok) { + response.text().then((text) => { + setPreviewData(text) + setLoading(false) + }) + } + if (response.status === 400) { + response.json().then((rv) => { + setLoading(false) + setError(rv.error) + }) + } + }) + .catch((err) => { + setLoading(false) + setError(err) + }) + return () => { + setLoading(false) + clearTimeout(throttleTimer) + setThrottleFetch(false) + } + } + + const showPreview = () => { + if (loading) { + return ( + <LoadingInline + align="center" + className="pbDocPlayground-Preview-Loading" + /> + ) + } else { + if (error) { + return ( + <FixedConfirmationToast + className="pbDocPlayground-Preview-Error" + status="error" + text={error} + /> + ) + } else { + return ( + <div + className="pbDocPlayground-Preview-Example" + dangerouslySetInnerHTML={{ __html: previewData }} + /> + ) + } + } + } + + return ( + <div className="pbDocPlayground"> + <div className="pbDocPlayground-Editor"> + <Editor + className="language-erb" + highlight={(code) => highlight(code, languages.js)} + onValueChange={(code) => saveCode(code)} + style={{ + fontFamily: 'monospace', + fontSize: 16, + }} + value={code} + /> + {throttleFetch} + </div> + <div className="pbDocPlayground-Preview"> + { showPreview() } + </div> + </div> + ) +} + +export default PbKitPlayground diff --git a/playbook-website/app/javascript/components/PbKitReact/index.tsx b/playbook-website/app/javascript/components/PbKitReact/index.tsx new file mode 100644 index 0000000000..35a8502464 --- /dev/null +++ b/playbook-website/app/javascript/components/PbKitReact/index.tsx @@ -0,0 +1,19 @@ +import React from 'react' + +import { Title } from 'playbook-ui' + +const PbKitReact = ({ kit, rawHTML }) => { + + return ( + <> + <Title + size={4} + tag="h1" + text={kit} + /> + <span dangerouslySetInnerHTML={{__html: rawHTML}} /> + </> + ) +} + +export default PbKitReact diff --git a/playbook-website/app/javascript/components/VisualGuidelines/Examples/Cursor.tsx b/playbook-website/app/javascript/components/VisualGuidelines/Examples/Cursor.tsx index 3c6671ed47..e6225c528b 100644 --- a/playbook-website/app/javascript/components/VisualGuidelines/Examples/Cursor.tsx +++ b/playbook-website/app/javascript/components/VisualGuidelines/Examples/Cursor.tsx @@ -1,50 +1,15 @@ import React from "react" -import { Card, Caption, FlexItem, Flex, Body } from 'playbook-ui' -import Example from '../Templates/Example' - -const CURSOR = [ - "auto", "default", "none", "contextMenu", "help", "pointer", "progress", "wait", "cell", - "crosshair", "text", "verticalText", "alias", "copy", "move", "noDrop", "notAllowed", "grab", - "grabbing", "eResize", "nResize", "neResize", "nwResize", "sResize", "seResize", "swResize", "wResize", - "ewResize", "nsResize", "neswResize", "nwseResize", "colResize", "rowResize", "allScroll", "zoomIn", "zoomOut", -] - -const Cursor = ({ example }: { example: string }) => ( - <> - <Example - example={example} - globalProps={{ - cursor: CURSOR - }} - title="Cursor" - /> - <Card - marginTop="md" - padding="none" - rounded - shadow="deeper" - > - <FlexItem> - <Card.Body> - <Caption - marginBottom="xs" - text="Visual Guide" - /> - <Body text="Hover over any card below to display its cursor." marginBottom="sm" /> - - <Flex gap="xxs" wrap> - {CURSOR.map(function (cursor, i) { - return <Card borderRadius="none" padding="xs" cursor={cursor} key={i}> - {cursor} - </Card> - })} - </Flex> +import Example from '../Templates/Example' - </Card.Body> - </FlexItem> - </Card> - </> +const Cursor = ({example}: {example: string}) => ( + <Example + example={example} + globalProps={{ + cursor: ["pointer"] + }} + title="Cursor" + /> ) export default Cursor diff --git a/playbook-website/app/javascript/packs/application.js b/playbook-website/app/javascript/packs/application.js index 2cbfd87cb7..d98f22f615 100644 --- a/playbook-website/app/javascript/packs/application.js +++ b/playbook-website/app/javascript/packs/application.js @@ -16,7 +16,9 @@ import KitSearch from '../components/KitSearch' import SnippetToggle from '../components/SnippetToggle' import Sidebar from '../components/Sidebar' import KitDocs from '../components/KitDocs' -import KitDemo from '../components/KitDemo' +import PbKitReact from '../components/PbKitReact' +import PbKitFetch from '../components/PbKitFetch' +import PbKitPlayground from '../components/PbKitPlayground' WebpackerReact.setup({ DarkModeToggle, @@ -24,7 +26,9 @@ WebpackerReact.setup({ SnippetToggle, Sidebar, KitDocs, - KitDemo, + PbKitReact, + PbKitFetch, + PbKitPlayground, }) // Produce image assets diff --git a/playbook-website/app/javascript/site_styles/docs/_code_snippet.scss b/playbook-website/app/javascript/site_styles/docs/_code_snippet.scss index 98fb94942f..e7c5432039 100755 --- a/playbook-website/app/javascript/site_styles/docs/_code_snippet.scss +++ b/playbook-website/app/javascript/site_styles/docs/_code_snippet.scss @@ -1,5 +1,7 @@ @import "playbook-ui/dist/tokens/colors"; + +// Rails & REACT .pb--codeCopy { .highlight { margin: 20px 0; @@ -532,3 +534,38 @@ overflow-x: auto; } } + + +// New React Based Editor using Prism + +.pbDocPlayground { + display: flex; + width: 100vw; + height: 100vh; + &-Editor { + background: $bg_dark; + font-weight: 700; + padding-top: $space_lg; + padding-left: $space_md; + flex: 1; + flex-basis: 50vw; + textarea { + outline: 0; + } + } + &-Preview { + flex: 1; + flex-basis: 50vw; + overflow: auto; + display: block; + &-Example { + } + &-Loading { + flex: 1; + place-self: center; + } + &-Error { + padding: $space_lg; + } + } +} \ No newline at end of file diff --git a/playbook-website/app/views/layouts/fullscreen.html.erb b/playbook-website/app/views/layouts/fullscreen.html.erb new file mode 100755 index 0000000000..a76943b991 --- /dev/null +++ b/playbook-website/app/views/layouts/fullscreen.html.erb @@ -0,0 +1,14 @@ +<!DOCTYPE html> +<html> + <head> + <title> Playbook Design System + <%= csrf_meta_tags%> + <%= csp_meta_tag%> + <%= stylesheet_packs_with_chunks_tag 'application' %> + + + + <%= yield %> + + <%= javascript_packs_with_chunks_tag 'application', 'site' %> + \ No newline at end of file diff --git a/playbook-website/app/views/layouts/fullscreen.html.slim b/playbook-website/app/views/layouts/fullscreen.html.slim deleted file mode 100755 index ec3123d38b..0000000000 --- a/playbook-website/app/views/layouts/fullscreen.html.slim +++ /dev/null @@ -1,10 +0,0 @@ -doctype html -html - head - title Playbook Design System - = csrf_meta_tags - = csp_meta_tag - = stylesheet_packs_with_chunks_tag 'application' - = javascript_packs_with_chunks_tag 'application', 'site' - body - = yield diff --git a/playbook-website/app/views/layouts/rails_raw.html.erb b/playbook-website/app/views/layouts/rails_raw.html.erb new file mode 100755 index 0000000000..b7342cd9f1 --- /dev/null +++ b/playbook-website/app/views/layouts/rails_raw.html.erb @@ -0,0 +1,9 @@ + + + + Playbook Design System + + + <%= yield %> + + diff --git a/playbook-website/app/views/pages/kit_show_demo.html.erb b/playbook-website/app/views/pages/kit_show_demo.html.erb deleted file mode 100644 index cb4d563501..0000000000 --- a/playbook-website/app/views/pages/kit_show_demo.html.erb +++ /dev/null @@ -1,17 +0,0 @@ -
- <%= pb_rails("title", props: { text: pb_kit_title(@kit), tag: "h1", size: 1, margin_top: "xl" }) %> -
"> - <%= markdown(pb_doc_kit_description(@kit)) %> -
-
- -
- <% @examples.each do |example| %> - <%= react_component("KitDemo", kit: @kit, source: get_source(example.keys.first), exampleTitle: example.values.first) %> - <% end %> - -
"> -
- <%= markdown(pb_doc_kit_footer(@kit)) %> -
-
\ No newline at end of file diff --git a/playbook-website/app/views/pages/rails_in_react.html.erb b/playbook-website/app/views/pages/rails_in_react.html.erb new file mode 100644 index 0000000000..a5d3af5942 --- /dev/null +++ b/playbook-website/app/views/pages/rails_in_react.html.erb @@ -0,0 +1,8 @@ + +<%= "#{@kit} in Rails rendered though React" %> +
+
+<%= react_component("PbKitReact", kit: "Passed via Props from Controller", rawHTML: @raw_example) %> +
+
+<%= react_component("PbKitFetch", kit: "Example Fetched from Server") %> \ No newline at end of file diff --git a/playbook-website/app/views/pages/rails_in_react_playground.html.erb b/playbook-website/app/views/pages/rails_in_react_playground.html.erb new file mode 100644 index 0000000000..d0beb79136 --- /dev/null +++ b/playbook-website/app/views/pages/rails_in_react_playground.html.erb @@ -0,0 +1,3 @@ +<%# @raw_example.html_safe%> + +<%= react_component("PbKitPlayground", kit: "Example Fetched from Server") %> \ No newline at end of file diff --git a/playbook-website/config/routes.rb b/playbook-website/config/routes.rb index 87c6968279..5dad7034ca 100644 --- a/playbook-website/config/routes.rb +++ b/playbook-website/config/routes.rb @@ -6,14 +6,19 @@ get "getting_started", to: "pages#getting_started" get "kits", to: "pages#kits" get "visual_guidelines", to: "pages#visual_guidelines" - get "changelog", to: "pages#changelog" + get "changelog", to: "pages#changelog" - get "kits/:name", to: "pages#kit_show_rails", as: "kit_show" - get "kits/:name/demo", to: "pages#kit_show_demo", as: "kit_show_demo" - get "kits/:name/sandpack", to: "pages#kit_show_new", as: "kit_show_new" - get "kits/:name/rails", to: "pages#kit_show_rails", as: "kit_show_rails" - get "kits/:name/react", to: "pages#kit_show_react", as: "kit_show_reacts" - get "all_kit_examples", to: "pages#all_kit_examples" + get "kits/:name", to: "pages#kit_show_rails", as: "kit_show" + get "kits/:name/rails", to: "pages#kit_show_rails", as: "kit_show_rails" + get "kits/:name/react", to: "pages#kit_show_react", as: "kit_show_reacts" + get "all_kit_examples", to: "pages#all_kit_examples" + + # Experiments + get "kits/:name/sandpack", to: "pages#kit_show_new", as: "kit_show_new" + get "kits/:name/rails_in_react", to: "pages#rails_in_react", as: "rails_in_react" + get "kits/:name/rails_raw", to: "pages#rails_raw", as: "rails_raw" + get "kit_playground_rails", to: "pages#kit_playground_rails", as: "kit_playground_rails" + post "rails_pg_render", to: "pages#rails_pg_render", as: "rails_pg_render" get "kit_category/:name", to: "pages#kit_category_show_rails", as: "kit_category_show" get "kit_category/:name/rails", to: "pages#kit_category_show_rails", as: "kit_category_show_rails" diff --git a/playbook-website/package.json b/playbook-website/package.json index 5bacb34415..b8f2985440 100644 --- a/playbook-website/package.json +++ b/playbook-website/package.json @@ -8,13 +8,15 @@ "release": "RAILS_ENV=production NODE_ENV=production ./bin/webpack" }, "dependencies": { - "@mapbox/mapbox-gl-draw": "^1.4.1", "@fortawesome/fontawesome-pro": "^6.2.1", + "@mapbox/mapbox-gl-draw": "^1.4.1", "@rails/webpacker": "5.2.1", "maplibre-gl": "^2.4.0", "playbook-ui": ">= 1", + "prismjs": "^1.29.0", "react": "^17.0.2", "react-dom": "^17.0.2", + "react-simple-code-editor": "^0.13.1", "trix": "1.3.1", "webpacker-react": "^0.3.2", "zxcvbn": "^4.4.2"