mirror of
https://github.com/penpot/penpot.git
synced 2025-06-06 09:31:38 +02:00
🐛 Fix many issues after PR review
This commit is contained in:
parent
2f6018c35c
commit
903a9356a9
18 changed files with 243 additions and 99 deletions
|
@ -103,6 +103,10 @@ http {
|
|||
add_header x-internal-redirect "$upstream_http_x_accel_redirect";
|
||||
}
|
||||
|
||||
location /api/export {
|
||||
proxy_pass http://127.0.0.1:6061;
|
||||
}
|
||||
|
||||
location /api {
|
||||
proxy_pass http://127.0.0.1:6060/api;
|
||||
}
|
||||
|
@ -115,10 +119,6 @@ http {
|
|||
proxy_pass http://127.0.0.1:6060/dbg;
|
||||
}
|
||||
|
||||
location /export {
|
||||
proxy_pass http://127.0.0.1:6061;
|
||||
}
|
||||
|
||||
location /telemetry {
|
||||
proxy_pass http://127.0.0.1:6070/inbox;
|
||||
}
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
"inflation": "^2.0.0",
|
||||
"ioredis": "^4.28.5",
|
||||
"luxon": "^2.3.1",
|
||||
"playwright": "^1.19.2",
|
||||
"playwright": "^1.20.0",
|
||||
"raw-body": "^2.5.1",
|
||||
"xml-js": "^1.6.11",
|
||||
"xregexp": "^5.0.2"
|
||||
|
|
|
@ -69,13 +69,9 @@
|
|||
|
||||
(defn pdf
|
||||
([page] (pdf page {}))
|
||||
([page {:keys [width height scale save-path]
|
||||
:or {width default-viewport-width
|
||||
height default-viewport-height
|
||||
scale 1}}]
|
||||
([page {:keys [scale save-path]
|
||||
:or {scale 1}}]
|
||||
(.pdf ^js page #js {:path save-path
|
||||
:width width
|
||||
:height height
|
||||
:scale scale
|
||||
:printBackground true
|
||||
:preferCSSPageSize true})))
|
||||
|
|
|
@ -28,9 +28,10 @@
|
|||
[type]
|
||||
(case (d/name type)
|
||||
"zip" "application/zip"
|
||||
"pdf" "application/pdf"
|
||||
"svg" "image/svg+xml"
|
||||
"jpeg" "image/jpeg"
|
||||
"png" "image/png"
|
||||
"pdf" "application/pdf"))
|
||||
"png" "image/png"))
|
||||
|
||||
(defn create
|
||||
"Generates ephimeral resource object."
|
||||
|
|
|
@ -65,7 +65,7 @@
|
|||
|
||||
(defn- wrap-body-params
|
||||
[handler]
|
||||
(let [opts #js {:limit "2mb" :encoding "utf8"}]
|
||||
(let [opts #js {:limit "60mb" :encoding "utf8"}]
|
||||
(fn [{:keys [:request/method :request/headers request] :as exchange}]
|
||||
(let [ctype (get headers "content-type")]
|
||||
(if (= method "post")
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
[app.common.logging :as l]
|
||||
[app.common.pages :as cp]
|
||||
[app.common.spec :as us]
|
||||
[app.common.uri :as u]
|
||||
[app.config :as cf]
|
||||
[cljs.spec.alpha :as s]
|
||||
[cuerdas.core :as str]
|
||||
|
@ -20,10 +21,14 @@
|
|||
|
||||
(defn screenshot-object
|
||||
[{:keys [file-id page-id object-id token scale type uri]}]
|
||||
(p/let [path (str "/render-object/" file-id "/" page-id "/" object-id)
|
||||
(p/let [params {:file-id file-id
|
||||
:page-id page-id
|
||||
:object-id object-id
|
||||
:route "render-object"}
|
||||
|
||||
uri (-> (or uri (cf/get :public-uri))
|
||||
(assoc :path "/")
|
||||
(assoc :fragment path))]
|
||||
(assoc :path "/render.html")
|
||||
(assoc :query (u/map->query-string params)))]
|
||||
(bw/exec!
|
||||
#js {:screen #js {:width bw/default-viewport-width
|
||||
:height bw/default-viewport-height}
|
||||
|
|
|
@ -11,16 +11,21 @@
|
|||
[app.common.exceptions :as ex :include-macros true]
|
||||
[app.common.logging :as l]
|
||||
[app.common.spec :as us]
|
||||
[app.common.uri :as u]
|
||||
[app.config :as cf]
|
||||
[cljs.spec.alpha :as s]
|
||||
[promesa.core :as p]))
|
||||
|
||||
(defn pdf-from-object
|
||||
[{:keys [file-id page-id object-id token scale type save-path uri] :as params}]
|
||||
(p/let [path (str "/render-object/" file-id "/" page-id "/" object-id)
|
||||
(p/let [params {:file-id file-id
|
||||
:page-id page-id
|
||||
:object-id object-id
|
||||
:route "render-object"}
|
||||
uri (-> (or uri (cf/get :public-uri))
|
||||
(assoc :path "/")
|
||||
(assoc :fragment path))]
|
||||
(assoc :path "/render.html")
|
||||
(assoc :query (u/map->query-string params)))]
|
||||
|
||||
(bw/exec!
|
||||
#js {:screen #js {:width bw/default-viewport-width
|
||||
:height bw/default-viewport-height}
|
||||
|
@ -37,6 +42,7 @@
|
|||
(p/let [dom (bw/select page "#screenshot")]
|
||||
(bw/wait-for dom)
|
||||
(bw/screenshot dom {:full-page? true})
|
||||
(bw/sleep page 2000) ; the good old fix with sleep
|
||||
(if save-path
|
||||
(bw/pdf page {:save-path save-path})
|
||||
(bw/pdf page))))))))
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
[app.common.logging :as l]
|
||||
[app.common.pages :as cp]
|
||||
[app.common.spec :as us]
|
||||
[app.common.uri :as u]
|
||||
[app.config :as cf]
|
||||
[app.util.shell :as sh]
|
||||
[cljs.spec.alpha :as s]
|
||||
|
@ -322,10 +323,15 @@
|
|||
result))
|
||||
]
|
||||
|
||||
(p/let [path (str "/render-object/" file-id "/" page-id "/" object-id "?render-texts=true")
|
||||
(p/let [params {:file-id file-id
|
||||
:page-id page-id
|
||||
:object-id object-id
|
||||
:render-texts true
|
||||
:route "render-object"}
|
||||
|
||||
uri (-> (or uri (cf/get :public-uri))
|
||||
(assoc :path "/")
|
||||
(assoc :fragment path))]
|
||||
(assoc :path "/render.html")
|
||||
(assoc :query (u/map->query-string params)))]
|
||||
|
||||
(bw/exec!
|
||||
#js {:screen #js {:width bw/default-viewport-width
|
||||
|
@ -341,7 +347,6 @@
|
|||
(p/do!
|
||||
(bw/nav! page uri)
|
||||
(p/let [dom (bw/select page "#screenshot")]
|
||||
(js/console.log "FFFF" dom)
|
||||
(bw/wait-for dom)
|
||||
(bw/sleep page 2000))
|
||||
|
||||
|
|
|
@ -239,6 +239,11 @@ cluster-key-slot@^1.1.0:
|
|||
resolved "https://registry.yarnpkg.com/cluster-key-slot/-/cluster-key-slot-1.1.0.tgz#30474b2a981fb12172695833052bc0d01336d10d"
|
||||
integrity sha512-2Nii8p3RwAPiFwsnZvukotvow2rIHM+yQ6ZcBXGHdniadkYGZYiGmkHJIbZPIV9nfv7m/U1IPMVVcAhoWFeklw==
|
||||
|
||||
colors@1.4.0:
|
||||
version "1.4.0"
|
||||
resolved "https://registry.yarnpkg.com/colors/-/colors-1.4.0.tgz#c50491479d4c1bdaed2c9ced32cf7c7dc2360f78"
|
||||
integrity sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA==
|
||||
|
||||
commander@8.3.0:
|
||||
version "8.3.0"
|
||||
resolved "https://registry.yarnpkg.com/commander/-/commander-8.3.0.tgz#4837ea1b2da67b9c616a67afbb0fafee567bca66"
|
||||
|
@ -827,17 +832,26 @@ pend@~1.2.0:
|
|||
resolved "https://registry.yarnpkg.com/pend/-/pend-1.2.0.tgz#7a57eb550a6783f9115331fcf4663d5c8e007a50"
|
||||
integrity sha1-elfrVQpng/kRUzH89GY9XI4AelA=
|
||||
|
||||
playwright-core@1.19.2:
|
||||
version "1.19.2"
|
||||
resolved "https://registry.yarnpkg.com/playwright-core/-/playwright-core-1.19.2.tgz#90b9209554f174c649abf495952fcb4335437218"
|
||||
integrity sha512-OsL3sJZIo1UxKNWSP7zW7sk3FyUGG06YRHxHeBw51eIOxTCQRx5t+hXd0cvXashN2CHnd3hIZTs2aKa/im4hZQ==
|
||||
pixelmatch@5.2.1:
|
||||
version "5.2.1"
|
||||
resolved "https://registry.yarnpkg.com/pixelmatch/-/pixelmatch-5.2.1.tgz#9e4e4f4aa59648208a31310306a5bed5522b0d65"
|
||||
integrity sha512-WjcAdYSnKrrdDdqTcVEY7aB7UhhwjYQKYhHiBXdJef0MOaQeYpUdQ+iVyBLa5YBKS8MPVPPMX7rpOByISLpeEQ==
|
||||
dependencies:
|
||||
pngjs "^4.0.1"
|
||||
|
||||
playwright-core@1.20.0:
|
||||
version "1.20.0"
|
||||
resolved "https://registry.yarnpkg.com/playwright-core/-/playwright-core-1.20.0.tgz#57e84d7663cada92fe0d5574e9cd42e5fa2e74e1"
|
||||
integrity sha512-d25IRcdooS278Cijlp8J8A5fLQZ+/aY3dKRJvgX5yjXA69N0huIUdnh3xXSgn+LsQ9DCNmB7Ngof3eY630jgdA==
|
||||
dependencies:
|
||||
colors "1.4.0"
|
||||
commander "8.3.0"
|
||||
debug "4.3.3"
|
||||
extract-zip "2.0.1"
|
||||
https-proxy-agent "5.0.0"
|
||||
jpeg-js "0.4.3"
|
||||
mime "3.0.0"
|
||||
pixelmatch "5.2.1"
|
||||
pngjs "6.0.0"
|
||||
progress "2.0.3"
|
||||
proper-lockfile "4.1.2"
|
||||
|
@ -849,18 +863,23 @@ playwright-core@1.19.2:
|
|||
yauzl "2.10.0"
|
||||
yazl "2.5.1"
|
||||
|
||||
playwright@^1.19.2:
|
||||
version "1.19.2"
|
||||
resolved "https://registry.yarnpkg.com/playwright/-/playwright-1.19.2.tgz#d9927ae8512482642356e50a286c5767dfb7a621"
|
||||
integrity sha512-2JmGWr/Iw/Uu27bZULeHgjn8doNrRVxIYdhspMuMlfKNpzwAe/sfm7wH8uey6jiZxnPL4bC5V4ACQcF4dAGWnw==
|
||||
playwright@^1.20.0:
|
||||
version "1.20.0"
|
||||
resolved "https://registry.yarnpkg.com/playwright/-/playwright-1.20.0.tgz#f80b131c0146afc4645fcd5cfcc2ca11895ba58a"
|
||||
integrity sha512-YcFXhXttk9yvpc8PMbfvts6KEopXjxdBh47BdOiA7xhjF/gkXeSM0Hs9CSdbL9mp2xtlB5xqE7+D+F2soQOjbA==
|
||||
dependencies:
|
||||
playwright-core "1.19.2"
|
||||
playwright-core "1.20.0"
|
||||
|
||||
pngjs@6.0.0:
|
||||
version "6.0.0"
|
||||
resolved "https://registry.yarnpkg.com/pngjs/-/pngjs-6.0.0.tgz#ca9e5d2aa48db0228a52c419c3308e87720da821"
|
||||
integrity sha512-TRzzuFRRmEoSW/p1KVAmiOgPco2Irlah+bGFCeNfJXxxYGwSw7YwAOAcd7X28K/m5bjBWKsC29KyoMfHbypayg==
|
||||
|
||||
pngjs@^4.0.1:
|
||||
version "4.0.1"
|
||||
resolved "https://registry.yarnpkg.com/pngjs/-/pngjs-4.0.1.tgz#f803869bb2fc1bfe1bf99aa4ec21c108117cfdbe"
|
||||
integrity sha512-rf5+2/ioHeQxR6IxuYNYGFytUyG3lma/WW1nsmjeHlWwtb2aByla6dkVc8pmJ9nplzkTA0q2xx7mMWrOTqT4Gg==
|
||||
|
||||
printj@~1.3.1:
|
||||
version "1.3.1"
|
||||
resolved "https://registry.yarnpkg.com/printj/-/printj-1.3.1.tgz#9af6b1d55647a1587ac44f4c1654a4b95b8e12cb"
|
||||
|
|
|
@ -136,6 +136,7 @@ function templatePipeline(options) {
|
|||
return function() {
|
||||
const input = options.input;
|
||||
const output = options.output;
|
||||
const name = options.name;
|
||||
|
||||
const ts = Math.floor(new Date());
|
||||
const th = process.env.APP_THEME || "default";
|
||||
|
@ -154,7 +155,7 @@ function templatePipeline(options) {
|
|||
|
||||
return gulp.src(input)
|
||||
.pipe(tmpl)
|
||||
.pipe(gulpRename("index.html"))
|
||||
.pipe(gulpRename(name))
|
||||
.pipe(gulp.dest(output))
|
||||
.pipe(touch());
|
||||
};
|
||||
|
@ -191,11 +192,18 @@ gulp.task("svg:sprite:cursors", function() {
|
|||
});
|
||||
|
||||
gulp.task("template:main", templatePipeline({
|
||||
name: "index.html",
|
||||
input: paths.resources + "templates/index.mustache",
|
||||
output: paths.output
|
||||
}));
|
||||
|
||||
gulp.task("templates", gulp.series("svg:sprite:icons", "svg:sprite:cursors", "template:main"));
|
||||
gulp.task("template:render", templatePipeline({
|
||||
name: "render.html",
|
||||
input: paths.resources + "templates/render.mustache",
|
||||
output: paths.output
|
||||
}));
|
||||
|
||||
gulp.task("templates", gulp.series("svg:sprite:icons", "svg:sprite:cursors", "template:main", "template:render"));
|
||||
|
||||
gulp.task("polyfills", function() {
|
||||
return gulp.src(paths.resources + "polyfills/*.js")
|
||||
|
|
26
frontend/resources/templates/render.mustache
Normal file
26
frontend/resources/templates/render.mustache
Normal file
|
@ -0,0 +1,26 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta http-equiv="x-ua-compatible" content="ie=edge" />
|
||||
<title>Penpot - Render</title>
|
||||
<link rel="icon" href="images/favicon.png" />
|
||||
|
||||
<script>
|
||||
window.penpotThemes = {{& themes}};
|
||||
window.penpotVersion = "%version%";
|
||||
</script>
|
||||
|
||||
{{# manifest}}
|
||||
<script src="{{& config}}"></script>
|
||||
<script src="{{& polyfills}}"></script>
|
||||
{{/manifest}}
|
||||
</head>
|
||||
<body>
|
||||
<section id="app" tabindex="1"></section>
|
||||
{{# manifest}}
|
||||
<script src="{{& shared}}"></script>
|
||||
<script src="{{& render}}"></script>
|
||||
{{/manifest}}
|
||||
</body>
|
||||
</html>
|
|
@ -15,9 +15,15 @@
|
|||
|
||||
:modules
|
||||
{:shared {:entries []}
|
||||
|
||||
:main {:entries [app.main]
|
||||
:depends-on #{:shared}
|
||||
:init-fn app.main/init}
|
||||
|
||||
:render {:entries [app.render]
|
||||
:depends-on #{:shared}
|
||||
:init-fn app.render/init}
|
||||
|
||||
:worker {:entries [app.worker]
|
||||
:web-worker true
|
||||
:depends-on #{:shared}}}
|
||||
|
|
|
@ -21,11 +21,9 @@
|
|||
[app.main.ui.routes :as rt]
|
||||
[app.main.worker :as worker]
|
||||
[app.util.dom :as dom]
|
||||
[app.util.globals :as glob]
|
||||
[app.util.i18n :as i18n]
|
||||
[app.util.theme :as theme]
|
||||
[beicon.core :as rx]
|
||||
[cuerdas.core :as str]
|
||||
[debug]
|
||||
[potok.core :as ptk]
|
||||
[rumext.alpha :as mf]))
|
||||
|
@ -68,19 +66,12 @@
|
|||
(rx/take 1)
|
||||
(rx/map #(ws/initialize)))))))
|
||||
|
||||
|
||||
(def essential-only?
|
||||
(let [href (.-href ^js glob/location)]
|
||||
(str/includes? href "essential=t")))
|
||||
|
||||
(defn ^:export init
|
||||
[]
|
||||
(when-not essential-only?
|
||||
(worker/init!)
|
||||
(sentry/init!)
|
||||
(i18n/init! cf/translations)
|
||||
(theme/init! cf/themes))
|
||||
|
||||
(theme/init! cf/themes)
|
||||
(init-ui)
|
||||
(st/emit! (initialize)))
|
||||
|
||||
|
|
|
@ -108,7 +108,7 @@
|
|||
(defn- send-export-command
|
||||
[& {:keys [cmd params blob?]}]
|
||||
(->> (http/send! {:method :post
|
||||
:uri (u/join base-uri "export")
|
||||
:uri (u/join base-uri "api/export")
|
||||
:body (http/transit-data (assoc params :cmd cmd))
|
||||
:credentials "include"
|
||||
:response-type (if blob? :blob :text)})
|
||||
|
@ -137,7 +137,7 @@
|
|||
:wait false
|
||||
:exports exports}]
|
||||
(->> (http/send! {:method :post
|
||||
:uri (u/join base-uri "export")
|
||||
:uri (u/join base-uri "api/export")
|
||||
:body (http/transit-data params)
|
||||
:credentials "include"
|
||||
:response-type :blob})
|
||||
|
|
|
@ -52,7 +52,9 @@
|
|||
|
||||
(mf/defc object-svg
|
||||
{::mf/wrap [mf/memo]}
|
||||
[{:keys [objects object-id zoom render-texts?] :or {zoom 1} :as props}]
|
||||
[{:keys [objects object-id zoom render-texts?]
|
||||
:or {zoom 1}
|
||||
:as props}]
|
||||
(let [object (get objects object-id)
|
||||
frame-id (if (= :frame (:type object))
|
||||
(:id object)
|
||||
|
@ -100,7 +102,8 @@
|
|||
render-texts? (and render-texts? (d/seek (comp nil? :position-data) text-shapes))]
|
||||
|
||||
(mf/with-effect [width height]
|
||||
(dom/set-page-style {:size (str (mth/ceil width) "px "
|
||||
(dom/set-page-style!
|
||||
{:size (str (mth/ceil width) "px "
|
||||
(mth/ceil height) "px")}))
|
||||
|
||||
[:& (mf/provider embed/context) {:value false}
|
||||
|
|
|
@ -60,7 +60,8 @@
|
|||
:object-id (first ids)}
|
||||
exports (mapv #(merge % defaults) exports)]
|
||||
(if (= 1 (count exports))
|
||||
(st/emit! (de/request-simple-export {:export (first exports)}))
|
||||
(let [export (first exports)]
|
||||
(st/emit! (de/request-simple-export {:export export :filename (:name export)})))
|
||||
(st/emit! (de/request-multiple-export {:exports exports :filename filename})))))))
|
||||
|
||||
;; TODO: maybe move to specific events for avoid to have this logic here?
|
||||
|
|
76
frontend/src/app/render.cljs
Normal file
76
frontend/src/app/render.cljs
Normal file
|
@ -0,0 +1,76 @@
|
|||
;; 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/.
|
||||
;;
|
||||
;; Copyright (c) UXBOX Labs SL
|
||||
|
||||
(ns app.render
|
||||
"The main entry point for UI part needed by the exporter."
|
||||
(:require
|
||||
[app.common.logging :as log]
|
||||
[app.common.spec :as us]
|
||||
[app.common.uri :as u]
|
||||
[app.config :as cf]
|
||||
[app.main.ui.render :as render]
|
||||
[app.util.dom :as dom]
|
||||
[app.util.globals :as glob]
|
||||
[clojure.spec.alpha :as s]
|
||||
[rumext.alpha :as mf]))
|
||||
|
||||
(log/initialize!)
|
||||
(log/set-level! :root :warn)
|
||||
(log/set-level! :app :info)
|
||||
|
||||
(declare reinit)
|
||||
|
||||
(declare ^:private render-object)
|
||||
|
||||
(log/info :hint "Welcome to penpot (Export)"
|
||||
:version (:full @cf/version)
|
||||
:public-uri (str cf/public-uri))
|
||||
|
||||
|
||||
(defn- parse-params
|
||||
[loc]
|
||||
(let [href (unchecked-get loc "href")]
|
||||
(some-> href u/uri :query u/query-string->map)))
|
||||
|
||||
(defn init-ui
|
||||
[]
|
||||
(when-let [params (parse-params glob/location)]
|
||||
(when-let [component (case (:route params)
|
||||
"render-object" (render-object params)
|
||||
nil)]
|
||||
(mf/mount component (dom/get-element "app")))))
|
||||
|
||||
(defn ^:export init
|
||||
[]
|
||||
(init-ui))
|
||||
|
||||
(defn reinit
|
||||
[]
|
||||
(mf/unmount (dom/get-element "app"))
|
||||
(init-ui))
|
||||
|
||||
(defn ^:dev/after-load after-load
|
||||
[]
|
||||
(reinit))
|
||||
|
||||
(s/def ::page-id ::us/uuid)
|
||||
(s/def ::file-id ::us/uuid)
|
||||
(s/def ::object-id ::us/uuid)
|
||||
(s/def ::render-text ::us/boolean)
|
||||
|
||||
(s/def ::render-object-params
|
||||
(s/keys :req-un [::file-id ::page-id ::object-id]
|
||||
:opt-un [::render-text]))
|
||||
|
||||
(defn- render-object
|
||||
[params]
|
||||
(let [{:keys [page-id file-id object-id render-texts]} (us/conform ::render-object-params params)]
|
||||
(mf/html
|
||||
[:& render/render-object
|
||||
{:file-id file-id
|
||||
:page-id page-id
|
||||
:object-id object-id
|
||||
:render-texts? (and (some? render-texts) (= render-texts "true"))}])))
|
|
@ -6,6 +6,7 @@
|
|||
|
||||
(ns app.util.dom
|
||||
(:require
|
||||
[app.common.data.macros :as dm]
|
||||
[app.common.exceptions :as ex]
|
||||
[app.common.geom.point :as gpt]
|
||||
[app.util.globals :as globals]
|
||||
|
@ -33,25 +34,25 @@
|
|||
|
||||
;; --- New methods
|
||||
|
||||
(declare get-elements-by-tag)
|
||||
|
||||
(defn set-html-title
|
||||
[^string title]
|
||||
(set! (.-title globals/document) title))
|
||||
|
||||
(defn set-page-style
|
||||
[style]
|
||||
(let [head (first (.getElementsByTagName ^js globals/document "head"))
|
||||
style-str (str/join "\n"
|
||||
(map (fn [[k v]]
|
||||
(str (name k) ": " v ";"))
|
||||
style))]
|
||||
(.insertAdjacentHTML head "beforeend"
|
||||
(str "<style>"
|
||||
" @page {" style-str "}"
|
||||
" html, body {" ; Fix issue having Chromium to add random 1px margin at the bottom
|
||||
" overflow: hidden;" ; https://github.com/puppeteer/puppeteer/issues/2278#issuecomment-410381934
|
||||
" font-size: 0;"
|
||||
" }"
|
||||
"</style>"))))
|
||||
(defn set-page-style!
|
||||
[styles]
|
||||
(let [node (first (get-elements-by-tag globals/document "head"))
|
||||
style (reduce-kv (fn [res k v]
|
||||
(conj res (dm/str (str/css-selector k) ":" v ";")))
|
||||
[]
|
||||
styles)
|
||||
style (dm/str "<style>\n"
|
||||
" @page {" (str/join " " style) "}\n "
|
||||
" html, body {font-size:0; margin:0; padding:0}\n "
|
||||
"</style>")]
|
||||
(.insertAdjacentHTML ^js node "beforeend" style)))
|
||||
|
||||
|
||||
(defn get-element-by-class
|
||||
([classname]
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue