diff --git a/frontend/package.json b/frontend/package.json index 1cb1fcb12..1b4f1b475 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -29,6 +29,7 @@ }, "dependencies": { "date-fns": "^2.15.0", + "highlight.js": "^10.3.1", "map-stream": "0.0.7", "mousetrap": "^1.6.5", "randomcolor": "^0.6.2", diff --git a/frontend/resources/styles/common/dependencies/highlightjs-theme.scss b/frontend/resources/styles/common/dependencies/highlightjs-theme.scss new file mode 100644 index 000000000..ba9963ff5 --- /dev/null +++ b/frontend/resources/styles/common/dependencies/highlightjs-theme.scss @@ -0,0 +1,81 @@ +/* +Monokai Sublime style. Derived from Monokai by noformnocontent http://nn.mit-license.org/ +*/ + +.hljs { + display: block; + overflow-x: auto; + padding: 0.5em; + background: #23241f; +} + +.hljs, +.hljs-tag, +.hljs-subst { + color: #f8f8f2; +} + +.hljs-strong, +.hljs-emphasis { + color: #a8a8a2; +} + +.hljs-bullet, +.hljs-quote, +.hljs-number, +.hljs-regexp, +.hljs-literal, +.hljs-link { + color: #ae81ff; +} + +.hljs-code, +.hljs-title, +.hljs-section, +.hljs-selector-class { + color: #a6e22e; +} + +.hljs-strong { + font-weight: bold; +} + +.hljs-emphasis { + font-style: italic; +} + +.hljs-keyword, +.hljs-selector-tag, +.hljs-name, +.hljs-attr { + color: #f92672; +} + +.hljs-symbol, +.hljs-attribute { + color: #66d9ef; +} + +.hljs-params, +.hljs-class .hljs-title { + color: #f8f8f2; +} + +.hljs-string, +.hljs-type, +.hljs-built_in, +.hljs-builtin-name, +.hljs-selector-id, +.hljs-selector-attr, +.hljs-selector-pseudo, +.hljs-addition, +.hljs-variable, +.hljs-template-variable { + color: #e6db74; +} + +.hljs-comment, +.hljs-deletion, +.hljs-meta { + color: #75715e; +} diff --git a/frontend/resources/styles/main-default.scss b/frontend/resources/styles/main-default.scss index a438f6464..b8860a4b4 100644 --- a/frontend/resources/styles/main-default.scss +++ b/frontend/resources/styles/main-default.scss @@ -19,6 +19,7 @@ @import 'common/dependencies/reset'; @import 'common/dependencies/animations'; @import 'common/dependencies/z-index'; +@import 'common/dependencies/highlightjs-theme'; //################################################# // Layouts diff --git a/frontend/resources/styles/main/partials/handoff.scss b/frontend/resources/styles/main/partials/handoff.scss index 0141180fc..899dd818b 100644 --- a/frontend/resources/styles/main/partials/handoff.scss +++ b/frontend/resources/styles/main/partials/handoff.scss @@ -15,6 +15,30 @@ justify-content: center; } +.attributes-copy-button { + visibility: hidden; + opacity: 0; + transition: opacity 0.3s; + position: absolute; + right: 0; + top: 0; + background: none; + border: none; + padding: 0; + cursor: pointer; + + svg { + width: 16px; + height: 16px; + fill: $color-gray-20; + transition: fill 0.3s; + + &:hover { + fill: $color-primary; + } + } +} + .attributes-block { user-select: text; @@ -30,30 +54,6 @@ border-bottom: none; } - .attributes-copy-button { - visibility: hidden; - opacity: 0; - transition: opacity 0.3s; - position: absolute; - right: 0; - top: 0; - background: none; - border: none; - padding: 0; - cursor: pointer; - - svg { - width: 16px; - height: 16px; - fill: $color-gray-20; - transition: fill 0.3s; - - &:hover { - fill: $color-primary; - } - } - } - .attributes-label { color: $color-gray-20; } @@ -263,3 +263,61 @@ border-top: none; } } + + +.code-block { + .code-row-lang { + position: relative; + display: flex; + flex-direction: row; + margin: 0.5rem; + + &:hover .attributes-copy-button { + visibility: visible; + opacity: 1; + } + + .code-selection { + height: 100%; + margin: 0; + padding: 0.5rem; + width: 4.5rem; + font-size: $fs12; + background: $color-gray-50; + color: $color-gray-10; + border-radius: 2px; + border: 1px solid $color-gray-30; + background-image: url("/images/icons/arrow-down-white.svg"); + background-repeat: no-repeat; + background-position: 90% 48%; + background-size: 8px; + } + .attributes-copy-button { + margin-top: 8px; + } + } + + .code-row-display { + margin: 0.5rem; + font-size: $fs12; + + .code-display { + border-radius: 4px; + padding: 1rem; + overflow: hidden; + white-space: pre-wrap; + background: $color-gray-60; + + .hljs-attr { + color: #a6e22e; + } + .hljs-comment { + color: $color-gray-30; + } + .hljs-string { + color: #66d9ef; + } + } + } + +} diff --git a/frontend/src/app/main/ui/viewer/handoff/attributes.cljs b/frontend/src/app/main/ui/viewer/handoff/attributes.cljs index 2863ced87..fe7658f8f 100644 --- a/frontend/src/app/main/ui/viewer/handoff/attributes.cljs +++ b/frontend/src/app/main/ui/viewer/handoff/attributes.cljs @@ -20,13 +20,23 @@ [app.main.ui.viewer.handoff.attributes.image :refer [image-panel]] [app.main.ui.viewer.handoff.attributes.text :refer [text-panel]])) -(mf/defc attributes - [{:keys [shapes frame options]}] - (let [locale (mf/deref i18n/locale) - shapes (->> shapes - (map #(gsh/translate-to-frame % frame))) +(def type->options + {:multiple [:fill :stroke :image :text :shadow :blur] + :frame [:layout :fill] + :group [:layout] + :rect [:layout :fill :stroke :shadow :blur] + :circle [:layout :fill :stroke :shadow :blur] + :path [:layout :fill :stroke :shadow :blur] + :curve [:layout :fill :stroke :shadow :blur] + :image [:image :layout :shadow :blur] + :text [:layout :text :shadow :blur]}) - shape (first shapes)] +(mf/defc attributes + [{:keys [shapes frame]}] + (let [locale (mf/deref i18n/locale) + shapes (->> shapes (map #(gsh/translate-to-frame % frame))) + type (if (= (count shapes) 1) (-> shapes first :type) :multiple) + options (type->options type)] [:div.element-options (for [option options] [:> (case option diff --git a/frontend/src/app/main/ui/viewer/handoff/code.cljs b/frontend/src/app/main/ui/viewer/handoff/code.cljs new file mode 100644 index 000000000..22a2d5577 --- /dev/null +++ b/frontend/src/app/main/ui/viewer/handoff/code.cljs @@ -0,0 +1,80 @@ +;; This Source Code Form is subject to the terms of the Mozilla Public +;; License, v. 2.0. If a copy of the MPL was not distributed with this +;; file, You can obtain one at http://mozilla.org/MPL/2.0/. +;; +;; This Source Code Form is "Incompatible With Secondary Licenses", as +;; defined by the Mozilla Public License, v. 2.0. +;; +;; Copyright (c) 2020 UXBOX Labs SL + +(ns app.main.ui.viewer.handoff.code + (:require + ["highlight.js" :as hljs] + [rumext.alpha :as mf] + [app.util.i18n :as i18n] + [app.main.ui.icons :as i] + [app.common.geom.shapes :as gsh])) + +(def css-example + "/* text layer name */ +.shape { + width: 142px; + height: 40px; + border-radius: 20px; + background-color: var(--tiffany-blue); +}") + +(def svg-example + " + + +") + +(mf/defc code-block [{:keys [code type]}] + (let [block-ref (mf/use-ref)] + (mf/use-effect + (mf/deps block-ref) + (fn [] + (hljs/highlightBlock (mf/ref-val block-ref)))) + [:pre.code-display {:class type + :ref block-ref} code])) + +(mf/defc code + [{:keys [shapes frame]}] + (let [locale (mf/deref i18n/locale) + shapes (->> shapes + (map #(gsh/translate-to-frame % frame)))] + [:div.element-options + [:div.code-block + [:div.code-row-lang + [:select.code-selection + [:option "CSS"] + [:option "SASS"] + [:option "Less"] + [:option "Stylus"]] + + [:button.attributes-copy-button + {:on-click #(prn "??")} + i/copy]] + + [:div.code-row-display + [:& code-block {:type "css" + :code css-example}]]] + + [:div.code-block + [:div.code-row-lang + [:select.code-selection + [:option "SVG"] + [:option "HTML"]] + + [:button.attributes-copy-button + {:on-click #(prn "??")} + i/copy]] + + [:div.code-row-display + [:& code-block {:type "svg" + :code svg-example}]]] + + ])) + diff --git a/frontend/src/app/main/ui/viewer/handoff/right_sidebar.cljs b/frontend/src/app/main/ui/viewer/handoff/right_sidebar.cljs index 3a97ff6b2..1fbb6e1cb 100644 --- a/frontend/src/app/main/ui/viewer/handoff/right_sidebar.cljs +++ b/frontend/src/app/main/ui/viewer/handoff/right_sidebar.cljs @@ -15,8 +15,9 @@ [app.main.store :as st] [app.main.ui.icons :as i] [app.main.ui.components.tab-container :refer [tab-container tab-element]] + [app.main.ui.workspace.sidebar.layers :refer [element-icon]] [app.main.ui.viewer.handoff.attributes :refer [attributes]] - [app.main.ui.workspace.sidebar.layers :refer [element-icon]])) + [app.main.ui.viewer.handoff.code :refer [code]])) (defn make-selected-shapes-iref [] @@ -28,28 +29,9 @@ (mapv resolve-shape selected)))] #(l/derived selected->shapes st/state))) -(mf/defc attributes-panel [{:keys [frame shapes]}] - (let [type (if (= (count shapes) 1) - (-> shapes first :type) - :multiple)] - (let [options (case type - :multiple [:fill :stroke :image :text :shadow :blur] - :frame [:layout :fill] - :group [:layout] - :rect [:layout :fill :stroke :shadow :blur] - :circle [:layout :fill :stroke :shadow :blur] - :path [:layout :fill :stroke :shadow :blur] - :curve [:layout :fill :stroke :shadow :blur] - :image [:image :layout :shadow :blur] - :text [:layout :text :shadow :blur])] - [:& attributes {:frame frame - :shapes shapes - :options options}]))) -(mf/defc code-panel [] - [:div.element-options]) - -(mf/defc right-sidebar [{:keys [frame]}] +(mf/defc right-sidebar + [{:keys [frame]}] (let [locale (mf/deref i18n/locale) section (mf/use-state :info #_:code) selected-ref (mf/use-memo (make-selected-shapes-iref)) @@ -72,8 +54,9 @@ [:& tab-container {:on-change-tab #(reset! section %) :selected @section} [:& tab-element {:id :info :title (t locale "handoff.tabs.info")} - [:& attributes-panel {:frame frame - :shapes shapes}]] + [:& attributes {:frame frame + :shapes shapes}]] [:& tab-element {:id :code :title (t locale "handoff.tabs.code")} - [:& code-panel]]]]])]])) + [:& code {:frame frame + :shapes shapes}]]]]])]])) diff --git a/frontend/yarn.lock b/frontend/yarn.lock index cfb999f66..4dabf371a 100644 --- a/frontend/yarn.lock +++ b/frontend/yarn.lock @@ -1931,6 +1931,11 @@ he@1.1.1: resolved "https://registry.yarnpkg.com/he/-/he-1.1.1.tgz#93410fd21b009735151f8868c2f271f3427e23fd" integrity sha1-k0EP0hsAlzUVH4howvJx80J+I/0= +highlight.js@^10.3.1: + version "10.3.1" + resolved "https://registry.yarnpkg.com/highlight.js/-/highlight.js-10.3.1.tgz#3ca6bf007377faae347e8135ff25900aac734b9a" + integrity sha512-jeW8rdPdhshYKObedYg5XGbpVgb1/DT4AHvDFXhkU7UnGSIjy9kkJ7zHG7qplhFHMitTSzh5/iClKQk3Kb2RFQ== + hmac-drbg@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/hmac-drbg/-/hmac-drbg-1.0.1.tgz#d2745701025a6c775a6c545793ed502fc0c649a1"