[#15578] fix code snippet

This commit is contained in:
Ulises Manuel Cárdenas 2023-04-10 12:24:22 -06:00 committed by GitHub
parent a261628b83
commit ccb20d7994
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 200 additions and 151 deletions

View File

@ -0,0 +1,87 @@
(ns quo2.components.code.code.style
(:require [quo2.foundations.colors :as colors]))
;; Example themes:
;; https://github.com/react-syntax-highlighter/react-syntax-highlighter/tree/master/src/styles/hljs
(defn theme
[theme-key]
(case theme-key
:hljs-comment (colors/theme-colors colors/neutral-40 colors/neutral-60)
:hljs-title (colors/custom-color-by-theme :sky 50 60)
:hljs-keyword (colors/custom-color-by-theme :green 50 60)
:hljs-string (colors/custom-color-by-theme :turquoise 50 60)
:hljs-literal (colors/custom-color-by-theme :turquoise 50 60)
:hljs-number (colors/custom-color-by-theme :turquoise 50 60)
:line-number colors/neutral-40
nil))
(defn text-style
[class-names]
(let [text-color (->> class-names
(map keyword)
(some (fn [class-name]
(when-let [text-color (theme class-name)]
text-color))))]
(cond-> {:flex-shrink 1
:line-height 18}
text-color (assoc :color text-color))))
(defn border-color
[]
(colors/theme-colors colors/neutral-20 colors/neutral-80))
(defn container
[]
{:overflow :hidden
:padding 8
:background-color (colors/theme-colors colors/white colors/neutral-80-opa-40)
:border-color (border-color)
:border-width 1
:border-radius 16})
(def gradient-container
{:position :absolute
:bottom 0
:left 0
:right 0
:z-index 1})
(def gradient {:height 48})
(defn line-number-container
[line-number-width]
{:position :absolute
:bottom 0
:top 0
:left 0
:width (+ line-number-width 8 7)
:background-color (colors/theme-colors colors/neutral-5 colors/neutral-80)})
(defn divider
[line-number-width]
{:position :absolute
:bottom 0
:top 0
:left (+ line-number-width 7 7)
:width 1
:z-index 2
:background-color (border-color)})
(def line {:flex-direction :row})
(defn line-number
[width]
{:margin-right 20 ; 8+12 margin
:width width})
(def copy-button
{:position :absolute
:bottom 8
:right 8
:z-index 1})
(defn gradient-color [] (colors/theme-colors colors/white colors/neutral-80))
(defn button-background-color
[]
(colors/theme-colors colors/neutral-80-opa-5 colors/white-opa-5))

View File

@ -1,175 +1,110 @@
(ns quo2.components.code.snippet (ns quo2.components.code.snippet
(:require [cljs-bean.core :as bean] (:require [cljs-bean.core :as bean]
[clojure.string :as string] [clojure.string :as string]
[oops.core :as oops]
[quo2.components.buttons.button :as button] [quo2.components.buttons.button :as button]
[quo2.components.code.code.style :as style]
[quo2.components.markdown.text :as text] [quo2.components.markdown.text :as text]
[quo2.foundations.colors :as colors]
[quo2.theme :as theme]
[react-native.core :as rn] [react-native.core :as rn]
[react-native.linear-gradient :as linear-gradient] [react-native.linear-gradient :as linear-gradient]
[react-native.masked-view :as masked-view]
[react-native.syntax-highlighter :as highlighter] [react-native.syntax-highlighter :as highlighter]
[reagent.core :as reagent])) [reagent.core :as reagent]))
;; Example themes:
;; https://github.com/react-syntax-highlighter/react-syntax-highlighter/tree/master/src/styles/hljs
(def ^:private themes
{:light {:hljs-comment {:color colors/neutral-40}
:hljs-title {:color (colors/custom-color :blue 50)}
:hljs-keyword {:color (colors/custom-color :green 50)}
:hljs-string {:color (colors/custom-color :turquoise 50)}
:hljs-literal {:color (colors/custom-color :turquoise 50)}
:hljs-number {:color (colors/custom-color :turquoise 50)}
:line-number {:color colors/neutral-40}}
:dark {:hljs-comment {:color colors/neutral-60}
:hljs-title {:color (colors/custom-color :blue 60)}
:hljs-keyword {:color (colors/custom-color :green 60)}
:hljs-string {:color (colors/custom-color :turquoise 60)}
:hljs-literal {:color (colors/custom-color :turquoise 60)}
:hljs-number {:color (colors/custom-color :turquoise 60)}
:line-number {:color colors/neutral-40}}})
(defn- text-style
[class-names]
(->> class-names
(map keyword)
(reduce #(merge %1 (get-in themes [(theme/get-theme) %2]))
{:flex-shrink 1
;; Round to a nearest whole number to achieve consistent
;; spacing (also important for calculating `max-text-height`).
;; Line height seems to be inconsistent between text being
;; wrapped and text being rendered on a newline using Flexbox
;; layout.
:line-height 18})))
(defn- render-nodes (defn- render-nodes
[nodes] [nodes]
(map (fn [{:keys [children value] :as node}] (map (fn [{:keys [children value last-line?] :as node}]
;; Node can have :children or a :value.
(if children (if children
(into [text/text (into [text/text
{:weight :code (cond-> {:weight :code
:size :paragraph-2 :size :paragraph-2
:style (text-style (get-in node [:properties :className]))}] :style (style/text-style (get-in node [:properties :className]))}
last-line? (assoc :number-of-lines 1))]
(render-nodes children)) (render-nodes children))
;; Remove newlines as we already render each line separately. ;; Remove newlines as we already render each line separately.
(-> value string/trim-newline))) (string/trim-newline value)))
nodes)) nodes))
(defn- line
[{:keys [line-number line-number-width]} children]
[rn/view {:style style/line}
[rn/view {:style (style/line-number line-number-width)}
[text/text
{:style (style/text-style ["line-number"])
:weight :code
:size :paragraph-2}
line-number]]
children])
(defn- code-block (defn- code-block
[{:keys [rows line-number-width]}] [{:keys [rows line-number-width]}]
[into [:<>] [rn/view
(->> rows (->> rows
(render-nodes) (render-nodes)
;; Line numbers (map-indexed (fn [idx row-content]
(map-indexed (fn [idx row] [line
(conj [rn/view {:style {:flex-direction :row}} {:line-number (inc idx)
[rn/view :line-number-width line-number-width}
{:style {:width line-number-width row-content]))
;; 8+12 margin (into [:<>]))])
:margin-right 20}}
[text/text (defn- mask-view
{:weight :code [{:keys [apply-mask?]} child]
:size :paragraph-2 (if apply-mask?
:style (text-style ["line-number"])} [:<>
(inc idx)]]] [rn/view {:style style/gradient-container}
row))))]) [linear-gradient/linear-gradient
{:style style/gradient
:colors [:transparent (style/gradient-color)]}
[rn/view {:style style/gradient}]]]
child]
child))
(defn- calc-line-number-width
[font-scale rows-to-show]
(let [max-line-digits (-> rows-to-show str count)]
(if (= 1 max-line-digits)
18 ;; ~ 9 is char width, 18 is width used in Figma.
(* 9 max-line-digits font-scale))))
(defn- native-renderer (defn- native-renderer
[] [{:keys [rows max-lines on-copy-press]
(let [text-height (reagent/atom nil)] :or {max-lines ##Inf}}]
(fn [{:keys [rows max-lines on-copy-press]}] (let [font-scale (:font-scale (rn/use-window-dimensions))
(let [background-color (colors/theme-colors total-rows (count rows)
colors/white number-rows-to-show (min (count rows) max-lines)
colors/neutral-80-opa-40) line-number-width (calc-line-number-width font-scale number-rows-to-show)
background-color-left (colors/theme-colors truncated? (< number-rows-to-show total-rows)
colors/neutral-5 rows-to-show-coll (if truncated?
colors/neutral-80) (as-> rows $
border-color (colors/theme-colors (update $ number-rows-to-show assoc :last-line? true)
colors/neutral-20 (take (inc number-rows-to-show) $))
colors/neutral-80) rows)]
rows (bean/->clj rows) [rn/view {:style (style/container)}
font-scale (:font-scale (rn/use-window-dimensions)) [rn/view {:style (style/line-number-container line-number-width)}]
max-rows (or max-lines (count rows)) ;; Cut down on rows to process. [rn/view {:style (style/divider line-number-width)}]
max-line-digits (-> rows count (min max-rows) str count) [mask-view {:apply-mask? truncated?}
;; ~ 9 is char width, 18 is width used in Figma. [code-block
line-number-width (* font-scale (max 18 (* 9 max-line-digits))) {:rows rows-to-show-coll
max-text-height (some-> max-lines :line-number-width line-number-width}]]
(* font-scale 18)) ;; 18 is font's line height. [rn/view {:style style/copy-button}
truncated? (and max-text-height (< max-text-height @text-height)) [button/button
maybe-mask-wrapper (if truncated? {:icon true
[masked-view/masked-view :type :grey
{:mask-element :size 24
(reagent/as-element :on-press on-copy-press
[linear-gradient/linear-gradient :override-background-color (style/button-background-color)}
{:colors ["black" "transparent"] :main-icons/copy]]]))
:locations [0.75 1]
:style {:flex 1}}])}]
[:<>])]
[rn/view
{:style {:overflow :hidden
:padding 8
:background-color background-color
:border-color border-color
:border-width 1
:border-radius 8
;; Hide on intial render to avoid flicker when mask-wrapper is shown.
:opacity (if @text-height 1 0)}}
;; Line number container
[rn/view
{:style {:position :absolute
:bottom 0
:top 0
:left 0
:width (+ line-number-width 8 8)
:background-color background-color-left
:border-right-color border-color
:border-right-width 1}}]
(conj maybe-mask-wrapper
[rn/view {:max-height max-text-height}
[rn/view
{:on-layout (fn [evt]
(let [height (oops/oget evt "nativeEvent.layout.height")]
(reset! text-height height)))}
[code-block
{:rows (take max-rows rows)
:line-number-width line-number-width}]]])
;; Copy button
[rn/view
{:style {:position :absolute
:bottom 8
:right 8}}
[button/button
{:icon true
:type :grey
:size 24
:on-press on-copy-press}
:main-icons/copy]]]))))
(defn- wrap-renderer-fn
[f {:keys [max-lines on-copy-press]}]
(fn [^js props]
(reagent/as-element [:f> f
{:rows (.-rows props)
:max-lines max-lines
:on-copy-press on-copy-press}])))
(defn snippet (defn snippet
[{:keys [language max-lines on-copy-press]} children] [{:keys [language max-lines on-copy-press]} children]
[highlighter/highlighter [highlighter/highlighter
{:language language {:language language
:renderer (wrap-renderer-fn :renderer (fn [^js/Object props]
native-renderer (reagent/as-element
{:max-lines max-lines [:f> native-renderer
:on-copy-press #(when on-copy-press {:rows (-> props .-rows bean/->clj)
(on-copy-press children))}) :on-copy-press #(when on-copy-press (on-copy-press children))
;; Default props to adapt Highlighter for react-native. :max-lines max-lines}]))
;;:CodeTag react-native/View
;;:PreTag react-native/View
:show-line-numbers false :show-line-numbers false
:style #js {} :style {}
:custom-style #js {:backgroundColor nil}} :custom-style {:background-color nil}}
children]) children])

View File

@ -1,5 +1,11 @@
(ns react-native.syntax-highlighter (ns react-native.syntax-highlighter
(:require ["react-syntax-highlighter" :default Highlighter] (:require ["react-native" :as react-native]
[reagent.core :as reagent])) ["react-syntax-highlighter" :default Highlighter]))
(def highlighter (reagent/adapt-react-class Highlighter))
(defn highlighter
[props code-string]
[:> Highlighter
;; Default props to adapt Highlighter for react-native.
(assoc props :Code-tag react-native/View :Pre-tag react-native/View)
code-string])

View File

@ -26,6 +26,23 @@
s.logger.Error(\"failed to set Server.port\", zap.Error(err)) s.logger.Error(\"failed to set Server.port\", zap.Error(err))
return return
} }
if s.afterPortChanged != nil {
s.afterPortChanged(s.port)
}
s.run = true
err = s.server.Serve(listener)
if err != http.ErrServerClosed {
s.logger.Error(\"server failed unexpectedly, restarting\", zap.Error(err))
err = s.Start()
if err != nil {
s.logger.Error(\"server start failed, giving up\", zap.Error(err))
}
return
}
s.run = false
}") }")
(def clojure-example (def clojure-example
@ -59,9 +76,13 @@
:value :clojure} :value :clojure}
{:key :go {:key :go
:value :go}]} :value :go}]}
{:label "Max lines:" {:label "Max lines:"
:key :max-lines :key :max-lines
:type :text} :type :select
:options (map (fn [n]
{:key n
:value (str n " lines")})
(range 0 41 5))}
{:label "Syntax highlight:" {:label "Syntax highlight:"
:key :syntax :key :syntax
:type :boolean}]) :type :boolean}])
@ -69,7 +90,7 @@
(defn cool-preview (defn cool-preview
[] []
(let [state (reagent/atom {:language :clojure (let [state (reagent/atom {:language :clojure
:max-lines "" :max-lines 40
:syntax true})] :syntax true})]
(fn [] (fn []
(let [language (if (:syntax @state) (:language @state) :text) (let [language (if (:syntax @state) (:language @state) :text)