mirror of
https://github.com/penpot/penpot.git
synced 2025-06-16 10:41:37 +02:00
Merge remote-tracking branch 'penpot/develop' into token-studio-develop
This commit is contained in:
commit
cbfcc50563
27 changed files with 3021 additions and 2806 deletions
|
@ -1,5 +1,11 @@
|
||||||
# CHANGELOG
|
# CHANGELOG
|
||||||
|
|
||||||
|
## 2.0.3
|
||||||
|
|
||||||
|
### :bug: Bugs fixed
|
||||||
|
|
||||||
|
- Fix chrome scrollbar styling [Taiga Issue #7852](https://tree.taiga.io/project/penpot/issue/7852)
|
||||||
|
|
||||||
## 2.0.2
|
## 2.0.2
|
||||||
|
|
||||||
### :sparkles: Enhancements
|
### :sparkles: Enhancements
|
||||||
|
@ -10,6 +16,7 @@
|
||||||
### :bug: Bugs fixed
|
### :bug: Bugs fixed
|
||||||
|
|
||||||
- Fix color palette sorting [Taiga Issue #7458](https://tree.taiga.io/project/penpot/issue/7458)
|
- Fix color palette sorting [Taiga Issue #7458](https://tree.taiga.io/project/penpot/issue/7458)
|
||||||
|
- Fix style scoping problem with imported SVG [Taiga #7671](https://tree.taiga.io/project/penpot/issue/7671)
|
||||||
|
|
||||||
## 2.0.1
|
## 2.0.1
|
||||||
|
|
||||||
|
|
|
@ -274,6 +274,13 @@
|
||||||
(catch #?(:clj Throwable :cljs :default) _cause
|
(catch #?(:clj Throwable :cljs :default) _cause
|
||||||
[0 0 0])))
|
[0 0 0])))
|
||||||
|
|
||||||
|
(defn hex->lum
|
||||||
|
[color]
|
||||||
|
(let [[r g b] (hex->rgb color)]
|
||||||
|
(mth/sqrt (+ (* 0.241 r)
|
||||||
|
(* 0.691 g)
|
||||||
|
(* 0.068 b)))))
|
||||||
|
|
||||||
(defn- int->hex
|
(defn- int->hex
|
||||||
"Convert integer to hex string"
|
"Convert integer to hex string"
|
||||||
[v]
|
[v]
|
||||||
|
@ -455,3 +462,19 @@
|
||||||
|
|
||||||
:else
|
:else
|
||||||
[r g (inc b)]))
|
[r g (inc b)]))
|
||||||
|
|
||||||
|
(defn reduce-range
|
||||||
|
[value range]
|
||||||
|
(/ (mth/floor (* value range)) range))
|
||||||
|
|
||||||
|
(defn sort-colors
|
||||||
|
[a b]
|
||||||
|
(let [[ah _ av] (hex->hsv (:color a))
|
||||||
|
[bh _ bv] (hex->hsv (:color b))
|
||||||
|
ah (reduce-range (/ ah 60) 8)
|
||||||
|
bh (reduce-range (/ bh 60) 8)
|
||||||
|
av (/ av 255)
|
||||||
|
bv (/ bv 255)
|
||||||
|
a (+ (* ah 100) (* av 10))
|
||||||
|
b (+ (* bh 100) (* bv 10))]
|
||||||
|
(compare a b)))
|
||||||
|
|
|
@ -3,8 +3,8 @@ LABEL maintainer="Andrey Antukh <niwi@niwi.nz>"
|
||||||
|
|
||||||
ARG DEBIAN_FRONTEND=noninteractive
|
ARG DEBIAN_FRONTEND=noninteractive
|
||||||
|
|
||||||
ENV NODE_VERSION=v20.11.1 \
|
ENV NODE_VERSION=v20.13.1 \
|
||||||
CLOJURE_VERSION=1.11.1.1435 \
|
CLOJURE_VERSION=1.11.3.1463 \
|
||||||
CLJKONDO_VERSION=2024.03.13 \
|
CLJKONDO_VERSION=2024.03.13 \
|
||||||
BABASHKA_VERSION=1.3.189 \
|
BABASHKA_VERSION=1.3.189 \
|
||||||
CLJFMT_VERSION=0.12.0 \
|
CLJFMT_VERSION=0.12.0 \
|
||||||
|
@ -105,12 +105,12 @@ RUN set -eux; \
|
||||||
ARCH="$(dpkg --print-architecture)"; \
|
ARCH="$(dpkg --print-architecture)"; \
|
||||||
case "${ARCH}" in \
|
case "${ARCH}" in \
|
||||||
aarch64|arm64) \
|
aarch64|arm64) \
|
||||||
ESUM='3ce6a2b357e2ef45fd6b53d6587aa05bfec7771e7fb982f2c964f6b771b7526a'; \
|
ESUM='7d3ab0e8eba95bd682cfda8041c6cb6fa21e09d0d9131316fd7c96c78969de31'; \
|
||||||
BINARY_URL='https://github.com/adoptium/temurin21-binaries/releases/download/jdk-21.0.2%2B13/OpenJDK21U-jdk_aarch64_linux_hotspot_21.0.2_13.tar.gz'; \
|
BINARY_URL='https://github.com/adoptium/temurin21-binaries/releases/download/jdk-21.0.3%2B9/OpenJDK21U-jdk_aarch64_linux_hotspot_21.0.3_9.tar.gz'; \
|
||||||
;; \
|
;; \
|
||||||
amd64|x86_64) \
|
amd64|x86_64) \
|
||||||
ESUM='454bebb2c9fe48d981341461ffb6bf1017c7b7c6e15c6b0c29b959194ba3aaa5'; \
|
ESUM='fffa52c22d797b715a962e6c8d11ec7d79b90dd819b5bc51d62137ea4b22a340'; \
|
||||||
BINARY_URL='https://github.com/adoptium/temurin21-binaries/releases/download/jdk-21.0.2%2B13/OpenJDK21U-jdk_x64_linux_hotspot_21.0.2_13.tar.gz'; \
|
BINARY_URL='https://github.com/adoptium/temurin21-binaries/releases/download/jdk-21.0.3%2B9/OpenJDK21U-jdk_x64_linux_hotspot_21.0.3_9.tar.gz'; \
|
||||||
;; \
|
;; \
|
||||||
*) \
|
*) \
|
||||||
echo "Unsupported arch: ${ARCH}"; \
|
echo "Unsupported arch: ${ARCH}"; \
|
||||||
|
|
|
@ -17,8 +17,8 @@ export default defineConfig({
|
||||||
forbidOnly: !!process.env.CI,
|
forbidOnly: !!process.env.CI,
|
||||||
/* Retry on CI only */
|
/* Retry on CI only */
|
||||||
retries: process.env.CI ? 2 : 0,
|
retries: process.env.CI ? 2 : 0,
|
||||||
/* Opt out of parallel tests on CI. */
|
/* Opt out of parallel tests by default; can be overriden with --workers */
|
||||||
workers: process.env.CI ? 1 : undefined,
|
workers: 1,
|
||||||
/* Reporter to use. See https://playwright.dev/docs/test-reporters */
|
/* Reporter to use. See https://playwright.dev/docs/test-reporters */
|
||||||
reporter: "html",
|
reporter: "html",
|
||||||
/* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */
|
/* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -28,9 +28,16 @@ body {
|
||||||
|
|
||||||
* {
|
* {
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
|
scrollbar-width: thin;
|
||||||
// transition: all .4s ease;
|
// transition: all .4s ease;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@-moz-document url-prefix() {
|
||||||
|
* {
|
||||||
|
scrollbar-width: auto;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.global-zeroclipboard-container {
|
.global-zeroclipboard-container {
|
||||||
transition: none;
|
transition: none;
|
||||||
|
|
||||||
|
|
|
@ -6,10 +6,14 @@
|
||||||
|
|
||||||
// SCROLLBAR
|
// SCROLLBAR
|
||||||
.new-scrollbar {
|
.new-scrollbar {
|
||||||
|
scrollbar-width: thin;
|
||||||
scrollbar-color: rgba(170, 181, 186, 0.3) transparent;
|
scrollbar-color: rgba(170, 181, 186, 0.3) transparent;
|
||||||
&:hover {
|
&:hover {
|
||||||
scrollbar-color: rgba(170, 181, 186, 0.7) transparent;
|
scrollbar-color: rgba(170, 181, 186, 0.7) transparent;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// These rules do not apply in chrome - 121 or higher
|
||||||
|
// We keep them to preserve backward compatibility.
|
||||||
::-webkit-scrollbar {
|
::-webkit-scrollbar {
|
||||||
background-color: transparent;
|
background-color: transparent;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
|
|
|
@ -19,19 +19,22 @@ function getCoreCount() {
|
||||||
return os.cpus().length;
|
return os.cpus().length;
|
||||||
}
|
}
|
||||||
|
|
||||||
// const __filename = url.fileURLToPath(import.meta.url);
|
|
||||||
export const dirname = url.fileURLToPath(new URL(".", import.meta.url));
|
export const dirname = url.fileURLToPath(new URL(".", import.meta.url));
|
||||||
|
|
||||||
export function startWorker() {
|
export function startWorker() {
|
||||||
return wpool.pool(dirname + "/_worker.js", {
|
return wpool.pool(dirname + "/_worker.js", {
|
||||||
maxWorkers: getCoreCount()
|
maxWorkers: getCoreCount(),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
async function findFiles(basePath, predicate, options={}) {
|
async function findFiles(basePath, predicate, options = {}) {
|
||||||
predicate = predicate ?? function() { return true; }
|
predicate =
|
||||||
|
predicate ??
|
||||||
|
function () {
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
|
||||||
let files = await fs.readdir(basePath, {recursive: options.recursive ?? false})
|
let files = await fs.readdir(basePath, { recursive: options.recursive ?? false });
|
||||||
files = files.map((path) => ph.join(basePath, path));
|
files = files.map((path) => ph.join(basePath, path));
|
||||||
|
|
||||||
return files;
|
return files;
|
||||||
|
@ -42,8 +45,11 @@ function syncDirs(originPath, destPath) {
|
||||||
|
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
proc.exec(command, (cause, stdout) => {
|
proc.exec(command, (cause, stdout) => {
|
||||||
if (cause) { reject(cause); }
|
if (cause) {
|
||||||
else { resolve(); }
|
reject(cause);
|
||||||
|
} else {
|
||||||
|
resolve();
|
||||||
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -71,28 +77,30 @@ export async function compileSassAll(worker) {
|
||||||
const limitFn = pLimit(4);
|
const limitFn = pLimit(4);
|
||||||
const sourceDir = "src";
|
const sourceDir = "src";
|
||||||
|
|
||||||
let files = await fs.readdir(sourceDir, { recursive: true })
|
let files = await fs.readdir(sourceDir, { recursive: true });
|
||||||
files = files.filter((path) => path.endsWith(".scss"));
|
files = files.filter((path) => path.endsWith(".scss"));
|
||||||
files = files.map((path) => ph.join(sourceDir, path));
|
files = files.map((path) => ph.join(sourceDir, path));
|
||||||
// files = files.slice(0, 10);
|
|
||||||
|
|
||||||
const procs = [
|
const procs = [
|
||||||
compileSass(worker, "resources/styles/main-default.scss", {}),
|
compileSass(worker, "resources/styles/main-default.scss", {}),
|
||||||
compileSass(worker, "resources/styles/debug.scss", {})
|
compileSass(worker, "resources/styles/debug.scss", {}),
|
||||||
];
|
];
|
||||||
|
|
||||||
for (let path of files) {
|
for (let path of files) {
|
||||||
const proc = limitFn(() => compileSass(worker, path, {modules: true}));
|
const proc = limitFn(() => compileSass(worker, path, { modules: true }));
|
||||||
procs.push(proc);
|
procs.push(proc);
|
||||||
}
|
}
|
||||||
|
|
||||||
const result = await Promise.all(procs);
|
const result = await Promise.all(procs);
|
||||||
|
|
||||||
return result.reduce((acc, item, index) => {
|
return result.reduce(
|
||||||
acc.index[item.outputPath] = item.css;
|
(acc, item, index) => {
|
||||||
acc.items.push(item.outputPath);
|
acc.index[item.outputPath] = item.css;
|
||||||
return acc;
|
acc.items.push(item.outputPath);
|
||||||
}, {index:{}, items: []});
|
return acc;
|
||||||
|
},
|
||||||
|
{ index: {}, items: [] },
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function compare(a, b) {
|
function compare(a, b) {
|
||||||
|
@ -106,7 +114,7 @@ function compare(a, b) {
|
||||||
}
|
}
|
||||||
|
|
||||||
export function concatSass(data) {
|
export function concatSass(data) {
|
||||||
const output = []
|
const output = [];
|
||||||
|
|
||||||
for (let path of data.items) {
|
for (let path of data.items) {
|
||||||
output.push(data.index[path]);
|
output.push(data.index[path]);
|
||||||
|
@ -118,10 +126,9 @@ export function concatSass(data) {
|
||||||
export async function watch(baseDir, predicate, callback) {
|
export async function watch(baseDir, predicate, callback) {
|
||||||
predicate = predicate ?? (() => true);
|
predicate = predicate ?? (() => true);
|
||||||
|
|
||||||
|
|
||||||
const watcher = new Watcher(baseDir, {
|
const watcher = new Watcher(baseDir, {
|
||||||
persistent: true,
|
persistent: true,
|
||||||
recursive: true
|
recursive: true,
|
||||||
});
|
});
|
||||||
|
|
||||||
watcher.on("change", (path) => {
|
watcher.on("change", (path) => {
|
||||||
|
@ -133,7 +140,7 @@ export async function watch(baseDir, predicate, callback) {
|
||||||
|
|
||||||
async function readShadowManifest() {
|
async function readShadowManifest() {
|
||||||
try {
|
try {
|
||||||
const manifestPath = "resources/public/js/manifest.json"
|
const manifestPath = "resources/public/js/manifest.json";
|
||||||
let content = await fs.readFile(manifestPath, { encoding: "utf8" });
|
let content = await fs.readFile(manifestPath, { encoding: "utf8" });
|
||||||
content = JSON.parse(content);
|
content = JSON.parse(content);
|
||||||
|
|
||||||
|
@ -148,7 +155,6 @@ async function readShadowManifest() {
|
||||||
|
|
||||||
return index;
|
return index;
|
||||||
} catch (cause) {
|
} catch (cause) {
|
||||||
// log.error("error on reading manifest (using default)", cause);
|
|
||||||
return {
|
return {
|
||||||
config: "js/config.js",
|
config: "js/config.js",
|
||||||
polyfills: "js/polyfills.js",
|
polyfills: "js/polyfills.js",
|
||||||
|
@ -160,14 +166,14 @@ async function readShadowManifest() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function renderTemplate(path, context={}, partials={}) {
|
async function renderTemplate(path, context = {}, partials = {}) {
|
||||||
const content = await fs.readFile(path, {encoding: "utf-8"});
|
const content = await fs.readFile(path, { encoding: "utf-8" });
|
||||||
|
|
||||||
const ts = Math.floor(new Date());
|
const ts = Math.floor(new Date());
|
||||||
|
|
||||||
context = Object.assign({}, context, {
|
context = Object.assign({}, context, {
|
||||||
ts: ts,
|
ts: ts,
|
||||||
isDebug: process.env.NODE_ENV !== "production"
|
isDebug: process.env.NODE_ENV !== "production",
|
||||||
});
|
});
|
||||||
|
|
||||||
return mustache.render(content, context, partials);
|
return mustache.render(content, context, partials);
|
||||||
|
@ -214,9 +220,8 @@ async function readTranslations() {
|
||||||
// this happens when file does not matches correct
|
// this happens when file does not matches correct
|
||||||
// iso code for the language.
|
// iso code for the language.
|
||||||
["ja_jp", "jpn_JP"],
|
["ja_jp", "jpn_JP"],
|
||||||
// ["fi", "fin_FI"],
|
|
||||||
["uk", "ukr_UA"],
|
["uk", "ukr_UA"],
|
||||||
"ha"
|
"ha",
|
||||||
];
|
];
|
||||||
const result = {};
|
const result = {};
|
||||||
|
|
||||||
|
@ -261,10 +266,6 @@ async function readTranslations() {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
// if (key === "modals.delete-font.title") {
|
|
||||||
// console.dir(trdata[key], {depth:10});
|
|
||||||
// console.dir(result[key], {depth:10});
|
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -274,13 +275,13 @@ async function readTranslations() {
|
||||||
async function generateSvgSprite(files, prefix) {
|
async function generateSvgSprite(files, prefix) {
|
||||||
const spriter = new SVGSpriter({
|
const spriter = new SVGSpriter({
|
||||||
mode: {
|
mode: {
|
||||||
symbol: { inline: true }
|
symbol: { inline: true },
|
||||||
}
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
for (let path of files) {
|
for (let path of files) {
|
||||||
const name = `${prefix}${ph.basename(path)}`
|
const name = `${prefix}${ph.basename(path)}`;
|
||||||
const content = await fs.readFile(path, {encoding: "utf-8"});
|
const content = await fs.readFile(path, { encoding: "utf-8" });
|
||||||
spriter.add(name, name, content);
|
spriter.add(name, name, content);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -302,6 +303,7 @@ async function generateSvgSprites() {
|
||||||
}
|
}
|
||||||
|
|
||||||
async function generateTemplates() {
|
async function generateTemplates() {
|
||||||
|
const isDebug = process.env.NODE_ENV !== "production";
|
||||||
await fs.mkdir("./resources/public/", { recursive: true });
|
await fs.mkdir("./resources/public/", { recursive: true });
|
||||||
|
|
||||||
const translations = await readTranslations();
|
const translations = await readTranslations();
|
||||||
|
@ -315,13 +317,19 @@ async function generateTemplates() {
|
||||||
"../public/images/sprites/symbol/cursors.svg": cursorsSprite,
|
"../public/images/sprites/symbol/cursors.svg": cursorsSprite,
|
||||||
};
|
};
|
||||||
|
|
||||||
const pluginRuntimeUri = (process.env.PENPOT_PLUGIN_DEV === "true") ? "http://localhost:4200" : "./plugins-runtime";
|
const pluginRuntimeUri =
|
||||||
|
process.env.PENPOT_PLUGIN_DEV === "true" ? "http://localhost:4200" : "./plugins-runtime";
|
||||||
|
|
||||||
content = await renderTemplate("resources/templates/index.mustache", {
|
content = await renderTemplate(
|
||||||
manifest: manifest,
|
"resources/templates/index.mustache",
|
||||||
translations: JSON.stringify(translations),
|
{
|
||||||
pluginRuntimeUri,
|
manifest: manifest,
|
||||||
}, partials);
|
translations: JSON.stringify(translations),
|
||||||
|
pluginRuntimeUri,
|
||||||
|
isDebug,
|
||||||
|
},
|
||||||
|
partials,
|
||||||
|
);
|
||||||
|
|
||||||
await fs.writeFile("./resources/public/index.html", content);
|
await fs.writeFile("./resources/public/index.html", content);
|
||||||
|
|
||||||
|
@ -351,7 +359,7 @@ export async function compileStyles() {
|
||||||
const worker = startWorker();
|
const worker = startWorker();
|
||||||
const start = process.hrtime();
|
const start = process.hrtime();
|
||||||
|
|
||||||
log.info("init: compile styles")
|
log.info("init: compile styles");
|
||||||
let result = await compileSassAll(worker);
|
let result = await compileSassAll(worker);
|
||||||
result = concatSass(result);
|
result = concatSass(result);
|
||||||
|
|
||||||
|
@ -365,7 +373,7 @@ export async function compileStyles() {
|
||||||
|
|
||||||
export async function compileSvgSprites() {
|
export async function compileSvgSprites() {
|
||||||
const start = process.hrtime();
|
const start = process.hrtime();
|
||||||
log.info("init: compile svgsprite")
|
log.info("init: compile svgsprite");
|
||||||
await generateSvgSprites();
|
await generateSvgSprites();
|
||||||
const end = process.hrtime(start);
|
const end = process.hrtime(start);
|
||||||
log.info("done: compile svgsprite", `(${ppt(end)})`);
|
log.info("done: compile svgsprite", `(${ppt(end)})`);
|
||||||
|
@ -373,7 +381,7 @@ export async function compileSvgSprites() {
|
||||||
|
|
||||||
export async function compileTemplates() {
|
export async function compileTemplates() {
|
||||||
const start = process.hrtime();
|
const start = process.hrtime();
|
||||||
log.info("init: compile templates")
|
log.info("init: compile templates");
|
||||||
await generateTemplates();
|
await generateTemplates();
|
||||||
const end = process.hrtime(start);
|
const end = process.hrtime(start);
|
||||||
log.info("done: compile templates", `(${ppt(end)})`);
|
log.info("done: compile templates", `(${ppt(end)})`);
|
||||||
|
@ -381,13 +389,12 @@ export async function compileTemplates() {
|
||||||
|
|
||||||
export async function compilePolyfills() {
|
export async function compilePolyfills() {
|
||||||
const start = process.hrtime();
|
const start = process.hrtime();
|
||||||
log.info("init: compile polyfills")
|
log.info("init: compile polyfills");
|
||||||
|
|
||||||
|
|
||||||
const files = await findFiles("resources/polyfills/", isJsFile);
|
const files = await findFiles("resources/polyfills/", isJsFile);
|
||||||
let result = [];
|
let result = [];
|
||||||
for (let path of files) {
|
for (let path of files) {
|
||||||
const content = await fs.readFile(path, {encoding:"utf-8"});
|
const content = await fs.readFile(path, { encoding: "utf-8" });
|
||||||
result.push(content);
|
result.push(content);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -400,7 +407,7 @@ export async function compilePolyfills() {
|
||||||
|
|
||||||
export async function copyAssets() {
|
export async function copyAssets() {
|
||||||
const start = process.hrtime();
|
const start = process.hrtime();
|
||||||
log.info("init: copy assets")
|
log.info("init: copy assets");
|
||||||
|
|
||||||
await syncDirs("resources/images/", "resources/public/images/");
|
await syncDirs("resources/images/", "resources/public/images/");
|
||||||
await syncDirs("resources/fonts/", "resources/public/fonts/");
|
await syncDirs("resources/fonts/", "resources/public/fonts/");
|
||||||
|
@ -409,4 +416,3 @@ export async function copyAssets() {
|
||||||
const end = process.hrtime(start);
|
const end = process.hrtime(start);
|
||||||
log.info("done: copy assets", `(${ppt(end)})`);
|
log.info("done: copy assets", `(${ppt(end)})`);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -58,7 +58,6 @@
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.demo-account,
|
|
||||||
.go-back {
|
.go-back {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
|
@ -67,7 +66,6 @@
|
||||||
border-block-start: none;
|
border-block-start: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.demo-account-link,
|
|
||||||
.go-back-link {
|
.go-back-link {
|
||||||
@extend .button-secondary;
|
@extend .button-secondary;
|
||||||
@include uppercaseTitleTipography;
|
@include uppercaseTitleTipography;
|
||||||
|
@ -81,7 +79,8 @@
|
||||||
|
|
||||||
.register,
|
.register,
|
||||||
.account,
|
.account,
|
||||||
.recovery-request {
|
.recovery-request,
|
||||||
|
.demo-account {
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
gap: $s-8;
|
gap: $s-8;
|
||||||
|
@ -90,7 +89,8 @@
|
||||||
|
|
||||||
.register-text,
|
.register-text,
|
||||||
.account-text,
|
.account-text,
|
||||||
.recovery-text {
|
.recovery-text,
|
||||||
|
.demo-account-text {
|
||||||
@include smallTitleTipography;
|
@include smallTitleTipography;
|
||||||
text-align: right;
|
text-align: right;
|
||||||
color: var(--title-foreground-color);
|
color: var(--title-foreground-color);
|
||||||
|
@ -99,7 +99,8 @@
|
||||||
.register-link,
|
.register-link,
|
||||||
.account-link,
|
.account-link,
|
||||||
.recovery-link,
|
.recovery-link,
|
||||||
.forgot-pass-link {
|
.forgot-pass-link,
|
||||||
|
.demo-account-link {
|
||||||
@include smallTitleTipography;
|
@include smallTitleTipography;
|
||||||
text-align: left;
|
text-align: left;
|
||||||
background-color: transparent;
|
background-color: transparent;
|
||||||
|
|
|
@ -158,7 +158,7 @@
|
||||||
[:*
|
[:*
|
||||||
(when-let [message @error]
|
(when-let [message @error]
|
||||||
[:& context-notification
|
[:& context-notification
|
||||||
{:type :warning
|
{:type :error
|
||||||
:content message
|
:content message
|
||||||
:data-test "login-banner"
|
:data-test "login-banner"
|
||||||
:role "alert"}])
|
:role "alert"}])
|
||||||
|
@ -300,11 +300,13 @@
|
||||||
[:& lk/link {:action go-register
|
[:& lk/link {:action go-register
|
||||||
:class (stl/css :register-link)
|
:class (stl/css :register-link)
|
||||||
:data-test "register-submit"}
|
:data-test "register-submit"}
|
||||||
(tr "auth.register-submit")]])]
|
(tr "auth.register-submit")]])
|
||||||
|
|
||||||
(when (contains? cf/flags :demo-users)
|
(when (contains? cf/flags :demo-users)
|
||||||
[:div {:class (stl/css :link-entry :demo-account)}
|
[:div {:class (stl/css :demo-account)}
|
||||||
[:span (tr "auth.create-demo-profile") " "]
|
[:span {:class (stl/css :demo-account-text)}
|
||||||
[:& lk/link {:action create-demo-profile
|
(tr "auth.create-demo-profile") " "]
|
||||||
:data-test "demo-account-link"}
|
[:& lk/link {:action create-demo-profile
|
||||||
(tr "auth.create-demo-account")]])]))
|
:class (stl/css :demo-account-link)
|
||||||
|
:data-test "demo-account-link"}
|
||||||
|
(tr "auth.create-demo-account")]])]]))
|
||||||
|
|
|
@ -12,5 +12,6 @@
|
||||||
margin-top: $s-8;
|
margin-top: $s-8;
|
||||||
padding: $s-12;
|
padding: $s-12;
|
||||||
background-color: var(--menu-background-color);
|
background-color: var(--menu-background-color);
|
||||||
|
color: var(--input-foreground-color-active);
|
||||||
overflow: auto;
|
overflow: auto;
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,6 +17,7 @@
|
||||||
(def current-page-id (mf/create-context nil))
|
(def current-page-id (mf/create-context nil))
|
||||||
(def current-file-id (mf/create-context nil))
|
(def current-file-id (mf/create-context nil))
|
||||||
(def current-vbox (mf/create-context nil))
|
(def current-vbox (mf/create-context nil))
|
||||||
|
(def current-svg-root-id (mf/create-context nil))
|
||||||
|
|
||||||
(def active-frames (mf/create-context nil))
|
(def active-frames (mf/create-context nil))
|
||||||
(def render-thumbnails (mf/create-context nil))
|
(def render-thumbnails (mf/create-context nil))
|
||||||
|
|
|
@ -85,8 +85,6 @@
|
||||||
color: var(--title-foreground-color-hover);
|
color: var(--title-foreground-color-hover);
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
height: $s-16;
|
height: $s-16;
|
||||||
display: inline-flex;
|
|
||||||
align-items: center;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.info-wrapper {
|
.info-wrapper {
|
||||||
|
|
|
@ -17,6 +17,7 @@
|
||||||
(mf/fnc group-shape
|
(mf/fnc group-shape
|
||||||
{::mf/wrap-props false}
|
{::mf/wrap-props false}
|
||||||
[props]
|
[props]
|
||||||
|
|
||||||
(let [shape (unchecked-get props "shape")
|
(let [shape (unchecked-get props "shape")
|
||||||
childs (unchecked-get props "childs")
|
childs (unchecked-get props "childs")
|
||||||
render-id (mf/use-ctx muc/render-id)
|
render-id (mf/use-ctx muc/render-id)
|
||||||
|
@ -36,21 +37,31 @@
|
||||||
|
|
||||||
mask-props (if ^boolean masked-group?
|
mask-props (if ^boolean masked-group?
|
||||||
#js {:mask (mask-url render-id mask)}
|
#js {:mask (mask-url render-id mask)}
|
||||||
#js {})]
|
#js {})
|
||||||
|
|
||||||
|
current-svg-root-id (mf/use-ctx muc/current-svg-root-id)
|
||||||
|
|
||||||
|
;; We need to create a "scope" for svg classes. The root of the imported SVG (first group) will
|
||||||
|
;; be stored in the context. When rendering the styles we add its id as prefix.
|
||||||
|
[svg-wrapper svg-wrapper-props]
|
||||||
|
(if (and (contains? shape :svg-attrs) (not current-svg-root-id))
|
||||||
|
[(mf/provider muc/current-svg-root-id) #js {:value (:id shape)}]
|
||||||
|
[mf/Fragment #js {}])]
|
||||||
|
|
||||||
;; We need to separate mask and clip into two because a bug in
|
;; We need to separate mask and clip into two because a bug in
|
||||||
;; Firefox breaks when the group has clip+mask+foreignObject
|
;; Firefox breaks when the group has clip+mask+foreignObject
|
||||||
;; Clip and mask separated will work in every platform Firefox
|
;; Clip and mask separated will work in every platform Firefox
|
||||||
;; bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1734805
|
;; bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1734805
|
||||||
[:> wrapper clip-props
|
[:> svg-wrapper svg-wrapper-props
|
||||||
[:> wrapper mask-props
|
[:> wrapper clip-props
|
||||||
(when ^boolean masked-group?
|
[:> wrapper mask-props
|
||||||
[:& render-mask {:mask mask}])
|
(when ^boolean masked-group?
|
||||||
|
[:& render-mask {:mask mask}])
|
||||||
|
|
||||||
(for [item childs]
|
(for [item childs]
|
||||||
[:& shape-wrapper
|
[:& shape-wrapper
|
||||||
{:shape item
|
{:shape item
|
||||||
:key (dm/str (dm/get-prop item :id))}])]]))))
|
:key (dm/str (dm/get-prop item :id))}])]]]))))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -104,9 +104,20 @@
|
||||||
svg-root? (and (map? content) (= tag :svg))
|
svg-root? (and (map? content) (= tag :svg))
|
||||||
svg-tag? (map? content)
|
svg-tag? (map? content)
|
||||||
svg-leaf? (string? content)
|
svg-leaf? (string? content)
|
||||||
valid-tag? (contains? csvg/svg-tags tag)]
|
valid-tag? (contains? csvg/svg-tags tag)
|
||||||
|
|
||||||
|
current-svg-root-id (mf/use-ctx muc/current-svg-root-id)
|
||||||
|
|
||||||
|
;; We need to create a "scope" for svg classes. The root of the imported SVG (first group) will
|
||||||
|
;; be stored in the context and with this we scoped the styles:
|
||||||
|
style-content
|
||||||
|
(when (= tag :style)
|
||||||
|
(dm/str "#shape-" current-svg-root-id "{ " (->> shape :content :content (str/join "\n")) " }"))]
|
||||||
|
|
||||||
(cond
|
(cond
|
||||||
|
(= tag :style)
|
||||||
|
[:style style-content]
|
||||||
|
|
||||||
^boolean svg-root?
|
^boolean svg-root?
|
||||||
[:& svg-root {:shape shape}
|
[:& svg-root {:shape shape}
|
||||||
(for [item childs]
|
(for [item childs]
|
||||||
|
|
|
@ -54,13 +54,7 @@
|
||||||
get-sorted-colors
|
get-sorted-colors
|
||||||
(mf/use-fn
|
(mf/use-fn
|
||||||
(fn [colors]
|
(fn [colors]
|
||||||
(sort (fn [a b]
|
(sort c/sort-colors (into [] (filter check-valid-color?) colors))))
|
||||||
(let [[ah _ al] (c/hex->hsl (:color a))
|
|
||||||
[bh _ bl] (c/hex->hsl (:color b))
|
|
||||||
a (+ (* ah 100) (* al 99))
|
|
||||||
b (+ (* bh 100) (* bl 99))]
|
|
||||||
(compare a b)))
|
|
||||||
(into [] (filter check-valid-color?) colors))))
|
|
||||||
|
|
||||||
toggle-palette
|
toggle-palette
|
||||||
(mf/use-fn
|
(mf/use-fn
|
||||||
|
|
|
@ -101,6 +101,7 @@
|
||||||
(fn []
|
(fn []
|
||||||
(->> (http/send! {:method :get
|
(->> (http/send! {:method :get
|
||||||
:uri plugin-url
|
:uri plugin-url
|
||||||
|
:omit-default-headers true
|
||||||
:response-type :json})
|
:response-type :json})
|
||||||
(rx/map :body)
|
(rx/map :body)
|
||||||
(rx/subs!
|
(rx/subs!
|
||||||
|
|
|
@ -32,12 +32,6 @@
|
||||||
;;
|
;;
|
||||||
;; PLUGINS PUBLIC API - The plugins will able to access this functions
|
;; PLUGINS PUBLIC API - The plugins will able to access this functions
|
||||||
;;
|
;;
|
||||||
(def ^:private
|
|
||||||
xf-map-shape-proxy
|
|
||||||
(comp
|
|
||||||
(map val)
|
|
||||||
(map shape/data->shape-proxy)))
|
|
||||||
|
|
||||||
(defn create-shape
|
(defn create-shape
|
||||||
[type]
|
[type]
|
||||||
(let [page-id (:current-page-id @st/state)
|
(let [page-id (:current-page-id @st/state)
|
||||||
|
@ -50,7 +44,7 @@
|
||||||
(cb/with-objects (:objects page))
|
(cb/with-objects (:objects page))
|
||||||
(cb/add-object shape))]
|
(cb/add-object shape))]
|
||||||
(st/emit! (ch/commit-changes changes))
|
(st/emit! (ch/commit-changes changes))
|
||||||
(shape/data->shape-proxy shape)))
|
(shape/shape-proxy (:id shape))))
|
||||||
|
|
||||||
(deftype PenpotContext []
|
(deftype PenpotContext []
|
||||||
Object
|
Object
|
||||||
|
@ -64,13 +58,13 @@
|
||||||
|
|
||||||
(getFile
|
(getFile
|
||||||
[_]
|
[_]
|
||||||
(file/data->file-proxy (:workspace-file @st/state) (:workspace-data @st/state)))
|
(file/file-proxy (:current-file-id @st/state)))
|
||||||
|
|
||||||
(getPage
|
(getPage
|
||||||
[_]
|
[_]
|
||||||
(let [page-id (:current-page-id @st/state)
|
(let [file-id (:current-file-id @st/state)
|
||||||
page (dm/get-in @st/state [:workspace-data :pages-index page-id])]
|
page-id (:current-page-id @st/state)]
|
||||||
(page/data->page-proxy page)))
|
(page/page-proxy file-id page-id)))
|
||||||
|
|
||||||
(getSelected
|
(getSelected
|
||||||
[_]
|
[_]
|
||||||
|
@ -79,17 +73,12 @@
|
||||||
|
|
||||||
(getSelectedShapes
|
(getSelectedShapes
|
||||||
[_]
|
[_]
|
||||||
(let [page-id (:current-page-id @st/state)
|
(let [selection (get-in @st/state [:workspace-local :selected])]
|
||||||
selection (get-in @st/state [:workspace-local :selected])
|
(apply array (sequence (map shape/shape-proxy) selection))))
|
||||||
objects (dm/get-in @st/state [:workspace-data :pages-index page-id :objects])
|
|
||||||
shapes (select-keys objects selection)]
|
|
||||||
(apply array (sequence xf-map-shape-proxy shapes))))
|
|
||||||
|
|
||||||
(getRoot
|
(getRoot
|
||||||
[_]
|
[_]
|
||||||
(let [page-id (:current-page-id @st/state)
|
(shape/shape-proxy uuid/zero))
|
||||||
root (dm/get-in @st/state [:workspace-data :pages-index page-id :objects uuid/zero])]
|
|
||||||
(shape/data->shape-proxy root)))
|
|
||||||
|
|
||||||
(getTheme
|
(getTheme
|
||||||
[_]
|
[_]
|
||||||
|
@ -100,7 +89,7 @@
|
||||||
|
|
||||||
(uploadMediaUrl
|
(uploadMediaUrl
|
||||||
[_ name url]
|
[_ name url]
|
||||||
(let [file-id (get-in @st/state [:workspace-file :id])]
|
(let [file-id (:current-file-id @st/state)]
|
||||||
(p/create
|
(p/create
|
||||||
(fn [resolve reject]
|
(fn [resolve reject]
|
||||||
(->> (dwm/upload-media-url name file-id url)
|
(->> (dwm/upload-media-url name file-id url)
|
||||||
|
@ -110,17 +99,17 @@
|
||||||
|
|
||||||
(group
|
(group
|
||||||
[_ shapes]
|
[_ shapes]
|
||||||
(let [page-id (:current-page-id @st/state)
|
(let [file-id (:current-file-id @st/state)
|
||||||
|
page-id (:current-page-id @st/state)
|
||||||
id (uuid/next)
|
id (uuid/next)
|
||||||
ids (into #{} (map #(get (obj/get % "_data") :id)) shapes)]
|
ids (into #{} (map #(obj/get % "$id")) shapes)]
|
||||||
(st/emit! (dwg/group-shapes id ids))
|
(st/emit! (dwg/group-shapes id ids))
|
||||||
(shape/data->shape-proxy
|
(shape/shape-proxy file-id page-id id)))
|
||||||
(dm/get-in @st/state [:workspace-data :pages-index page-id :objects id]))))
|
|
||||||
|
|
||||||
(ungroup
|
(ungroup
|
||||||
[_ group & rest]
|
[_ group & rest]
|
||||||
(let [shapes (concat [group] rest)
|
(let [shapes (concat [group] rest)
|
||||||
ids (into #{} (map #(get (obj/get % "_data") :id)) shapes)]
|
ids (into #{} (map #(obj/get % "$id")) shapes)]
|
||||||
(st/emit! (dwg/ungroup-shapes ids))))
|
(st/emit! (dwg/ungroup-shapes ids))))
|
||||||
|
|
||||||
(createFrame
|
(createFrame
|
||||||
|
@ -133,7 +122,8 @@
|
||||||
|
|
||||||
(createText
|
(createText
|
||||||
[_ text]
|
[_ text]
|
||||||
(let [page-id (:current-page-id @st/state)
|
(let [file-id (:current-file-id @st/state)
|
||||||
|
page-id (:current-page-id @st/state)
|
||||||
page (dm/get-in @st/state [:workspace-data :pages-index page-id])
|
page (dm/get-in @st/state [:workspace-data :pages-index page-id])
|
||||||
shape (-> (cts/setup-shape {:type :text :x 0 :y 0 :grow-type :auto-width})
|
shape (-> (cts/setup-shape {:type :text :x 0 :y 0 :grow-type :auto-width})
|
||||||
(txt/change-text text)
|
(txt/change-text text)
|
||||||
|
@ -144,23 +134,24 @@
|
||||||
(cb/with-objects (:objects page))
|
(cb/with-objects (:objects page))
|
||||||
(cb/add-object shape))]
|
(cb/add-object shape))]
|
||||||
(st/emit! (ch/commit-changes changes))
|
(st/emit! (ch/commit-changes changes))
|
||||||
(shape/data->shape-proxy shape)))
|
(shape/shape-proxy file-id page-id (:id shape))))
|
||||||
|
|
||||||
(createShapeFromSvg
|
(createShapeFromSvg
|
||||||
[_ svg-string]
|
[_ svg-string]
|
||||||
(when (some? svg-string)
|
(when (some? svg-string)
|
||||||
(let [id (uuid/next)
|
(let [id (uuid/next)
|
||||||
|
file-id (:current-file-id @st/state)
|
||||||
page-id (:current-page-id @st/state)]
|
page-id (:current-page-id @st/state)]
|
||||||
(st/emit! (dwm/create-svg-shape id "svg" svg-string (gpt/point 0 0)))
|
(st/emit! (dwm/create-svg-shape id "svg" svg-string (gpt/point 0 0)))
|
||||||
(shape/data->shape-proxy
|
(shape/shape-proxy file-id page-id id)))))
|
||||||
(dm/get-in @st/state [:workspace-data :pages-index page-id :objects id]))))))
|
|
||||||
|
|
||||||
(defn create-context
|
(defn create-context
|
||||||
[]
|
[]
|
||||||
(cr/add-properties!
|
(cr/add-properties!
|
||||||
(PenpotContext.)
|
(PenpotContext.)
|
||||||
{:name "root" :get #(.getRoot ^js %)}
|
{:name "root" :get #(.getRoot ^js %)}
|
||||||
|
{:name "currentFile" :get #(.getFile ^js %)}
|
||||||
{:name "currentPage" :get #(.getPage ^js %)}
|
{:name "currentPage" :get #(.getPage ^js %)}
|
||||||
{:name "selection" :get #(.getSelectedShapes ^js %)}
|
{:name "selection" :get #(.getSelectedShapes ^js %)}
|
||||||
{:name "viewport" :get #(.getViewport ^js %)}
|
{:name "viewport" :get #(.getViewport ^js %)}
|
||||||
{:name "library" :get (fn [_] (library/create-library-subcontext))}))
|
{:name "library" :get (fn [_] (library/library-subcontext))}))
|
||||||
|
|
|
@ -23,17 +23,18 @@
|
||||||
(if (and (identical? old-file new-file)
|
(if (and (identical? old-file new-file)
|
||||||
(identical? old-data new-data))
|
(identical? old-data new-data))
|
||||||
::not-changed
|
::not-changed
|
||||||
(file/data->file-proxy new-file new-data))))
|
(file/file-proxy (:id new-file)))))
|
||||||
|
|
||||||
(defmethod handle-state-change "pagechange"
|
(defmethod handle-state-change "pagechange"
|
||||||
[_ old-val new-val]
|
[_ old-val new-val]
|
||||||
(let [old-page-id (:current-page-id old-val)
|
(let [file-id (:current-file-id new-val)
|
||||||
|
old-page-id (:current-page-id old-val)
|
||||||
new-page-id (:current-page-id new-val)
|
new-page-id (:current-page-id new-val)
|
||||||
old-page (dm/get-in old-val [:workspace-data :pages-index old-page-id])
|
old-page (dm/get-in old-val [:workspace-data :pages-index old-page-id])
|
||||||
new-page (dm/get-in new-val [:workspace-data :pages-index new-page-id])]
|
new-page (dm/get-in new-val [:workspace-data :pages-index new-page-id])]
|
||||||
(if (identical? old-page new-page)
|
(if (identical? old-page new-page)
|
||||||
::not-changed
|
::not-changed
|
||||||
(page/data->page-proxy new-page))))
|
(page/page-proxy file-id new-page-id))))
|
||||||
|
|
||||||
(defmethod handle-state-change "selectionchange"
|
(defmethod handle-state-change "selectionchange"
|
||||||
[_ old-val new-val]
|
[_ old-val new-val]
|
||||||
|
|
|
@ -7,38 +7,34 @@
|
||||||
(ns app.plugins.file
|
(ns app.plugins.file
|
||||||
"RPC for plugins runtime."
|
"RPC for plugins runtime."
|
||||||
(:require
|
(:require
|
||||||
|
[app.common.data.macros :as dm]
|
||||||
[app.common.record :as crc]
|
[app.common.record :as crc]
|
||||||
[app.plugins.page :as page]
|
[app.plugins.page :as page]
|
||||||
[app.plugins.utils :refer [get-data-fn]]))
|
[app.plugins.utils :refer [locate-file proxy->file]]
|
||||||
|
[app.util.object :as obj]))
|
||||||
|
|
||||||
(def ^:private
|
(deftype FileProxy [$id]
|
||||||
xf-map-page-proxy
|
|
||||||
(comp
|
|
||||||
(map val)
|
|
||||||
(map page/data->page-proxy)))
|
|
||||||
|
|
||||||
(deftype FileProxy [#_:clj-kondo/ignore _data]
|
|
||||||
Object
|
Object
|
||||||
(getPages [_]
|
(getPages [_]
|
||||||
;; Returns a lazy (iterable) of all available pages
|
(let [file (locate-file $id)]
|
||||||
(apply array (sequence xf-map-page-proxy (:pages-index _data)))))
|
(apply array (sequence (map #(page/page-proxy $id %)) (dm/get-in file [:data :pages]))))))
|
||||||
|
|
||||||
(crc/define-properties!
|
(crc/define-properties!
|
||||||
FileProxy
|
FileProxy
|
||||||
{:name js/Symbol.toStringTag
|
{:name js/Symbol.toStringTag
|
||||||
:get (fn [] (str "FileProxy"))})
|
:get (fn [] (str "FileProxy"))})
|
||||||
|
|
||||||
(defn data->file-proxy
|
(defn file-proxy
|
||||||
[file data]
|
[id]
|
||||||
(crc/add-properties!
|
(crc/add-properties!
|
||||||
(FileProxy. (merge file data))
|
(FileProxy. id)
|
||||||
{:name "_data" :enumerable false}
|
{:name "$id" :enumerable false :get (constantly id)}
|
||||||
|
|
||||||
{:name "id"
|
{:name "id"
|
||||||
:get (get-data-fn :id str)}
|
:get #(dm/str (obj/get % "$id"))}
|
||||||
|
|
||||||
{:name "name"
|
{:name "name"
|
||||||
:get (get-data-fn :name)}
|
:get #(-> % proxy->file :name)}
|
||||||
|
|
||||||
{:name "pages"
|
{:name "pages"
|
||||||
:get #(.getPages ^js %)}))
|
:get #(.getPages ^js %)}))
|
||||||
|
|
282
frontend/src/app/plugins/flex.cljs
Normal file
282
frontend/src/app/plugins/flex.cljs
Normal file
|
@ -0,0 +1,282 @@
|
||||||
|
;; 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) KALEIDOS INC
|
||||||
|
|
||||||
|
(ns app.plugins.flex
|
||||||
|
(:require
|
||||||
|
[app.common.data :as d]
|
||||||
|
[app.common.record :as crc]
|
||||||
|
[app.common.spec :as us]
|
||||||
|
[app.common.types.shape.layout :as ctl]
|
||||||
|
[app.main.data.workspace.shape-layout :as dwsl]
|
||||||
|
[app.main.data.workspace.transforms :as dwt]
|
||||||
|
[app.main.store :as st]
|
||||||
|
[app.plugins.utils :as utils :refer [proxy->shape]]
|
||||||
|
[app.util.object :as obj]
|
||||||
|
[potok.v2.core :as ptk]))
|
||||||
|
|
||||||
|
(deftype FlexLayout [$file $page $id]
|
||||||
|
Object
|
||||||
|
(remove
|
||||||
|
[_]
|
||||||
|
(st/emit! (dwsl/remove-layout #{$id})))
|
||||||
|
|
||||||
|
(appendChild
|
||||||
|
[_ child]
|
||||||
|
(let [child-id (obj/get child "$id")]
|
||||||
|
(st/emit! (dwt/move-shapes-to-frame #{child-id} $id nil nil)
|
||||||
|
(ptk/data-event :layout/update {:ids [$id]})))))
|
||||||
|
|
||||||
|
(defn flex-layout-proxy
|
||||||
|
[file-id page-id id]
|
||||||
|
(-> (FlexLayout. file-id page-id id)
|
||||||
|
(crc/add-properties!
|
||||||
|
{:name "$id" :enumerable false :get (constantly id)}
|
||||||
|
{:name "$file" :enumerable false :get (constantly file-id)}
|
||||||
|
{:name "$page" :enumerable false :get (constantly page-id)}
|
||||||
|
|
||||||
|
{:name "dir"
|
||||||
|
:get #(-> % proxy->shape :layout-flex-dir d/name)
|
||||||
|
:set
|
||||||
|
(fn [self value]
|
||||||
|
(let [id (obj/get self "$id")
|
||||||
|
value (keyword value)]
|
||||||
|
(when (contains? ctl/flex-direction-types value)
|
||||||
|
(st/emit! (dwsl/update-layout #{id} {:layout-flex-dir value})))))}
|
||||||
|
|
||||||
|
{:name "alignItems"
|
||||||
|
:get #(-> % proxy->shape :layout-align-items d/name)
|
||||||
|
:set
|
||||||
|
(fn [self value]
|
||||||
|
(let [id (obj/get self "$id")
|
||||||
|
value (keyword value)]
|
||||||
|
(when (contains? ctl/align-items-types value)
|
||||||
|
(st/emit! (dwsl/update-layout #{id} {:layout-align-items value})))))}
|
||||||
|
|
||||||
|
{:name "alignContent"
|
||||||
|
:get #(-> % proxy->shape :layout-align-content d/name)
|
||||||
|
:set
|
||||||
|
(fn [self value]
|
||||||
|
(let [id (obj/get self "$id")
|
||||||
|
value (keyword value)]
|
||||||
|
(when (contains? ctl/align-content-types value)
|
||||||
|
(st/emit! (dwsl/update-layout #{id} {:layout-align-content value})))))}
|
||||||
|
|
||||||
|
{:name "justifyItems"
|
||||||
|
:get #(-> % proxy->shape :layout-justify-items d/name)
|
||||||
|
:set
|
||||||
|
(fn [self value]
|
||||||
|
(let [id (obj/get self "$id")
|
||||||
|
value (keyword value)]
|
||||||
|
(when (contains? ctl/justify-items-types value)
|
||||||
|
(st/emit! (dwsl/update-layout #{id} {:layout-justify-items value})))))}
|
||||||
|
|
||||||
|
{:name "justifyContent"
|
||||||
|
:get #(-> % proxy->shape :layout-justify-content d/name)
|
||||||
|
:set
|
||||||
|
(fn [self value]
|
||||||
|
(let [id (obj/get self "$id")
|
||||||
|
value (keyword value)]
|
||||||
|
(when (contains? ctl/justify-content-types value)
|
||||||
|
(st/emit! (dwsl/update-layout #{id} {:layout-justify-content value})))))}
|
||||||
|
|
||||||
|
{:name "rowGap"
|
||||||
|
:get #(-> % proxy->shape :layout-gap :row-gap)
|
||||||
|
:set
|
||||||
|
(fn [self value]
|
||||||
|
(let [id (obj/get self "$id")]
|
||||||
|
(when (us/safe-int? value)
|
||||||
|
(st/emit! (dwsl/update-layout #{id} {:layout-gap {:row-gap value}})))))}
|
||||||
|
|
||||||
|
{:name "columnGap"
|
||||||
|
:get #(-> % proxy->shape :layout-gap :column-gap)
|
||||||
|
:set
|
||||||
|
(fn [self value]
|
||||||
|
(let [id (obj/get self "$id")]
|
||||||
|
(when (us/safe-int? value)
|
||||||
|
(st/emit! (dwsl/update-layout #{id} {:layout-gap {:column-gap value}})))))}
|
||||||
|
|
||||||
|
{:name "verticalPadding"
|
||||||
|
:get #(-> % proxy->shape :layout-padding :p1)
|
||||||
|
:set
|
||||||
|
(fn [self value]
|
||||||
|
(let [id (obj/get self "$id")]
|
||||||
|
(when (us/safe-int? value)
|
||||||
|
(st/emit! (dwsl/update-layout #{id} {:layout-padding {:p1 value :p3 value}})))))}
|
||||||
|
|
||||||
|
{:name "horizontalPadding"
|
||||||
|
:get #(-> % proxy->shape :layout-padding :p2)
|
||||||
|
:set
|
||||||
|
(fn [self value]
|
||||||
|
(let [id (obj/get self "$id")]
|
||||||
|
(when (us/safe-int? value)
|
||||||
|
(st/emit! (dwsl/update-layout #{id} {:layout-padding {:p2 value :p4 value}})))))}
|
||||||
|
|
||||||
|
|
||||||
|
{:name "topPadding"
|
||||||
|
:get #(-> % proxy->shape :layout-padding :p1)
|
||||||
|
:set
|
||||||
|
(fn [self value]
|
||||||
|
(let [id (obj/get self "$id")]
|
||||||
|
(when (us/safe-int? value)
|
||||||
|
(st/emit! (dwsl/update-layout #{id} {:layout-padding {:p1 value}})))))}
|
||||||
|
|
||||||
|
{:name "rightPadding"
|
||||||
|
:get #(-> % proxy->shape :layout-padding :p2)
|
||||||
|
:set
|
||||||
|
(fn [self value]
|
||||||
|
(let [id (obj/get self "$id")]
|
||||||
|
(when (us/safe-int? value)
|
||||||
|
(st/emit! (dwsl/update-layout #{id} {:layout-padding {:p2 value}})))))}
|
||||||
|
|
||||||
|
{:name "bottomPadding"
|
||||||
|
:get #(-> % proxy->shape :layout-padding :p3)
|
||||||
|
:set
|
||||||
|
(fn [self value]
|
||||||
|
(let [id (obj/get self "$id")]
|
||||||
|
(when (us/safe-int? value)
|
||||||
|
(st/emit! (dwsl/update-layout #{id} {:layout-padding {:p3 value}})))))}
|
||||||
|
|
||||||
|
{:name "leftPadding"
|
||||||
|
:get #(-> % proxy->shape :layout-padding :p4)
|
||||||
|
:set
|
||||||
|
(fn [self value]
|
||||||
|
(let [id (obj/get self "$id")]
|
||||||
|
(when (us/safe-int? value)
|
||||||
|
(st/emit! (dwsl/update-layout #{id} {:layout-padding {:p4 value}})))))})))
|
||||||
|
|
||||||
|
|
||||||
|
(deftype LayoutChildProxy [$file $page $id])
|
||||||
|
|
||||||
|
(defn layout-child-proxy
|
||||||
|
[file-id page-id id]
|
||||||
|
(-> (LayoutChildProxy. file-id page-id id)
|
||||||
|
(crc/add-properties!
|
||||||
|
{:name "$id" :enumerable false :get (constantly id)}
|
||||||
|
{:name "$file" :enumerable false :get (constantly file-id)}
|
||||||
|
{:name "$page" :enumerable false :get (constantly page-id)}
|
||||||
|
|
||||||
|
{:name "absolute"
|
||||||
|
:get #(-> % proxy->shape :layout-item-absolute boolean)
|
||||||
|
:set
|
||||||
|
(fn [self value]
|
||||||
|
(let [id (obj/get self "$id")]
|
||||||
|
(when (boolean? value)
|
||||||
|
(st/emit! (dwsl/update-layout #{id} {:layout-item-absolute value})))))}
|
||||||
|
|
||||||
|
{:name "zIndex"
|
||||||
|
:get #(-> % proxy->shape :layout-item-z-index (d/nilv 0))
|
||||||
|
:set
|
||||||
|
(fn [self value]
|
||||||
|
(let [id (obj/get self "$id")]
|
||||||
|
(when (us/safe-int? value)
|
||||||
|
(st/emit! (dwsl/update-layout-child #{id} {:layout-item-z-index value})))))}
|
||||||
|
|
||||||
|
{:name "horizontalSizing"
|
||||||
|
:get #(-> % proxy->shape :layout-item-h-sizing (d/nilv :fix) d/name)
|
||||||
|
:set
|
||||||
|
(fn [self value]
|
||||||
|
(let [id (obj/get self "$id")
|
||||||
|
value (keyword value)]
|
||||||
|
(when (contains? ctl/item-h-sizing-types value)
|
||||||
|
(st/emit! (dwsl/update-layout-child #{id} {:layout-item-h-sizing value})))))}
|
||||||
|
|
||||||
|
{:name "verticalSizing"
|
||||||
|
:get #(-> % proxy->shape :layout-item-v-sizing (d/nilv :fix) d/name)
|
||||||
|
:set
|
||||||
|
(fn [self value]
|
||||||
|
(let [id (obj/get self "$id")
|
||||||
|
value (keyword value)]
|
||||||
|
(when (contains? ctl/item-v-sizing-types value)
|
||||||
|
(st/emit! (dwsl/update-layout-child #{id} {:layout-item-v-sizing value})))))}
|
||||||
|
|
||||||
|
{:name "alignSelf"
|
||||||
|
:get #(-> % proxy->shape :layout-item-align-self (d/nilv :auto) d/name)
|
||||||
|
:set
|
||||||
|
(fn [self value]
|
||||||
|
(let [id (obj/get self "$id")
|
||||||
|
value (keyword value)]
|
||||||
|
(when (contains? ctl/item-align-self-types value)
|
||||||
|
(st/emit! (dwsl/update-layout-child #{id} {:layout-item-align-self value})))))}
|
||||||
|
|
||||||
|
{:name "verticalMargin"
|
||||||
|
:get #(-> % proxy->shape :layout-item-margin :m1 (d/nilv 0))
|
||||||
|
:set
|
||||||
|
(fn [self value]
|
||||||
|
(let [id (obj/get self "$id")]
|
||||||
|
(when (us/safe-number? value)
|
||||||
|
(st/emit! (dwsl/update-layout-child #{id} {:layout-item-margin {:m1 value :m3 value}})))))}
|
||||||
|
|
||||||
|
{:name "horizontalMargin"
|
||||||
|
:get #(-> % proxy->shape :layout-item-margin :m2 (d/nilv 0))
|
||||||
|
:set
|
||||||
|
(fn [self value]
|
||||||
|
(let [id (obj/get self "$id")]
|
||||||
|
(when (us/safe-number? value)
|
||||||
|
(st/emit! (dwsl/update-layout-child #{id} {:layout-item-margin {:m2 value :m4 value}})))))}
|
||||||
|
|
||||||
|
{:name "topMargin"
|
||||||
|
:get #(-> % proxy->shape :layout-item-margin :m1 (d/nilv 0))
|
||||||
|
:set
|
||||||
|
(fn [self value]
|
||||||
|
(let [id (obj/get self "$id")]
|
||||||
|
(when (us/safe-number? value)
|
||||||
|
(st/emit! (dwsl/update-layout-child #{id} {:layout-item-margin {:m1 value}})))))}
|
||||||
|
|
||||||
|
{:name "rightMargin"
|
||||||
|
:get #(-> % proxy->shape :layout-item-margin :m2 (d/nilv 0))
|
||||||
|
:set
|
||||||
|
(fn [self value]
|
||||||
|
(let [id (obj/get self "$id")]
|
||||||
|
(when (us/safe-number? value)
|
||||||
|
(st/emit! (dwsl/update-layout-child #{id} {:layout-item-margin {:m2 value}})))))}
|
||||||
|
|
||||||
|
{:name "bottomMargin"
|
||||||
|
:get #(-> % proxy->shape :layout-item-margin :m3 (d/nilv 0))
|
||||||
|
:set
|
||||||
|
(fn [self value]
|
||||||
|
(let [id (obj/get self "$id")]
|
||||||
|
(when (us/safe-number? value)
|
||||||
|
(st/emit! (dwsl/update-layout-child #{id} {:layout-item-margin {:m3 value}})))))}
|
||||||
|
|
||||||
|
{:name "leftMargin"
|
||||||
|
:get #(-> % proxy->shape :layout-item-margin :m4 (d/nilv 0))
|
||||||
|
:set
|
||||||
|
(fn [self value]
|
||||||
|
(let [id (obj/get self "$id")]
|
||||||
|
(when (us/safe-number? value)
|
||||||
|
(st/emit! (dwsl/update-layout-child #{id} {:layout-item-margin {:m4 value}})))))}
|
||||||
|
|
||||||
|
{:name "maxWidth"
|
||||||
|
:get #(-> % proxy->shape :layout-item-max-w)
|
||||||
|
:set
|
||||||
|
(fn [self value]
|
||||||
|
(let [id (obj/get self "$id")]
|
||||||
|
(when (us/safe-number? value)
|
||||||
|
(st/emit! (dwsl/update-layout-child #{id} {:layout-item-max-w value})))))}
|
||||||
|
|
||||||
|
{:name "minWidth"
|
||||||
|
:get #(-> % proxy->shape :layout-item-min-w)
|
||||||
|
:set
|
||||||
|
(fn [self value]
|
||||||
|
(let [id (obj/get self "$id")]
|
||||||
|
(when (us/safe-number? value)
|
||||||
|
(st/emit! (dwsl/update-layout-child #{id} {:layout-item-min-w value})))))}
|
||||||
|
|
||||||
|
{:name "maxHeight"
|
||||||
|
:get #(-> % proxy->shape :layout-item-max-h)
|
||||||
|
:set
|
||||||
|
(fn [self value]
|
||||||
|
(let [id (obj/get self "$id")]
|
||||||
|
(when (us/safe-number? value)
|
||||||
|
(st/emit! (dwsl/update-layout-child #{id} {:layout-item-max-h value})))))}
|
||||||
|
|
||||||
|
{:name "minHeight"
|
||||||
|
:get #(-> % proxy->shape :layout-item-min-h)
|
||||||
|
:set
|
||||||
|
(fn [self value]
|
||||||
|
(let [id (obj/get self "$id")]
|
||||||
|
(when (us/safe-number? value)
|
||||||
|
(st/emit! (dwsl/update-layout-child #{id} {:layout-item-min-h value})))))})))
|
|
@ -10,11 +10,10 @@
|
||||||
[app.common.record :as crc]
|
[app.common.record :as crc]
|
||||||
[app.common.spec :as us]
|
[app.common.spec :as us]
|
||||||
[app.common.types.shape.layout :as ctl]
|
[app.common.types.shape.layout :as ctl]
|
||||||
[app.common.uuid :as uuid]
|
|
||||||
[app.main.data.workspace.shape-layout :as dwsl]
|
[app.main.data.workspace.shape-layout :as dwsl]
|
||||||
[app.main.data.workspace.transforms :as dwt]
|
[app.main.data.workspace.transforms :as dwt]
|
||||||
[app.main.store :as st]
|
[app.main.store :as st]
|
||||||
[app.plugins.utils :as utils :refer [get-data get-state]]
|
[app.plugins.utils :as utils :refer [proxy->shape locate-shape]]
|
||||||
[app.util.object :as obj]
|
[app.util.object :as obj]
|
||||||
[potok.v2.core :as ptk]))
|
[potok.v2.core :as ptk]))
|
||||||
|
|
||||||
|
@ -24,183 +23,266 @@
|
||||||
js/Object
|
js/Object
|
||||||
(apply array (->> tracks (map utils/to-js)))))
|
(apply array (->> tracks (map utils/to-js)))))
|
||||||
|
|
||||||
(deftype GridLayout [_data]
|
(deftype GridLayout [$file $page $id]
|
||||||
Object
|
Object
|
||||||
|
|
||||||
(addRow
|
(addRow
|
||||||
[self type value]
|
[_ type value]
|
||||||
(let [id (get-data self :id)
|
(let [type (keyword type)]
|
||||||
type (keyword type)]
|
(st/emit! (dwsl/add-layout-track #{$id} :row {:type type :value value}))))
|
||||||
(st/emit! (dwsl/add-layout-track #{id} :row {:type type :value value}))))
|
|
||||||
|
|
||||||
(addRowAtIndex
|
(addRowAtIndex
|
||||||
[self index type value]
|
[_ index type value]
|
||||||
(let [id (get-data self :id)
|
(let [type (keyword type)]
|
||||||
type (keyword type)]
|
(st/emit! (dwsl/add-layout-track #{$id} :row {:type type :value value} index))))
|
||||||
(st/emit! (dwsl/add-layout-track #{id} :row {:type type :value value} index))))
|
|
||||||
|
|
||||||
(addColumn
|
(addColumn
|
||||||
[self type value]
|
[_ type value]
|
||||||
(let [id (get-data self :id)
|
(let [type (keyword type)]
|
||||||
type (keyword type)]
|
(st/emit! (dwsl/add-layout-track #{$id} :column {:type type :value value}))))
|
||||||
(st/emit! (dwsl/add-layout-track #{id} :column {:type type :value value}))))
|
|
||||||
|
|
||||||
(addColumnAtIndex
|
(addColumnAtIndex
|
||||||
[self index type value]
|
[_ index type value]
|
||||||
(let [id (get-data self :id)
|
(let [type (keyword type)]
|
||||||
type (keyword type)]
|
(st/emit! (dwsl/add-layout-track #{$id} :column {:type type :value value} index))))
|
||||||
(st/emit! (dwsl/add-layout-track #{id} :column {:type type :value value} index))))
|
|
||||||
|
|
||||||
(removeRow
|
(removeRow
|
||||||
[self index]
|
[_ index]
|
||||||
(let [id (get-data self :id)]
|
(st/emit! (dwsl/remove-layout-track #{$id} :row index)))
|
||||||
(st/emit! (dwsl/remove-layout-track #{id} :row index))))
|
|
||||||
|
|
||||||
(removeColumn
|
(removeColumn
|
||||||
[self index]
|
[_ index]
|
||||||
(let [id (get-data self :id)]
|
(st/emit! (dwsl/remove-layout-track #{$id} :column index)))
|
||||||
(st/emit! (dwsl/remove-layout-track #{id} :column index))))
|
|
||||||
|
|
||||||
(setColumn
|
(setColumn
|
||||||
[self index type value]
|
[_ index type value]
|
||||||
(let [id (get-data self :id)
|
(let [type (keyword type)]
|
||||||
type (keyword type)]
|
(st/emit! (dwsl/change-layout-track #{$id} :column index (d/without-nils {:type type :value value})))))
|
||||||
(st/emit! (dwsl/change-layout-track #{id} :column index (d/without-nils {:type type :value value})))))
|
|
||||||
|
|
||||||
(setRow
|
(setRow
|
||||||
[self index type value]
|
[_ index type value]
|
||||||
(let [id (get-data self :id)
|
(let [type (keyword type)]
|
||||||
type (keyword type)]
|
(st/emit! (dwsl/change-layout-track #{$id} :row index (d/without-nils {:type type :value value})))))
|
||||||
(st/emit! (dwsl/change-layout-track #{id} :row index (d/without-nils {:type type :value value})))))
|
|
||||||
|
|
||||||
(remove
|
(remove
|
||||||
[self]
|
[_]
|
||||||
(let [id (get-data self :id)]
|
(st/emit! (dwsl/remove-layout #{$id})))
|
||||||
(st/emit! (dwsl/remove-layout #{id}))))
|
|
||||||
|
|
||||||
(appendChild
|
(appendChild
|
||||||
[self child row column]
|
[_ child row column]
|
||||||
(let [parent-id (get-data self :id)
|
(let [child-id (obj/get child "$id")]
|
||||||
child-id (uuid/uuid (obj/get child "id"))]
|
(st/emit! (dwt/move-shapes-to-frame #{child-id} $id nil [row column])
|
||||||
(st/emit! (dwt/move-shapes-to-frame #{child-id} parent-id nil [row column])
|
(ptk/data-event :layout/update {:ids [$id]})))))
|
||||||
(ptk/data-event :layout/update {:ids [parent-id]})))))
|
|
||||||
|
|
||||||
(defn grid-layout-proxy
|
(defn grid-layout-proxy
|
||||||
[data]
|
[file-id page-id id]
|
||||||
(-> (GridLayout. data)
|
(-> (GridLayout. file-id page-id id)
|
||||||
(crc/add-properties!
|
(crc/add-properties!
|
||||||
|
{:name "$id" :enumerable false :get (constantly id)}
|
||||||
|
{:name "$file" :enumerable false :get (constantly file-id)}
|
||||||
|
{:name "$page" :enumerable false :get (constantly page-id)}
|
||||||
{:name "dir"
|
{:name "dir"
|
||||||
:get #(get-state % :layout-grid-dir d/name)
|
:get #(-> % proxy->shape :layout-grid-dir d/name)
|
||||||
:set
|
:set
|
||||||
(fn [self value]
|
(fn [self value]
|
||||||
(let [id (get-data self :id)
|
(let [id (obj/get self "$id")
|
||||||
value (keyword value)]
|
value (keyword value)]
|
||||||
(when (contains? ctl/grid-direction-types value)
|
(when (contains? ctl/grid-direction-types value)
|
||||||
(st/emit! (dwsl/update-layout #{id} {:layout-grid-dir value})))))}
|
(st/emit! (dwsl/update-layout #{id} {:layout-grid-dir value})))))}
|
||||||
|
|
||||||
{:name "rows"
|
{:name "rows"
|
||||||
:get #(get-state % :layout-grid-rows make-tracks)}
|
:get #(-> % proxy->shape :layout-grid-rows make-tracks)}
|
||||||
|
|
||||||
{:name "columns"
|
{:name "columns"
|
||||||
:get #(get-state % :layout-grid-columns make-tracks)}
|
:get #(-> % proxy->shape :layout-grid-columns make-tracks)}
|
||||||
|
|
||||||
{:name "alignItems"
|
{:name "alignItems"
|
||||||
:get #(get-state % :layout-align-items d/name)
|
:get #(-> % proxy->shape :layout-align-items d/name)
|
||||||
:set
|
:set
|
||||||
(fn [self value]
|
(fn [self value]
|
||||||
(let [id (get-data self :id)
|
(let [id (obj/get self "$id")
|
||||||
value (keyword value)]
|
value (keyword value)]
|
||||||
(when (contains? ctl/align-items-types value)
|
(when (contains? ctl/align-items-types value)
|
||||||
(st/emit! (dwsl/update-layout #{id} {:layout-align-items value})))))}
|
(st/emit! (dwsl/update-layout #{id} {:layout-align-items value})))))}
|
||||||
|
|
||||||
{:name "alignContent"
|
{:name "alignContent"
|
||||||
:get #(get-state % :layout-align-content d/name)
|
:get #(-> % proxy->shape :layout-align-content d/name)
|
||||||
:set
|
:set
|
||||||
(fn [self value]
|
(fn [self value]
|
||||||
(let [id (get-data self :id)
|
(let [id (obj/get self "$id")
|
||||||
value (keyword value)]
|
value (keyword value)]
|
||||||
(when (contains? ctl/align-content-types value)
|
(when (contains? ctl/align-content-types value)
|
||||||
(st/emit! (dwsl/update-layout #{id} {:layout-align-content value})))))}
|
(st/emit! (dwsl/update-layout #{id} {:layout-align-content value})))))}
|
||||||
|
|
||||||
{:name "justifyItems"
|
{:name "justifyItems"
|
||||||
:get #(get-state % :layout-justify-items d/name)
|
:get #(-> % proxy->shape :layout-justify-items d/name)
|
||||||
:set
|
:set
|
||||||
(fn [self value]
|
(fn [self value]
|
||||||
(let [id (get-data self :id)
|
(let [id (obj/get self "$id")
|
||||||
value (keyword value)]
|
value (keyword value)]
|
||||||
(when (contains? ctl/justify-items-types value)
|
(when (contains? ctl/justify-items-types value)
|
||||||
(st/emit! (dwsl/update-layout #{id} {:layout-justify-items value})))))}
|
(st/emit! (dwsl/update-layout #{id} {:layout-justify-items value})))))}
|
||||||
|
|
||||||
{:name "justifyContent"
|
{:name "justifyContent"
|
||||||
:get #(get-state % :layout-justify-content d/name)
|
:get #(-> % proxy->shape :layout-justify-content d/name)
|
||||||
:set
|
:set
|
||||||
(fn [self value]
|
(fn [self value]
|
||||||
(let [id (get-data self :id)
|
(let [id (obj/get self "$id")
|
||||||
value (keyword value)]
|
value (keyword value)]
|
||||||
(when (contains? ctl/justify-content-types value)
|
(when (contains? ctl/justify-content-types value)
|
||||||
(st/emit! (dwsl/update-layout #{id} {:layout-justify-content value})))))}
|
(st/emit! (dwsl/update-layout #{id} {:layout-justify-content value})))))}
|
||||||
|
|
||||||
{:name "rowGap"
|
{:name "rowGap"
|
||||||
:get #(:row-gap (get-state % :layout-gap))
|
:get #(-> % proxy->shape :layout-gap :row-gap)
|
||||||
:set
|
:set
|
||||||
(fn [self value]
|
(fn [self value]
|
||||||
(let [id (get-data self :id)]
|
(let [id (obj/get self "$id")]
|
||||||
(when (us/safe-int? value)
|
(when (us/safe-int? value)
|
||||||
(st/emit! (dwsl/update-layout #{id} {:layout-gap {:row-gap value}})))))}
|
(st/emit! (dwsl/update-layout #{id} {:layout-gap {:row-gap value}})))))}
|
||||||
|
|
||||||
{:name "columnGap"
|
{:name "columnGap"
|
||||||
:get #(:column-gap (get-state % :layout-gap))
|
:get #(-> % proxy->shape :layout-gap :column-gap)
|
||||||
:set
|
:set
|
||||||
(fn [self value]
|
(fn [self value]
|
||||||
(let [id (get-data self :id)]
|
(let [id (obj/get self "$id")]
|
||||||
(when (us/safe-int? value)
|
(when (us/safe-int? value)
|
||||||
(st/emit! (dwsl/update-layout #{id} {:layout-gap {:column-gap value}})))))}
|
(st/emit! (dwsl/update-layout #{id} {:layout-gap {:column-gap value}})))))}
|
||||||
|
|
||||||
{:name "verticalPadding"
|
{:name "verticalPadding"
|
||||||
:get #(:p1 (get-state % :layout-padding))
|
:get #(-> % proxy->shape :layout-padding :p1)
|
||||||
:set
|
:set
|
||||||
(fn [self value]
|
(fn [self value]
|
||||||
(let [id (get-data self :id)]
|
(let [id (obj/get self "$id")]
|
||||||
(when (us/safe-int? value)
|
(when (us/safe-int? value)
|
||||||
(st/emit! (dwsl/update-layout #{id} {:layout-padding {:p1 value :p3 value}})))))}
|
(st/emit! (dwsl/update-layout #{id} {:layout-padding {:p1 value :p3 value}})))))}
|
||||||
|
|
||||||
{:name "horizontalPadding"
|
{:name "horizontalPadding"
|
||||||
:get #(:p2 (get-state % :layout-padding))
|
:get #(-> % proxy->shape :layout-padding :p2)
|
||||||
:set
|
:set
|
||||||
(fn [self value]
|
(fn [self value]
|
||||||
(let [id (get-data self :id)]
|
(let [id (obj/get self "$id")]
|
||||||
(when (us/safe-int? value)
|
(when (us/safe-int? value)
|
||||||
(st/emit! (dwsl/update-layout #{id} {:layout-padding {:p2 value :p4 value}})))))}
|
(st/emit! (dwsl/update-layout #{id} {:layout-padding {:p2 value :p4 value}})))))}
|
||||||
|
|
||||||
|
|
||||||
{:name "topPadding"
|
{:name "topPadding"
|
||||||
:get #(:p1 (get-state % :layout-padding))
|
:get #(-> % proxy->shape :layout-padding :p1)
|
||||||
:set
|
:set
|
||||||
(fn [self value]
|
(fn [self value]
|
||||||
(let [id (get-data self :id)]
|
(let [id (obj/get self "$id")]
|
||||||
(when (us/safe-int? value)
|
(when (us/safe-int? value)
|
||||||
(st/emit! (dwsl/update-layout #{id} {:layout-padding {:p1 value}})))))}
|
(st/emit! (dwsl/update-layout #{id} {:layout-padding {:p1 value}})))))}
|
||||||
|
|
||||||
{:name "rightPadding"
|
{:name "rightPadding"
|
||||||
:get #(:p2 (get-state % :layout-padding))
|
:get #(-> % proxy->shape :layout-padding :p2)
|
||||||
:set
|
:set
|
||||||
(fn [self value]
|
(fn [self value]
|
||||||
(let [id (get-data self :id)]
|
(let [id (obj/get self "$id")]
|
||||||
(when (us/safe-int? value)
|
(when (us/safe-int? value)
|
||||||
(st/emit! (dwsl/update-layout #{id} {:layout-padding {:p2 value}})))))}
|
(st/emit! (dwsl/update-layout #{id} {:layout-padding {:p2 value}})))))}
|
||||||
|
|
||||||
{:name "bottomPadding"
|
{:name "bottomPadding"
|
||||||
:get #(:p3 (get-state % :layout-padding))
|
:get #(-> % proxy->shape :layout-padding :p3)
|
||||||
:set
|
:set
|
||||||
(fn [self value]
|
(fn [self value]
|
||||||
(let [id (get-data self :id)]
|
(let [id (obj/get self "$id")]
|
||||||
(when (us/safe-int? value)
|
(when (us/safe-int? value)
|
||||||
(st/emit! (dwsl/update-layout #{id} {:layout-padding {:p3 value}})))))}
|
(st/emit! (dwsl/update-layout #{id} {:layout-padding {:p3 value}})))))}
|
||||||
|
|
||||||
{:name "leftPadding"
|
{:name "leftPadding"
|
||||||
:get #(:p4 (get-state % :layout-padding))
|
:get #(-> % proxy->shape :layout-padding :p4)
|
||||||
:set
|
:set
|
||||||
(fn [self value]
|
(fn [self value]
|
||||||
(let [id (get-data self :id)]
|
(let [id (obj/get self "$id")]
|
||||||
(when (us/safe-int? value)
|
(when (us/safe-int? value)
|
||||||
(st/emit! (dwsl/update-layout #{id} {:layout-padding {:p4 value}})))))})))
|
(st/emit! (dwsl/update-layout #{id} {:layout-padding {:p4 value}})))))})))
|
||||||
|
|
||||||
|
(deftype GridCellProxy [$file $page $id])
|
||||||
|
|
||||||
|
(defn layout-cell-proxy
|
||||||
|
[file-id page-id id]
|
||||||
|
(letfn [(locate-cell [_]
|
||||||
|
(let [shape (locate-shape file-id page-id id)
|
||||||
|
parent (locate-shape file-id page-id (:parent-id shape))]
|
||||||
|
(ctl/get-cell-by-shape-id parent id)))]
|
||||||
|
|
||||||
|
(-> (GridCellProxy. file-id page-id id)
|
||||||
|
(crc/add-properties!
|
||||||
|
{:name "$id" :enumerable false :get (constantly id)}
|
||||||
|
{:name "$file" :enumerable false :get (constantly file-id)}
|
||||||
|
{:name "$page" :enumerable false :get (constantly page-id)}
|
||||||
|
|
||||||
|
{:name "row"
|
||||||
|
:get #(-> % locate-cell :row)
|
||||||
|
:set
|
||||||
|
(fn [self value]
|
||||||
|
(let [shape (proxy->shape self)
|
||||||
|
cell (locate-cell self)]
|
||||||
|
(when (us/safe-int? value)
|
||||||
|
(st/emit! (dwsl/update-grid-cell-position (:parent-id shape) (:id cell) {:row value})))))}
|
||||||
|
|
||||||
|
{:name "rowSpan"
|
||||||
|
:get #(-> % locate-cell :row-span)
|
||||||
|
:set
|
||||||
|
(fn [self value]
|
||||||
|
(let [shape (proxy->shape self)
|
||||||
|
cell (locate-cell self)]
|
||||||
|
(when (us/safe-int? value)
|
||||||
|
(st/emit! (dwsl/update-grid-cell-position (:parent-id shape) (:id cell) {:row-span value})))))}
|
||||||
|
|
||||||
|
{:name "column"
|
||||||
|
:get #(-> % locate-cell :column)
|
||||||
|
:set
|
||||||
|
(fn [self value]
|
||||||
|
(let [shape (proxy->shape self)
|
||||||
|
cell (locate-cell self)]
|
||||||
|
(when (us/safe-int? value)
|
||||||
|
(st/emit! (dwsl/update-grid-cell-position (:parent-id shape) (:id cell) {:column value})))))}
|
||||||
|
|
||||||
|
{:name "columnSpan"
|
||||||
|
:get #(-> % locate-cell :column-span)
|
||||||
|
:set
|
||||||
|
(fn [self value]
|
||||||
|
(let [shape (proxy->shape self)
|
||||||
|
cell (locate-cell self)]
|
||||||
|
(when (us/safe-int? value)
|
||||||
|
(st/emit! (dwsl/update-grid-cell-position (:parent-id shape) (:id cell) {:column-span value})))))}
|
||||||
|
|
||||||
|
{:name "areaName"
|
||||||
|
:get #(-> % locate-cell :area-name)
|
||||||
|
:set
|
||||||
|
(fn [self value]
|
||||||
|
(let [shape (proxy->shape self)
|
||||||
|
cell (locate-cell self)]
|
||||||
|
(when (string? value)
|
||||||
|
(st/emit! (dwsl/update-grid-cells (:parent-id shape) #{(:id cell)} {:area-name value})))))}
|
||||||
|
|
||||||
|
{:name "position"
|
||||||
|
:get #(-> % locate-cell :position d/name)
|
||||||
|
:set
|
||||||
|
(fn [self value]
|
||||||
|
(let [shape (proxy->shape self)
|
||||||
|
cell (locate-cell self)
|
||||||
|
value (keyword value)]
|
||||||
|
(when (contains? ctl/grid-position-types value)
|
||||||
|
(st/emit! (dwsl/change-cells-mode (:parent-id shape) #{(:id cell)} value)))))}
|
||||||
|
|
||||||
|
{:name "alignSelf"
|
||||||
|
:get #(-> % locate-cell :align-self d/name)
|
||||||
|
:set
|
||||||
|
(fn [self value]
|
||||||
|
(let [shape (proxy->shape self)
|
||||||
|
value (keyword value)
|
||||||
|
cell (locate-cell self)]
|
||||||
|
(when (contains? ctl/grid-cell-align-self-types value)
|
||||||
|
(st/emit! (dwsl/update-grid-cells (:parent-id shape) #{(:id cell)} {:align-self value})))))}
|
||||||
|
|
||||||
|
{:name "justifySelf"
|
||||||
|
:get #(-> % locate-cell :justify-self d/name)
|
||||||
|
:set
|
||||||
|
(fn [self value]
|
||||||
|
(let [shape (proxy->shape self)
|
||||||
|
value (keyword value)
|
||||||
|
cell (locate-cell self)]
|
||||||
|
(when (contains? ctl/grid-cell-justify-self-types value)
|
||||||
|
(st/emit! (dwsl/update-grid-cells (:parent-id shape) #{(:id cell)} {:justify-self value})))))}))))
|
||||||
|
|
|
@ -7,71 +7,135 @@
|
||||||
(ns app.plugins.library
|
(ns app.plugins.library
|
||||||
"RPC for plugins runtime."
|
"RPC for plugins runtime."
|
||||||
(:require
|
(:require
|
||||||
|
[app.common.data :as d]
|
||||||
[app.common.data.macros :as dm]
|
[app.common.data.macros :as dm]
|
||||||
[app.common.record :as cr]
|
[app.common.record :as cr]
|
||||||
[app.main.store :as st]
|
[app.main.store :as st]
|
||||||
[app.plugins.utils :as utils :refer [get-data]]
|
[app.plugins.utils :as u]))
|
||||||
[app.util.object :as obj]))
|
|
||||||
|
|
||||||
(defn get-library-info
|
(deftype LibraryColorProxy [$file $id]
|
||||||
([self attr]
|
Object
|
||||||
(let [lib-id (get-data self :id)
|
|
||||||
current-file-id (:current-file-id @st/state)]
|
|
||||||
(if (= lib-id current-file-id)
|
|
||||||
(dm/get-in @st/state [:workspace-file attr])
|
|
||||||
(dm/get-in @st/state [:workspace-libraries lib-id attr]))))
|
|
||||||
|
|
||||||
([self attr mapfn]
|
(asFill [_]
|
||||||
(-> (get-library-info self attr)
|
(let [color (u/locate-library-color $file $id)]
|
||||||
(mapfn))))
|
(u/to-js
|
||||||
|
(d/without-nils
|
||||||
|
{:fill-color (:color color)
|
||||||
|
:fill-opacity (:opacity color)
|
||||||
|
:fill-color-gradient (:gradient color)
|
||||||
|
:fill-color-ref-file $file
|
||||||
|
:fill-color-ref-id $id
|
||||||
|
:fill-image (:image color)}))))
|
||||||
|
|
||||||
(defn get-library-data
|
(asStroke [_]
|
||||||
([self attr]
|
(let [color (u/locate-library-color $file $id)]
|
||||||
(let [lib-id (get-data self :id)
|
(u/to-js
|
||||||
current-file-id (:current-file-id @st/state)]
|
(d/without-nils
|
||||||
(if (= lib-id current-file-id)
|
{:stroke-color (:color color)
|
||||||
(dm/get-in @st/state [:workspace-data attr])
|
:stroke-opacity (:opacity color)
|
||||||
(dm/get-in @st/state [:workspace-libraries lib-id :data attr]))))
|
:stroke-color-gradient (:gradient color)
|
||||||
|
:stroke-color-ref-file $file
|
||||||
|
:stroke-color-ref-id $id
|
||||||
|
:stroke-image (:image color)
|
||||||
|
:stroke-style :solid
|
||||||
|
:stroke-alignment :inner})))))
|
||||||
|
|
||||||
([self attr mapfn]
|
(defn lib-color-proxy
|
||||||
(-> (get-library-data self attr)
|
[file-id id]
|
||||||
(mapfn))))
|
(assert (uuid? file-id))
|
||||||
|
(assert (uuid? id))
|
||||||
|
|
||||||
(defn- array-to-js
|
|
||||||
[value]
|
|
||||||
(.freeze
|
|
||||||
js/Object
|
|
||||||
(apply array (->> value (map utils/to-js)))))
|
|
||||||
|
|
||||||
(deftype Library [_data]
|
|
||||||
Object)
|
|
||||||
|
|
||||||
(defn create-library
|
|
||||||
[data]
|
|
||||||
(cr/add-properties!
|
(cr/add-properties!
|
||||||
(Library. data)
|
(LibraryColorProxy. file-id id)
|
||||||
{:name "_data"
|
{:name "$id" :enumerable false :get (constantly id)}
|
||||||
:enumerable false}
|
{:name "$file" :enumerable false :get (constantly file-id)}
|
||||||
|
|
||||||
{:name "id"
|
{:name "id" :get (fn [_] (dm/str id))}
|
||||||
:get (fn [self]
|
|
||||||
(str (:id (obj/get self "_data"))))}
|
|
||||||
|
|
||||||
{:name "name"
|
{:name "name"
|
||||||
:get (fn [self]
|
:get #(-> % u/proxy->library-color :name)}
|
||||||
(get-library-info self :name))}
|
|
||||||
|
{:name "color"
|
||||||
|
:get #(-> % u/proxy->library-color :color)}
|
||||||
|
|
||||||
|
{:name "opacity"
|
||||||
|
:get #(-> % u/proxy->library-color :opacity)}
|
||||||
|
|
||||||
|
{:name "gradient"
|
||||||
|
:get #(-> % u/proxy->library-color :gradient u/to-js)}
|
||||||
|
|
||||||
|
{:name "image"
|
||||||
|
:get #(-> % u/proxy->library-color :image u/to-js)}))
|
||||||
|
|
||||||
|
(deftype LibraryTypographyProxy [$file $id]
|
||||||
|
Object)
|
||||||
|
|
||||||
|
(defn lib-typography-proxy
|
||||||
|
[file-id id]
|
||||||
|
(assert (uuid? file-id))
|
||||||
|
(assert (uuid? id))
|
||||||
|
|
||||||
|
(cr/add-properties!
|
||||||
|
(LibraryTypographyProxy. file-id id)
|
||||||
|
{:name "$id" :enumerable false :get (constantly id)}
|
||||||
|
{:name "$file" :enumerable false :get (constantly file-id)}
|
||||||
|
{:name "id" :get (fn [_] (dm/str id))}
|
||||||
|
{:name "name"
|
||||||
|
:get #(-> % u/proxy->library-typography :name)}))
|
||||||
|
|
||||||
|
(deftype LibraryComponentProxy [$file $id]
|
||||||
|
Object)
|
||||||
|
|
||||||
|
(defn lib-component-proxy
|
||||||
|
[file-id id]
|
||||||
|
(assert (uuid? file-id))
|
||||||
|
(assert (uuid? id))
|
||||||
|
|
||||||
|
(cr/add-properties!
|
||||||
|
(LibraryComponentProxy. file-id id)
|
||||||
|
{:name "$id" :enumerable false :get (constantly id)}
|
||||||
|
{:name "$file" :enumerable false :get (constantly file-id)}
|
||||||
|
{:name "id" :get (fn [_] (dm/str id))}
|
||||||
|
{:name "name"
|
||||||
|
:get #(-> % u/proxy->library-component :name)}))
|
||||||
|
|
||||||
|
(deftype Library [$id]
|
||||||
|
Object)
|
||||||
|
|
||||||
|
(defn library-proxy
|
||||||
|
[file-id]
|
||||||
|
(assert (uuid? file-id) "File id not valid")
|
||||||
|
|
||||||
|
(cr/add-properties!
|
||||||
|
(Library. file-id)
|
||||||
|
{:name "$file" :enumerable false :get (constantly file-id)}
|
||||||
|
|
||||||
|
{:name "id"
|
||||||
|
:get #(-> % u/proxy->file :id str)}
|
||||||
|
|
||||||
|
{:name "name"
|
||||||
|
:get #(-> % u/proxy->file :name)}
|
||||||
|
|
||||||
{:name "colors"
|
{:name "colors"
|
||||||
:get (fn [self]
|
:get
|
||||||
(array-to-js (get-library-data self :colors vals)))}
|
(fn [_]
|
||||||
|
(let [file (u/locate-file file-id)
|
||||||
|
colors (->> file :data :colors keys (map #(lib-color-proxy file-id %)))]
|
||||||
|
(apply array colors)))}
|
||||||
|
|
||||||
{:name "typographies"
|
{:name "typographies"
|
||||||
:get (fn [self]
|
:get
|
||||||
(array-to-js (get-library-data self :typographies vals)))}
|
(fn [_]
|
||||||
|
(let [file (u/locate-file file-id)
|
||||||
|
typographies (->> file :data :typographies keys (map #(lib-typography-proxy file-id %)))]
|
||||||
|
(apply array typographies)))}
|
||||||
|
|
||||||
{:name "components"
|
{:name "components"
|
||||||
:get (fn [self]
|
:get
|
||||||
(array-to-js (get-library-data self :components vals)))}))
|
(fn [_]
|
||||||
|
(let [file (u/locate-file file-id)
|
||||||
|
components (->> file :data :componentes keys (map #(lib-component-proxy file-id %)))]
|
||||||
|
(apply array components)))}))
|
||||||
|
|
||||||
(deftype PenpotLibrarySubcontext []
|
(deftype PenpotLibrarySubcontext []
|
||||||
Object
|
Object
|
||||||
|
@ -80,17 +144,15 @@
|
||||||
|
|
||||||
(find [_]))
|
(find [_]))
|
||||||
|
|
||||||
(defn create-library-subcontext
|
(defn library-subcontext
|
||||||
[]
|
[]
|
||||||
(cr/add-properties!
|
(cr/add-properties!
|
||||||
(PenpotLibrarySubcontext.)
|
(PenpotLibrarySubcontext.)
|
||||||
{:name "local" :get
|
{:name "local" :get
|
||||||
(fn [_]
|
(fn [_]
|
||||||
(let [file (get @st/state :workspace-file)
|
(library-proxy (:current-file-id @st/state)))}
|
||||||
data (get @st/state :workspace-data)]
|
|
||||||
(create-library (assoc file :data data))))}
|
|
||||||
|
|
||||||
{:name "connected" :get
|
{:name "connected" :get
|
||||||
(fn [_]
|
(fn [_]
|
||||||
(let [libraries (get @st/state :workspace-libraries)]
|
(let [libraries (get @st/state :workspace-libraries)]
|
||||||
(apply array (->> libraries vals (map create-library)))))}))
|
(apply array (->> libraries vals (map library-proxy)))))}))
|
||||||
|
|
|
@ -7,46 +7,48 @@
|
||||||
(ns app.plugins.page
|
(ns app.plugins.page
|
||||||
"RPC for plugins runtime."
|
"RPC for plugins runtime."
|
||||||
(:require
|
(:require
|
||||||
|
[app.common.data.macros :as dm]
|
||||||
[app.common.record :as crc]
|
[app.common.record :as crc]
|
||||||
[app.common.uuid :as uuid]
|
[app.common.uuid :as uuid]
|
||||||
[app.plugins.shape :as shape]
|
[app.plugins.shape :as shape]
|
||||||
[app.plugins.utils :refer [get-data-fn]]))
|
[app.plugins.utils :refer [locate-page proxy->page]]
|
||||||
|
[app.util.object :as obj]))
|
||||||
|
|
||||||
(def ^:private
|
(deftype PageProxy [$file $id]
|
||||||
xf-map-shape-proxy
|
|
||||||
(comp
|
|
||||||
(map val)
|
|
||||||
(map shape/data->shape-proxy)))
|
|
||||||
|
|
||||||
(deftype PageProxy [#_:clj-kondo/ignore _data]
|
|
||||||
Object
|
Object
|
||||||
(getShapeById [_ id]
|
(getShapeById
|
||||||
(shape/data->shape-proxy (get (:objects _data) (uuid/uuid id))))
|
[_ shape-id]
|
||||||
|
(let [shape-id (uuid/uuid shape-id)]
|
||||||
|
(shape/shape-proxy $file $id shape-id)))
|
||||||
|
|
||||||
(getRoot [_]
|
(getRoot
|
||||||
(shape/data->shape-proxy (get (:objects _data) uuid/zero)))
|
[_]
|
||||||
|
(shape/shape-proxy $file $id uuid/zero))
|
||||||
|
|
||||||
(findShapes [_]
|
(findShapes
|
||||||
|
[_]
|
||||||
;; Returns a lazy (iterable) of all available shapes
|
;; Returns a lazy (iterable) of all available shapes
|
||||||
(apply array (sequence xf-map-shape-proxy (:objects _data)))))
|
(let [page (locate-page $file $id)]
|
||||||
|
(apply array (sequence (map shape/shape-proxy) (keys (:objects page)))))))
|
||||||
|
|
||||||
(crc/define-properties!
|
(crc/define-properties!
|
||||||
PageProxy
|
PageProxy
|
||||||
{:name js/Symbol.toStringTag
|
{:name js/Symbol.toStringTag
|
||||||
:get (fn [] (str "PageProxy"))})
|
:get (fn [] (str "PageProxy"))})
|
||||||
|
|
||||||
(defn data->page-proxy
|
(defn page-proxy
|
||||||
[data]
|
[file-id id]
|
||||||
|
|
||||||
(crc/add-properties!
|
(crc/add-properties!
|
||||||
(PageProxy. data)
|
(PageProxy. file-id id)
|
||||||
{:name "_data" :enumerable false}
|
{:name "$id" :enumerable false :get (constantly id)}
|
||||||
|
{:name "$file" :enumerable false :get (constantly file-id)}
|
||||||
|
|
||||||
{:name "id"
|
{:name "id"
|
||||||
:get (get-data-fn :id str)}
|
:get #(dm/str (obj/get % "$id"))}
|
||||||
|
|
||||||
{:name "name"
|
{:name "name"
|
||||||
:get (get-data-fn :name)}
|
:get #(-> % proxy->page :name)}
|
||||||
|
|
||||||
{:name "root"
|
{:name "root"
|
||||||
|
:enumerable false
|
||||||
:get #(.getRoot ^js %)}))
|
:get #(.getRoot ^js %)}))
|
||||||
|
|
|
@ -8,364 +8,407 @@
|
||||||
"RPC for plugins runtime."
|
"RPC for plugins runtime."
|
||||||
(:require
|
(:require
|
||||||
[app.common.data :as d]
|
[app.common.data :as d]
|
||||||
[app.common.data.macros :as dm]
|
|
||||||
[app.common.files.helpers :as cfh]
|
[app.common.files.helpers :as cfh]
|
||||||
[app.common.record :as crc]
|
[app.common.record :as crc]
|
||||||
[app.common.spec :as us]
|
[app.common.spec :as us]
|
||||||
[app.common.text :as txt]
|
[app.common.text :as txt]
|
||||||
[app.common.types.shape :as cts]
|
[app.common.types.shape :as cts]
|
||||||
[app.common.uuid :as uuid]
|
[app.common.types.shape.layout :as ctl]
|
||||||
[app.main.data.workspace :as udw]
|
[app.main.data.workspace :as udw]
|
||||||
[app.main.data.workspace.changes :as dwc]
|
[app.main.data.workspace.changes :as dwc]
|
||||||
[app.main.data.workspace.selection :as dws]
|
[app.main.data.workspace.selection :as dws]
|
||||||
[app.main.data.workspace.shape-layout :as dwsl]
|
[app.main.data.workspace.shape-layout :as dwsl]
|
||||||
[app.main.data.workspace.shapes :as dwsh]
|
[app.main.data.workspace.shapes :as dwsh]
|
||||||
[app.main.store :as st]
|
[app.main.store :as st]
|
||||||
|
[app.plugins.flex :as flex]
|
||||||
[app.plugins.grid :as grid]
|
[app.plugins.grid :as grid]
|
||||||
[app.plugins.utils :as utils :refer [get-data get-data-fn get-state]]
|
[app.plugins.utils :as utils :refer [locate-objects locate-shape proxy->shape array-to-js]]
|
||||||
[app.util.object :as obj]))
|
[app.util.object :as obj]))
|
||||||
|
|
||||||
(declare data->shape-proxy)
|
(declare shape-proxy)
|
||||||
|
|
||||||
(defn- array-to-js
|
(deftype ShapeProxy [$file $page $id]
|
||||||
[value]
|
|
||||||
(.freeze
|
|
||||||
js/Object
|
|
||||||
(apply array (->> value (map utils/to-js)))))
|
|
||||||
|
|
||||||
(defn- locate-shape
|
|
||||||
[shape-id]
|
|
||||||
(let [page-id (:current-page-id @st/state)]
|
|
||||||
(dm/get-in @st/state [:workspace-data :pages-index page-id :objects shape-id])))
|
|
||||||
|
|
||||||
(deftype ShapeProxy [#_:clj-kondo/ignore _data]
|
|
||||||
Object
|
Object
|
||||||
(resize
|
(resize
|
||||||
[self width height]
|
[_ width height]
|
||||||
(let [id (get-data self :id)]
|
(st/emit! (udw/update-dimensions [$id] :width width)
|
||||||
(st/emit! (udw/update-dimensions [id] :width width)
|
(udw/update-dimensions [$id] :height height)))
|
||||||
(udw/update-dimensions [id] :height height))))
|
|
||||||
|
|
||||||
(clone [self]
|
(clone
|
||||||
(let [id (get-data self :id)
|
[_]
|
||||||
page-id (:current-page-id @st/state)
|
(let [ret-v (atom nil)]
|
||||||
ret-v (atom nil)]
|
(st/emit! (dws/duplicate-shapes #{$id} :change-selection? false :return-ref ret-v))
|
||||||
(st/emit! (dws/duplicate-shapes #{id} :change-selection? false :return-ref ret-v))
|
(shape-proxy (deref ret-v))))
|
||||||
(let [new-id (deref ret-v)
|
|
||||||
shape (dm/get-in @st/state [:workspace-data :pages-index page-id :objects new-id])]
|
|
||||||
(data->shape-proxy shape))))
|
|
||||||
|
|
||||||
(remove [self]
|
(remove
|
||||||
(let [id (get-data self :id)]
|
[_]
|
||||||
(st/emit! (dwsh/delete-shapes #{id}))))
|
(st/emit! (dwsh/delete-shapes #{$id})))
|
||||||
|
|
||||||
;; Only for frames + groups + booleans
|
;; Only for frames + groups + booleans
|
||||||
(getChildren
|
(getChildren
|
||||||
[self]
|
[_]
|
||||||
(apply array (->> (get-state self :shapes)
|
(apply array (->> (locate-shape $file $page $id)
|
||||||
(map locate-shape)
|
:shapes
|
||||||
(map data->shape-proxy))))
|
(map #(shape-proxy $file $page %)))))
|
||||||
|
|
||||||
(appendChild [self child]
|
(appendChild
|
||||||
(let [parent-id (get-data self :id)
|
[_ child]
|
||||||
child-id (uuid/uuid (obj/get child "id"))]
|
(let [child-id (obj/get child "$id")]
|
||||||
(st/emit! (udw/relocate-shapes #{child-id} parent-id 0))))
|
(st/emit! (udw/relocate-shapes #{child-id} $id 0))))
|
||||||
|
|
||||||
(insertChild [self index child]
|
(insertChild
|
||||||
(let [parent-id (get-data self :id)
|
[_ index child]
|
||||||
child-id (uuid/uuid (obj/get child "id"))]
|
(let [child-id (obj/get child "$id")]
|
||||||
(st/emit! (udw/relocate-shapes #{child-id} parent-id index))))
|
(st/emit! (udw/relocate-shapes #{child-id} $id index))))
|
||||||
|
|
||||||
;; Only for frames
|
;; Only for frames
|
||||||
(addFlexLayout [self]
|
(addFlexLayout
|
||||||
(let [id (get-data self :id)]
|
[_]
|
||||||
(st/emit! (dwsl/create-layout-from-id id :flex :from-frame? true :calculate-params? false))))
|
(st/emit! (dwsl/create-layout-from-id $id :flex :from-frame? true :calculate-params? false))
|
||||||
|
(grid/grid-layout-proxy $file $page $id))
|
||||||
|
|
||||||
(addGridLayout [self]
|
(addGridLayout
|
||||||
(let [id (get-data self :id)]
|
[_]
|
||||||
(st/emit! (dwsl/create-layout-from-id id :grid :from-frame? true :calculate-params? false))
|
(st/emit! (dwsl/create-layout-from-id $id :grid :from-frame? true :calculate-params? false))
|
||||||
(grid/grid-layout-proxy (obj/get self "_data")))))
|
(grid/grid-layout-proxy $file $page $id)))
|
||||||
|
|
||||||
(crc/define-properties!
|
(crc/define-properties!
|
||||||
ShapeProxy
|
ShapeProxy
|
||||||
{:name js/Symbol.toStringTag
|
{:name js/Symbol.toStringTag
|
||||||
:get (fn [] (str "ShapeProxy"))})
|
:get (fn [] (str "ShapeProxy"))})
|
||||||
|
|
||||||
(defn data->shape-proxy
|
(defn shape-proxy
|
||||||
[data]
|
([id]
|
||||||
|
(shape-proxy (:current-file-id @st/state) (:current-page-id @st/state) id))
|
||||||
|
|
||||||
(-> (ShapeProxy. data)
|
([page-id id]
|
||||||
(crc/add-properties!
|
(shape-proxy (:current-file-id @st/state) page-id id))
|
||||||
{:name "_data"
|
|
||||||
:enumerable false}
|
|
||||||
|
|
||||||
{:name "id"
|
([file-id page-id id]
|
||||||
:get (get-data-fn :id str)}
|
(assert (uuid? file-id))
|
||||||
|
(assert (uuid? page-id))
|
||||||
|
(assert (uuid? id))
|
||||||
|
|
||||||
{:name "type"
|
(let [data (locate-shape file-id page-id id)]
|
||||||
:get (get-data-fn :type name)}
|
(-> (ShapeProxy. file-id page-id id)
|
||||||
|
(crc/add-properties!
|
||||||
|
{:name "$id" :enumerable false :get (constantly id)}
|
||||||
|
{:name "$file" :enumerable false :get (constantly file-id)}
|
||||||
|
{:name "$page" :enumerable false :get (constantly page-id)}
|
||||||
|
|
||||||
{:name "name"
|
{:name "id"
|
||||||
:get #(get-state % :name)
|
:get #(-> % proxy->shape :id str)}
|
||||||
:set (fn [self value]
|
|
||||||
(let [id (get-data self :id)]
|
|
||||||
(st/emit! (dwc/update-shapes [id] #(assoc % :name value)))))}
|
|
||||||
|
|
||||||
{:name "blocked"
|
{:name "type"
|
||||||
:get #(get-state % :blocked boolean)
|
:get #(-> % proxy->shape :type name)}
|
||||||
:set (fn [self value]
|
|
||||||
(let [id (get-data self :id)]
|
|
||||||
(st/emit! (dwc/update-shapes [id] #(assoc % :blocked value)))))}
|
|
||||||
|
|
||||||
{:name "hidden"
|
{:name "name"
|
||||||
:get #(get-state % :hidden boolean)
|
:get #(-> % proxy->shape :name)
|
||||||
:set (fn [self value]
|
:set (fn [self value]
|
||||||
(let [id (get-data self :id)]
|
(let [id (obj/get self "$id")]
|
||||||
(st/emit! (dwc/update-shapes [id] #(assoc % :hidden value)))))}
|
(st/emit! (dwc/update-shapes [id] #(assoc % :name value)))))}
|
||||||
|
|
||||||
{:name "proportionLock"
|
{:name "blocked"
|
||||||
:get #(get-state % :proportion-lock boolean)
|
:get #(-> % proxy->shape :blocked boolean)
|
||||||
:set (fn [self value]
|
:set (fn [self value]
|
||||||
(let [id (get-data self :id)]
|
(let [id (obj/get self "$id")]
|
||||||
(st/emit! (dwc/update-shapes [id] #(assoc % :proportion-lock value)))))}
|
(st/emit! (dwc/update-shapes [id] #(assoc % :blocked value)))))}
|
||||||
|
|
||||||
{:name "constraintsHorizontal"
|
{:name "hidden"
|
||||||
:get #(get-state % :constraints-h d/name)
|
:get #(-> % proxy->shape :hidden boolean)
|
||||||
:set (fn [self value]
|
:set (fn [self value]
|
||||||
(let [id (get-data self :id)
|
(let [id (obj/get self "$id")]
|
||||||
value (keyword value)]
|
(st/emit! (dwc/update-shapes [id] #(assoc % :hidden value)))))}
|
||||||
(when (contains? cts/horizontal-constraint-types value)
|
|
||||||
(st/emit! (dwc/update-shapes [id] #(assoc % :constraints-h value))))))}
|
|
||||||
|
|
||||||
{:name "constraintsVertical"
|
{:name "proportionLock"
|
||||||
:get #(get-state % :constraints-v d/name)
|
:get #(-> % proxy->shape :proportion-lock boolean)
|
||||||
:set (fn [self value]
|
:set (fn [self value]
|
||||||
(let [id (get-data self :id)
|
(let [id (obj/get self "$id")]
|
||||||
value (keyword value)]
|
(st/emit! (dwc/update-shapes [id] #(assoc % :proportion-lock value)))))}
|
||||||
(when (contains? cts/vertical-constraint-types value)
|
|
||||||
(st/emit! (dwc/update-shapes [id] #(assoc % :constraints-v value))))))}
|
|
||||||
|
|
||||||
{:name "borderRadius"
|
{:name "constraintsHorizontal"
|
||||||
:get #(get-state % :rx)
|
:get #(-> % proxy->shape :constraints-h d/name)
|
||||||
:set (fn [self value]
|
:set (fn [self value]
|
||||||
(let [id (get-data self :id)]
|
(let [id (obj/get self "$id")
|
||||||
(when (us/safe-int? value)
|
value (keyword value)]
|
||||||
(st/emit! (dwc/update-shapes [id] #(assoc % :rx value :ry value))))))}
|
(when (contains? cts/horizontal-constraint-types value)
|
||||||
|
(st/emit! (dwc/update-shapes [id] #(assoc % :constraints-h value))))))}
|
||||||
|
|
||||||
{:name "borderRadiusTopLeft"
|
{:name "constraintsVertical"
|
||||||
:get #(get-state % :r1)
|
:get #(-> % proxy->shape :constraints-v d/name)
|
||||||
:set (fn [self value]
|
:set (fn [self value]
|
||||||
(let [id (get-data self :id)]
|
(let [id (obj/get self "$id")
|
||||||
(when (us/safe-int? value)
|
value (keyword value)]
|
||||||
(st/emit! (dwc/update-shapes [id] #(assoc % :r1 value))))))}
|
(when (contains? cts/vertical-constraint-types value)
|
||||||
|
(st/emit! (dwc/update-shapes [id] #(assoc % :constraints-v value))))))}
|
||||||
|
|
||||||
{:name "borderRadiusTopRight"
|
{:name "borderRadius"
|
||||||
:get #(get-state % :r2)
|
:get #(-> % proxy->shape :rx)
|
||||||
:set (fn [self value]
|
:set (fn [self value]
|
||||||
(let [id (get-data self :id)]
|
(let [id (obj/get self "$id")]
|
||||||
(when (us/safe-int? value)
|
(when (us/safe-int? value)
|
||||||
(st/emit! (dwc/update-shapes [id] #(assoc % :r2 value))))))}
|
(st/emit! (dwc/update-shapes [id] #(assoc % :rx value :ry value))))))}
|
||||||
|
|
||||||
{:name "borderRadiusBottomRight"
|
{:name "borderRadiusTopLeft"
|
||||||
:get #(get-state % :r3)
|
:get #(-> % proxy->shape :r1)
|
||||||
:set (fn [self value]
|
:set (fn [self value]
|
||||||
(let [id (get-data self :id)]
|
(let [id (obj/get self "$id")]
|
||||||
(when (us/safe-int? value)
|
(when (us/safe-int? value)
|
||||||
(st/emit! (dwc/update-shapes [id] #(assoc % :r3 value))))))}
|
(st/emit! (dwc/update-shapes [id] #(assoc % :r1 value))))))}
|
||||||
|
|
||||||
{:name "borderRadiusBottomLeft"
|
{:name "borderRadiusTopRight"
|
||||||
:get #(get-state % :r4)
|
:get #(-> % proxy->shape :r2)
|
||||||
:set (fn [self value]
|
:set (fn [self value]
|
||||||
(let [id (get-data self :id)]
|
(let [id (obj/get self "$id")]
|
||||||
(when (us/safe-int? value)
|
(when (us/safe-int? value)
|
||||||
(st/emit! (dwc/update-shapes [id] #(assoc % :r4 value))))))}
|
(st/emit! (dwc/update-shapes [id] #(assoc % :r2 value))))))}
|
||||||
|
|
||||||
{:name "opacity"
|
{:name "borderRadiusBottomRight"
|
||||||
:get #(get-state % :opacity)
|
:get #(-> % proxy->shape :r3)
|
||||||
:set (fn [self value]
|
:set (fn [self value]
|
||||||
(let [id (get-data self :id)]
|
(let [id (obj/get self "$id")]
|
||||||
(when (and (us/safe-number? value) (>= value 0) (<= value 1))
|
(when (us/safe-int? value)
|
||||||
(st/emit! (dwc/update-shapes [id] #(assoc % :opacity value))))))}
|
(st/emit! (dwc/update-shapes [id] #(assoc % :r3 value))))))}
|
||||||
|
|
||||||
{:name "blendMode"
|
{:name "borderRadiusBottomLeft"
|
||||||
:get #(get-state % :blend-mode d/name)
|
:get #(-> % proxy->shape :r4)
|
||||||
:set (fn [self value]
|
:set (fn [self value]
|
||||||
(let [id (get-data self :id)
|
(let [id (obj/get self "$id")]
|
||||||
value (keyword value)]
|
(when (us/safe-int? value)
|
||||||
(when (contains? cts/blend-modes value)
|
(st/emit! (dwc/update-shapes [id] #(assoc % :r4 value))))))}
|
||||||
(st/emit! (dwc/update-shapes [id] #(assoc % :blend-mode value))))))}
|
|
||||||
|
|
||||||
{:name "shadows"
|
{:name "opacity"
|
||||||
:get #(get-state % :shadow array-to-js)
|
:get #(-> % proxy->shape :opacity)
|
||||||
:set (fn [self value]
|
:set (fn [self value]
|
||||||
(let [id (get-data self :id)
|
(let [id (obj/get self "$id")]
|
||||||
value (mapv #(utils/from-js %) value)]
|
(when (and (us/safe-number? value) (>= value 0) (<= value 1))
|
||||||
(st/emit! (dwc/update-shapes [id] #(assoc % :shadows value)))))}
|
(st/emit! (dwc/update-shapes [id] #(assoc % :opacity value))))))}
|
||||||
|
|
||||||
{:name "blur"
|
{:name "blendMode"
|
||||||
:get #(get-state % :blur utils/to-js)
|
:get #(-> % proxy->shape :blend-mode (d/nilv :normal) d/name)
|
||||||
:set (fn [self value]
|
:set (fn [self value]
|
||||||
(let [id (get-data self :id)
|
(let [id (obj/get self "$id")
|
||||||
value (utils/from-js value)]
|
value (keyword value)]
|
||||||
(st/emit! (dwc/update-shapes [id] #(assoc % :blur value)))))}
|
(when (contains? cts/blend-modes value)
|
||||||
|
(st/emit! (dwc/update-shapes [id] #(assoc % :blend-mode value))))))}
|
||||||
|
|
||||||
{:name "exports"
|
{:name "shadows"
|
||||||
:get #(get-state % :exports array-to-js)
|
:get #(-> % proxy->shape :shadow array-to-js)
|
||||||
:set (fn [self value]
|
:set (fn [self value]
|
||||||
(let [id (get-data self :id)
|
(let [id (obj/get self "$id")
|
||||||
value (mapv #(utils/from-js %) value)]
|
value (mapv #(utils/from-js %) value)]
|
||||||
(st/emit! (dwc/update-shapes [id] #(assoc % :exports value)))))}
|
(st/emit! (dwc/update-shapes [id] #(assoc % :shadows value)))))}
|
||||||
|
|
||||||
;; Geometry properties
|
{:name "blur"
|
||||||
{:name "x"
|
:get #(-> % proxy->shape :blur utils/to-js)
|
||||||
:get #(get-state % :x)
|
:set (fn [self value]
|
||||||
:set
|
(let [id (obj/get self "$id")
|
||||||
(fn [self value]
|
value (utils/from-js value)]
|
||||||
(let [id (get-data self :id)]
|
(st/emit! (dwc/update-shapes [id] #(assoc % :blur value)))))}
|
||||||
(st/emit! (udw/update-position id {:x value}))))}
|
|
||||||
|
|
||||||
{:name "y"
|
{:name "exports"
|
||||||
:get #(get-state % :y)
|
:get #(-> % proxy->shape :exports array-to-js)
|
||||||
:set
|
:set (fn [self value]
|
||||||
(fn [self value]
|
(let [id (obj/get self "$id")
|
||||||
(let [id (get-data self :id)]
|
value (mapv #(utils/from-js %) value)]
|
||||||
(st/emit! (udw/update-position id {:y value}))))}
|
(st/emit! (dwc/update-shapes [id] #(assoc % :exports value)))))}
|
||||||
|
|
||||||
{:name "parentX"
|
;; Geometry properties
|
||||||
:get (fn [self]
|
{:name "x"
|
||||||
(let [page-id (:current-page-id @st/state)
|
:get #(-> % proxy->shape :x)
|
||||||
parent-id (get-state self :parent-id)
|
:set
|
||||||
parent-x (dm/get-in @st/state [:workspace-data :pages-index page-id :objects parent-id :x])]
|
(fn [self value]
|
||||||
(- (get-state self :x) parent-x)))
|
(let [id (obj/get self "$id")]
|
||||||
:set
|
(st/emit! (udw/update-position id {:x value}))))}
|
||||||
(fn [self value]
|
|
||||||
(let [page-id (:current-page-id @st/state)
|
|
||||||
id (get-data self :id)
|
|
||||||
parent-id (get-state self :parent-id)
|
|
||||||
parent-x (dm/get-in @st/state [:workspace-data :pages-index page-id :objects parent-id :x])]
|
|
||||||
(st/emit! (udw/update-position id {:x (+ parent-x value)}))))}
|
|
||||||
|
|
||||||
{:name "parentY"
|
{:name "y"
|
||||||
:get (fn [self]
|
:get #(-> % proxy->shape :y)
|
||||||
(let [page-id (:current-page-id @st/state)
|
:set
|
||||||
parent-id (get-state self :parent-id)
|
(fn [self value]
|
||||||
parent-y (dm/get-in @st/state [:workspace-data :pages-index page-id :objects parent-id :y])]
|
(let [id (obj/get self "$id")]
|
||||||
(- (get-state self :y) parent-y)))
|
(st/emit! (udw/update-position id {:y value}))))}
|
||||||
:set
|
|
||||||
(fn [self value]
|
|
||||||
(let [page-id (:current-page-id @st/state)
|
|
||||||
id (get-data self :id)
|
|
||||||
parent-id (get-state self :parent-id)
|
|
||||||
parent-y (dm/get-in @st/state [:workspace-data :pages-index page-id :objects parent-id :y])]
|
|
||||||
(st/emit! (udw/update-position id {:y (+ parent-y value)}))))}
|
|
||||||
|
|
||||||
{:name "frameX"
|
{:name "parentX"
|
||||||
:get (fn [self]
|
:get (fn [self]
|
||||||
(let [page-id (:current-page-id @st/state)
|
(let [shape (proxy->shape self)
|
||||||
frame-id (get-state self :frame-id)
|
parent-id (:parent-id shape)
|
||||||
frame-x (dm/get-in @st/state [:workspace-data :pages-index page-id :objects frame-id :x])]
|
parent (locate-shape (obj/get self "$file") (obj/get self "$page") parent-id)]
|
||||||
(- (get-state self :x) frame-x)))
|
(- (:x shape) (:x parent))))
|
||||||
:set
|
:set
|
||||||
(fn [self value]
|
(fn [self value]
|
||||||
(let [page-id (:current-page-id @st/state)
|
(let [id (obj/get self "$id")
|
||||||
id (get-data self :id)
|
parent-id (-> self proxy->shape :parent-id)
|
||||||
frame-id (get-state self :frame-id)
|
parent (locate-shape (obj/get self "$file") (obj/get self "$page") parent-id)
|
||||||
frame-x (dm/get-in @st/state [:workspace-data :pages-index page-id :objects frame-id :x])]
|
parent-x (:x parent)]
|
||||||
(st/emit! (udw/update-position id {:x (+ frame-x value)}))))}
|
(st/emit! (udw/update-position id {:x (+ parent-x value)}))))}
|
||||||
|
|
||||||
{:name "frameY"
|
{:name "parentY"
|
||||||
:get (fn [self]
|
:get (fn [self]
|
||||||
(let [page-id (:current-page-id @st/state)
|
(let [shape (proxy->shape self)
|
||||||
frame-id (get-state self :frame-id)
|
parent-id (:parent-id shape)
|
||||||
frame-y (dm/get-in @st/state [:workspace-data :pages-index page-id :objects frame-id :y])]
|
parent (locate-shape (obj/get self "$file") (obj/get self "$page") parent-id)
|
||||||
(- (get-state self :y) frame-y)))
|
parent-y (:y parent)]
|
||||||
:set
|
(- (:y shape) parent-y)))
|
||||||
(fn [self value]
|
:set
|
||||||
(let [page-id (:current-page-id @st/state)
|
(fn [self value]
|
||||||
id (get-data self :id)
|
(let [id (obj/get self "$id")
|
||||||
frame-id (get-state self :frame-id)
|
parent-id (-> self proxy->shape :parent-id)
|
||||||
frame-y (dm/get-in @st/state [:workspace-data :pages-index page-id :objects frame-id :y])]
|
parent (locate-shape (obj/get self "$file") (obj/get self "$page") parent-id)
|
||||||
(st/emit! (udw/update-position id {:y (+ frame-y value)}))))}
|
parent-y (:y parent)]
|
||||||
|
(st/emit! (udw/update-position id {:y (+ parent-y value)}))))}
|
||||||
|
|
||||||
{:name "width"
|
{:name "frameX"
|
||||||
:get #(get-state % :width)}
|
:get (fn [self]
|
||||||
|
(let [shape (proxy->shape self)
|
||||||
|
frame-id (:parent-id shape)
|
||||||
|
frame (locate-shape (obj/get self "$file") (obj/get self "$page") frame-id)
|
||||||
|
frame-x (:x frame)]
|
||||||
|
(- (:x shape) frame-x)))
|
||||||
|
:set
|
||||||
|
(fn [self value]
|
||||||
|
(let [id (obj/get self "$id")
|
||||||
|
frame-id (-> self proxy->shape :frame-id)
|
||||||
|
frame (locate-shape (obj/get self "$file") (obj/get self "$page") frame-id)
|
||||||
|
frame-x (:x frame)]
|
||||||
|
(st/emit! (udw/update-position id {:x (+ frame-x value)}))))}
|
||||||
|
|
||||||
{:name "height"
|
{:name "frameY"
|
||||||
:get #(get-state % :height)}
|
:get (fn [self]
|
||||||
|
(let [shape (proxy->shape self)
|
||||||
|
frame-id (:parent-id shape)
|
||||||
|
frame (locate-shape (obj/get self "$file") (obj/get self "$page") frame-id)
|
||||||
|
frame-y (:y frame)]
|
||||||
|
(- (:y shape) frame-y)))
|
||||||
|
:set
|
||||||
|
(fn [self value]
|
||||||
|
(let [id (obj/get self "$id")
|
||||||
|
frame-id (-> self proxy->shape :frame-id)
|
||||||
|
frame (locate-shape (obj/get self "$file") (obj/get self "$page") frame-id)
|
||||||
|
frame-y (:y frame)]
|
||||||
|
(st/emit! (udw/update-position id {:y (+ frame-y value)}))))}
|
||||||
|
|
||||||
{:name "flipX"
|
{:name "width"
|
||||||
:get #(get-state % :flip-x)}
|
:get #(-> % proxy->shape :width)}
|
||||||
|
|
||||||
{:name "flipY"
|
{:name "height"
|
||||||
:get #(get-state % :flip-y)}
|
:get #(-> % proxy->shape :height)}
|
||||||
|
|
||||||
;; Strokes and fills
|
{:name "flipX"
|
||||||
{:name "fills"
|
:get #(-> % proxy->shape :flip-x)}
|
||||||
:get #(get-state % :fills array-to-js)
|
|
||||||
:set (fn [self value]
|
|
||||||
(let [id (get-data self :id)
|
|
||||||
value (mapv #(utils/from-js %) value)]
|
|
||||||
(st/emit! (dwc/update-shapes [id] #(assoc % :fills value)))))}
|
|
||||||
|
|
||||||
{:name "strokes"
|
{:name "flipY"
|
||||||
:get #(get-state % :strokes array-to-js)
|
:get #(-> % proxy->shape :flip-y)}
|
||||||
:set (fn [self value]
|
|
||||||
(let [id (get-data self :id)
|
|
||||||
value (mapv #(utils/from-js %) value)]
|
|
||||||
(st/emit! (dwc/update-shapes [id] #(assoc % :strokes value)))))})
|
|
||||||
|
|
||||||
(cond-> (or (cfh/frame-shape? data) (cfh/group-shape? data) (cfh/svg-raw-shape? data) (cfh/bool-shape? data))
|
;; Strokes and fills
|
||||||
(crc/add-properties!
|
{:name "fills"
|
||||||
{:name "children"
|
:get #(-> % proxy->shape :fills array-to-js)
|
||||||
:get #(.getChildren ^js %)}))
|
:set (fn [self value]
|
||||||
|
(let [id (obj/get self "$id")
|
||||||
|
value (mapv #(utils/from-js %) value)]
|
||||||
|
(st/emit! (dwc/update-shapes [id] #(assoc % :fills value)))))}
|
||||||
|
|
||||||
(cond-> (not (or (cfh/frame-shape? data) (cfh/group-shape? data) (cfh/svg-raw-shape? data) (cfh/bool-shape? data)))
|
{:name "strokes"
|
||||||
(-> (obj/unset! "appendChild")
|
:get #(-> % proxy->shape :strokes array-to-js)
|
||||||
(obj/unset! "insertChild")
|
:set (fn [self value]
|
||||||
(obj/unset! "getChildren")))
|
(let [id (obj/get self "$id")
|
||||||
|
value (mapv #(utils/from-js %) value)]
|
||||||
|
(st/emit! (dwc/update-shapes [id] #(assoc % :strokes value)))))}
|
||||||
|
|
||||||
(cond-> (cfh/frame-shape? data)
|
{:name "layoutChild"
|
||||||
(-> (crc/add-properties!
|
:get
|
||||||
{:name "grid"
|
(fn [self]
|
||||||
:get
|
(let [file-id (obj/get self "$file")
|
||||||
(fn [self]
|
page-id (obj/get self "$page")
|
||||||
(let [layout (get-state self :layout)]
|
id (obj/get self "$id")
|
||||||
(when (= :grid layout)
|
objects (locate-objects file-id page-id)]
|
||||||
(grid/grid-layout-proxy data))))}
|
(when (ctl/any-layout-immediate-child-id? objects id)
|
||||||
|
(flex/layout-child-proxy file-id page-id id))))}
|
||||||
|
|
||||||
{:name "guides"
|
{:name "layoutCell"
|
||||||
:get #(get-state % :grids array-to-js)
|
:get
|
||||||
:set (fn [self value]
|
(fn [self]
|
||||||
(let [id (get-data self :id)
|
(let [file-id (obj/get self "$file")
|
||||||
value (mapv #(utils/from-js %) value)]
|
page-id (obj/get self "$page")
|
||||||
(st/emit! (dwc/update-shapes [id] #(assoc % :grids value)))))})
|
id (obj/get self "$id")
|
||||||
|
objects (locate-objects file-id page-id)]
|
||||||
|
(when (ctl/grid-layout-immediate-child-id? objects id)
|
||||||
|
(grid/layout-cell-proxy file-id page-id id))))})
|
||||||
|
|
||||||
;; TODO: Flex properties
|
(cond-> (or (cfh/frame-shape? data) (cfh/group-shape? data) (cfh/svg-raw-shape? data) (cfh/bool-shape? data))
|
||||||
#_(crc/add-properties!
|
(crc/add-properties!
|
||||||
{:name "flex"
|
{:name "children"
|
||||||
:get
|
:enumerable false
|
||||||
(fn [self]
|
:get #(.getChildren ^js %)}))
|
||||||
(let [layout (get-state self :layout)]
|
|
||||||
(when (= :flex layout)
|
|
||||||
(flex-layout-proxy data))))})))
|
|
||||||
|
|
||||||
(cond-> (not (cfh/frame-shape? data))
|
(cond-> (not (or (cfh/frame-shape? data) (cfh/group-shape? data) (cfh/svg-raw-shape? data) (cfh/bool-shape? data)))
|
||||||
(-> (obj/unset! "addGridLayout")
|
(-> (obj/unset! "appendChild")
|
||||||
(obj/unset! "addFlexLayout")))
|
(obj/unset! "insertChild")
|
||||||
|
(obj/unset! "getChildren")))
|
||||||
|
|
||||||
(cond-> (cfh/text-shape? data)
|
(cond-> (cfh/frame-shape? data)
|
||||||
(-> (crc/add-properties!
|
(-> (crc/add-properties!
|
||||||
{:name "characters"
|
{:name "grid"
|
||||||
:get #(get-state % :content txt/content->text)
|
:get
|
||||||
:set (fn [self value]
|
(fn [self]
|
||||||
(let [id (get-data self :id)]
|
(let [layout (-> self proxy->shape :layout)
|
||||||
(st/emit! (dwc/update-shapes [id] #(txt/change-text % value)))))})
|
file-id (obj/get self "$file")
|
||||||
|
page-id (obj/get self "$page")
|
||||||
|
id (obj/get self "$id")]
|
||||||
|
(when (= :grid layout)
|
||||||
|
(grid/grid-layout-proxy file-id page-id id))))}
|
||||||
|
|
||||||
(crc/add-properties!
|
{:name "flex"
|
||||||
{:name "growType"
|
:get
|
||||||
:get #(get-state % :grow-type d/name)
|
(fn [self]
|
||||||
:set (fn [self value]
|
(let [layout (-> self proxy->shape :layout)
|
||||||
(let [id (get-data self :id)
|
file-id (obj/get self "$file")
|
||||||
value (keyword value)]
|
page-id (obj/get self "$page")
|
||||||
(when (contains? #{:auto-width :auto-height :fixed} value)
|
id (obj/get self "$id")]
|
||||||
(st/emit! (dwc/update-shapes [id] #(assoc % :grow-type value))))))})))))
|
(when (= :flex layout)
|
||||||
|
(flex/flex-layout-proxy file-id page-id id))))}
|
||||||
|
|
||||||
|
{:name "guides"
|
||||||
|
:get #(-> % proxy->shape :grids array-to-js)
|
||||||
|
:set (fn [self value]
|
||||||
|
(let [id (obj/get self "$id")
|
||||||
|
value (mapv #(utils/from-js %) value)]
|
||||||
|
(st/emit! (dwc/update-shapes [id] #(assoc % :grids value)))))}
|
||||||
|
|
||||||
|
{:name "horizontalSizing"
|
||||||
|
:get #(-> % proxy->shape :layout-item-h-sizing (d/nilv :fix) d/name)
|
||||||
|
:set
|
||||||
|
(fn [self value]
|
||||||
|
(let [id (obj/get self "$id")
|
||||||
|
value (keyword value)]
|
||||||
|
(when (contains? #{:fix :auto} value)
|
||||||
|
(st/emit! (dwsl/update-layout #{id} {:layout-item-h-sizing value})))))}
|
||||||
|
|
||||||
|
{:name "verticalSizing"
|
||||||
|
:get #(-> % proxy->shape :layout-item-v-sizing (d/nilv :fix) d/name)
|
||||||
|
:set
|
||||||
|
(fn [self value]
|
||||||
|
(let [id (obj/get self "$id")
|
||||||
|
value (keyword value)]
|
||||||
|
(when (contains? #{:fix :auto} value)
|
||||||
|
(st/emit! (dwsl/update-layout #{id} {:layout-item-v-sizing value})))))})))
|
||||||
|
|
||||||
|
(cond-> (not (cfh/frame-shape? data))
|
||||||
|
(-> (obj/unset! "addGridLayout")
|
||||||
|
(obj/unset! "addFlexLayout")))
|
||||||
|
|
||||||
|
(cond-> (cfh/text-shape? data)
|
||||||
|
(-> (crc/add-properties!
|
||||||
|
{:name "characters"
|
||||||
|
:get #(-> % proxy->shape :content txt/content->text)
|
||||||
|
:set (fn [self value]
|
||||||
|
(let [id (obj/get self "$id")]
|
||||||
|
(st/emit! (dwc/update-shapes [id] #(txt/change-text % value)))))})
|
||||||
|
|
||||||
|
(crc/add-properties!
|
||||||
|
{:name "growType"
|
||||||
|
:get #(-> % proxy->shape :grow-type d/name)
|
||||||
|
:set (fn [self value]
|
||||||
|
(let [id (obj/get self "$id")
|
||||||
|
value (keyword value)]
|
||||||
|
(when (contains? #{:auto-width :auto-height :fixed} value)
|
||||||
|
(st/emit! (dwc/update-shapes [id] #(assoc % :grow-type value))))))})))))))
|
||||||
|
|
|
@ -16,6 +16,79 @@
|
||||||
[cuerdas.core :as str]
|
[cuerdas.core :as str]
|
||||||
[promesa.core :as p]))
|
[promesa.core :as p]))
|
||||||
|
|
||||||
|
(defn locate-file
|
||||||
|
[id]
|
||||||
|
(assert (uuid? id) "File not valid uuid")
|
||||||
|
(if (= id (:current-file-id @st/state))
|
||||||
|
(-> (:workspace-file @st/state)
|
||||||
|
(assoc :data (:workspace-data @st/state)))
|
||||||
|
(dm/get-in @st/state [:workspace-libraries id])))
|
||||||
|
|
||||||
|
(defn locate-page
|
||||||
|
[file-id id]
|
||||||
|
(assert (uuid? id) "Page not valid uuid")
|
||||||
|
(dm/get-in (locate-file file-id) [:data :pages-index id]))
|
||||||
|
|
||||||
|
(defn locate-objects
|
||||||
|
[file-id page-id]
|
||||||
|
(:objects (locate-page file-id page-id)))
|
||||||
|
|
||||||
|
(defn locate-shape
|
||||||
|
[file-id page-id id]
|
||||||
|
(assert (uuid? id) "Shape not valid uuid")
|
||||||
|
(dm/get-in (locate-page file-id page-id) [:objects id]))
|
||||||
|
|
||||||
|
(defn locate-library-color
|
||||||
|
[file-id id]
|
||||||
|
(assert (uuid? id) "Color not valid uuid")
|
||||||
|
(dm/get-in (locate-file file-id) [:data :colors id]))
|
||||||
|
|
||||||
|
(defn locate-library-typography
|
||||||
|
[file-id id]
|
||||||
|
(assert (uuid? id) "Typography not valid uuid")
|
||||||
|
(dm/get-in (locate-file file-id) [:data :typographies id]))
|
||||||
|
|
||||||
|
(defn locate-library-component
|
||||||
|
[file-id id]
|
||||||
|
(assert (uuid? id) "Component not valid uuid")
|
||||||
|
(dm/get-in (locate-file file-id) [:data :components id]))
|
||||||
|
|
||||||
|
(defn proxy->file
|
||||||
|
[proxy]
|
||||||
|
(let [id (obj/get proxy "$id")]
|
||||||
|
(locate-file id)))
|
||||||
|
|
||||||
|
(defn proxy->page
|
||||||
|
[proxy]
|
||||||
|
(let [file-id (obj/get proxy "$file")
|
||||||
|
id (obj/get proxy "$id")]
|
||||||
|
(locate-page file-id id)))
|
||||||
|
|
||||||
|
(defn proxy->shape
|
||||||
|
[proxy]
|
||||||
|
(let [file-id (obj/get proxy "$file")
|
||||||
|
page-id (obj/get proxy "$page")
|
||||||
|
id (obj/get proxy "$id")]
|
||||||
|
(locate-shape file-id page-id id)))
|
||||||
|
|
||||||
|
(defn proxy->library-color
|
||||||
|
[proxy]
|
||||||
|
(let [file-id (obj/get proxy "$file")
|
||||||
|
id (obj/get proxy "$id")]
|
||||||
|
(locate-library-color file-id id)))
|
||||||
|
|
||||||
|
(defn proxy->library-typography
|
||||||
|
[proxy]
|
||||||
|
(let [file-id (obj/get proxy "$file")
|
||||||
|
id (obj/get proxy "$id")]
|
||||||
|
(locate-library-color file-id id)))
|
||||||
|
|
||||||
|
(defn proxy->library-component
|
||||||
|
[proxy]
|
||||||
|
(let [file-id (obj/get proxy "$file")
|
||||||
|
id (obj/get proxy "$id")]
|
||||||
|
(locate-library-color file-id id)))
|
||||||
|
|
||||||
(defn get-data
|
(defn get-data
|
||||||
([self attr]
|
([self attr]
|
||||||
(-> (obj/get self "_data")
|
(-> (obj/get self "_data")
|
||||||
|
@ -45,37 +118,51 @@
|
||||||
|
|
||||||
(defn from-js
|
(defn from-js
|
||||||
"Converts the object back to js"
|
"Converts the object back to js"
|
||||||
([obj]
|
[obj]
|
||||||
(from-js obj identity))
|
(when (some? obj)
|
||||||
([obj vfn]
|
(let [process-node
|
||||||
(let [ret (js->clj obj {:keyword-fn (fn [k] (str/camel (name k)))})]
|
(fn process-node [node]
|
||||||
(reduce-kv
|
(reduce-kv
|
||||||
(fn [m k v]
|
(fn [m k v]
|
||||||
(let [k (keyword (str/kebab k))
|
(let [k (keyword (str/kebab k))
|
||||||
v (cond (map? v)
|
v (cond (map? v)
|
||||||
(from-js v)
|
(process-node v)
|
||||||
|
|
||||||
(and (string? v) (re-matches us/uuid-rx v))
|
(vector? v)
|
||||||
(uuid/uuid v)
|
(mapv process-node v)
|
||||||
|
|
||||||
:else (vfn k v))]
|
(and (string? v) (re-matches us/uuid-rx v))
|
||||||
(assoc m k v)))
|
(uuid/uuid v)
|
||||||
{}
|
|
||||||
ret))))
|
(= k :type)
|
||||||
|
(keyword v)
|
||||||
|
|
||||||
|
:else v)]
|
||||||
|
(assoc m k v)))
|
||||||
|
{}
|
||||||
|
node))]
|
||||||
|
(process-node (js->clj obj)))))
|
||||||
|
|
||||||
(defn to-js
|
(defn to-js
|
||||||
"Converts to javascript an camelize the keys"
|
"Converts to javascript an camelize the keys"
|
||||||
[obj]
|
[obj]
|
||||||
(let [result
|
(when (some? obj)
|
||||||
(reduce-kv
|
(let [result
|
||||||
(fn [m k v]
|
(reduce-kv
|
||||||
(let [v (cond (object? v) (to-js v)
|
(fn [m k v]
|
||||||
(uuid? v) (dm/str v)
|
(let [v (cond (object? v) (to-js v)
|
||||||
:else v)]
|
(uuid? v) (dm/str v)
|
||||||
(assoc m (str/camel (name k)) v)))
|
:else v)]
|
||||||
{}
|
(assoc m (str/camel (name k)) v)))
|
||||||
obj)]
|
{}
|
||||||
(clj->js result)))
|
obj)]
|
||||||
|
(clj->js result))))
|
||||||
|
|
||||||
|
(defn array-to-js
|
||||||
|
[value]
|
||||||
|
(.freeze
|
||||||
|
js/Object
|
||||||
|
(apply array (->> value (map to-js)))))
|
||||||
|
|
||||||
(defn result-p
|
(defn result-p
|
||||||
"Creates a pair of atom+promise. The promise will be resolved when the atom gets a value.
|
"Creates a pair of atom+promise. The promise will be resolved when the atom gets a value.
|
||||||
|
|
91
package-lock.json
generated
91
package-lock.json
generated
|
@ -1,91 +0,0 @@
|
||||||
{
|
|
||||||
"name": "penpot",
|
|
||||||
"version": "1.20.0",
|
|
||||||
"lockfileVersion": 3,
|
|
||||||
"requires": true,
|
|
||||||
"packages": {
|
|
||||||
"": {
|
|
||||||
"name": "penpot",
|
|
||||||
"version": "1.20.0",
|
|
||||||
"license": "MPL-2.0",
|
|
||||||
"devDependencies": {
|
|
||||||
"@playwright/test": "^1.43.1",
|
|
||||||
"@types/node": "^20.12.7"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@playwright/test": {
|
|
||||||
"version": "1.43.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.43.1.tgz",
|
|
||||||
"integrity": "sha512-HgtQzFgNEEo4TE22K/X7sYTYNqEMMTZmFS8kTq6m8hXj+m1D8TgwgIbumHddJa9h4yl4GkKb8/bgAl2+g7eDgA==",
|
|
||||||
"dev": true,
|
|
||||||
"dependencies": {
|
|
||||||
"playwright": "1.43.1"
|
|
||||||
},
|
|
||||||
"bin": {
|
|
||||||
"playwright": "cli.js"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">=16"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@types/node": {
|
|
||||||
"version": "20.12.7",
|
|
||||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-20.12.7.tgz",
|
|
||||||
"integrity": "sha512-wq0cICSkRLVaf3UGLMGItu/PtdY7oaXaI/RVU+xliKVOtRna3PRY57ZDfztpDL0n11vfymMUnXv8QwYCO7L1wg==",
|
|
||||||
"dev": true,
|
|
||||||
"dependencies": {
|
|
||||||
"undici-types": "~5.26.4"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/fsevents": {
|
|
||||||
"version": "2.3.2",
|
|
||||||
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz",
|
|
||||||
"integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==",
|
|
||||||
"dev": true,
|
|
||||||
"hasInstallScript": true,
|
|
||||||
"optional": true,
|
|
||||||
"os": [
|
|
||||||
"darwin"
|
|
||||||
],
|
|
||||||
"engines": {
|
|
||||||
"node": "^8.16.0 || ^10.6.0 || >=11.0.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/playwright": {
|
|
||||||
"version": "1.43.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/playwright/-/playwright-1.43.1.tgz",
|
|
||||||
"integrity": "sha512-V7SoH0ai2kNt1Md9E3Gwas5B9m8KR2GVvwZnAI6Pg0m3sh7UvgiYhRrhsziCmqMJNouPckiOhk8T+9bSAK0VIA==",
|
|
||||||
"dev": true,
|
|
||||||
"dependencies": {
|
|
||||||
"playwright-core": "1.43.1"
|
|
||||||
},
|
|
||||||
"bin": {
|
|
||||||
"playwright": "cli.js"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">=16"
|
|
||||||
},
|
|
||||||
"optionalDependencies": {
|
|
||||||
"fsevents": "2.3.2"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/playwright-core": {
|
|
||||||
"version": "1.43.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.43.1.tgz",
|
|
||||||
"integrity": "sha512-EI36Mto2Vrx6VF7rm708qSnesVQKbxEWvPrfA1IPY6HgczBplDx7ENtx+K2n4kJ41sLLkuGfmb0ZLSSXlDhqPg==",
|
|
||||||
"dev": true,
|
|
||||||
"bin": {
|
|
||||||
"playwright-core": "cli.js"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">=16"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/undici-types": {
|
|
||||||
"version": "5.26.5",
|
|
||||||
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz",
|
|
||||||
"integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==",
|
|
||||||
"dev": true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
Loading…
Add table
Add a link
Reference in a new issue