diff --git a/editor/core/states/workspace-initial-state.ts b/editor/core/states/workspace-initial-state.ts index 4e2b652a..7ea2bf63 100644 --- a/editor/core/states/workspace-initial-state.ts +++ b/editor/core/states/workspace-initial-state.ts @@ -5,6 +5,7 @@ import { createPendingHistoryState, } from "./history-initial-state"; import { react_presets, vanilla_presets } from "@grida/builder-config-preset"; +import { WorkspacePreferenceStore } from "store/workspace-preference-store"; const _IS_DEV = process.env.NODE_ENV === "development"; @@ -21,15 +22,20 @@ const _ENABLE_PREVIEW_FEATURE_COMPONENTS_SUPPORT = export function createInitialWorkspaceState( editor: EditorSnapshot ): WorkspaceState { + const pref_store = new WorkspacePreferenceStore(); + const saved_pref = pref_store.load(); + const default_pref = { + debug_mode: _IS_DEV, + enable_preview_feature_components_support: + _ENABLE_PREVIEW_FEATURE_COMPONENTS_SUPPORT, + preview_runner_framework_config: vanilla_presets.vanilla_default, + framework_config: react_presets.react_default, + }; + if (!saved_pref) pref_store.set(default_pref); + return { history: createInitialHistoryState(editor), - preferences: { - debug_mode: _IS_DEV, - enable_preview_feature_components_support: - _ENABLE_PREVIEW_FEATURE_COMPONENTS_SUPPORT, - preview_runner_framework_config: vanilla_presets.vanilla_default, - framework_config: react_presets.react_default, - }, + preferences: saved_pref ?? default_pref, }; } diff --git a/editor/core/states/workspace-state.ts b/editor/core/states/workspace-state.ts index 5a3fb240..b08e28a6 100644 --- a/editor/core/states/workspace-state.ts +++ b/editor/core/states/workspace-state.ts @@ -3,10 +3,12 @@ import { HistoryState } from "core/states/history-state"; export interface WorkspaceState { history: HistoryState; - preferences: { - debug_mode: boolean; - framework_config: config.FrameworkConfig; - preview_runner_framework_config: config.FrameworkConfig; - enable_preview_feature_components_support: boolean; - }; + preferences: WorkspacePreferences; +} + +export interface WorkspacePreferences { + debug_mode: boolean; + framework_config: config.FrameworkConfig; + preview_runner_framework_config: config.FrameworkConfig; + enable_preview_feature_components_support: boolean; } diff --git a/editor/pages/preferences/index.tsx b/editor/pages/preferences/index.tsx index fd79dc75..286d32a2 100644 --- a/editor/pages/preferences/index.tsx +++ b/editor/pages/preferences/index.tsx @@ -1,12 +1,53 @@ import React from "react"; import Link from "next/link"; import styled from "@emotion/styled"; + +import FormGroup from "@material-ui/core/FormGroup"; +import FormControlLabel from "@material-ui/core/FormControlLabel"; +import Checkbox from "@material-ui/core/Checkbox"; +import { WorkspacePreferenceStore } from "store/workspace-preference-store"; + export default function PreferencesHomePage() { + const wsprefef = new WorkspacePreferenceStore(); + return ( <_Root> Set Personal Access token for figma +
+
+
+
+
Workspace preferences
+ + { + wsprefef.debug_mode(e.target.checked); + }} + /> + } + label="debug_mode" + /> + { + wsprefef.enable_preview_feature_components_support( + e.target.checked + ); + }} + /> + } + label="enable_preview_feature_components_support" + /> + ); } diff --git a/editor/store/workspace-preference-store/index.ts b/editor/store/workspace-preference-store/index.ts new file mode 100644 index 00000000..6af9b947 --- /dev/null +++ b/editor/store/workspace-preference-store/index.ts @@ -0,0 +1 @@ +export { WorkspacePreferenceStore } from "./workspace-preference-store"; diff --git a/editor/store/workspace-preference-store/workspace-preference-store.ts b/editor/store/workspace-preference-store/workspace-preference-store.ts new file mode 100644 index 00000000..b0d53d83 --- /dev/null +++ b/editor/store/workspace-preference-store/workspace-preference-store.ts @@ -0,0 +1,37 @@ +import { WorkspacePreferences } from "core/states"; +export class WorkspacePreferenceStore { + readonly key: string; + constructor(ws?: string) { + this.key = "workspace-preferences-" + ws ?? "default"; + } + + enable_preview_feature_components_support(b: boolean) { + const pf = this.load(); + pf.enable_preview_feature_components_support = b; + this.set(pf); + return pf; + } + + debug_mode(b: boolean) { + const pf = this.load(); + pf.debug_mode = b; + this.set(pf); + return pf; + } + + set(pf: WorkspacePreferences) { + window.localStorage.setItem(this.key, JSON.stringify(pf)); + } + + load(): WorkspacePreferences { + try { + const pl = window.localStorage.getItem(this.key); + if (!pl) { + return; + } + return JSON.parse(pl) as WorkspacePreferences; + } catch (e) { + return; + } + } +} diff --git a/packages/builder-css-styles/index.ts b/packages/builder-css-styles/index.ts index 8176110c..cf1cc4ca 100644 --- a/packages/builder-css-styles/index.ts +++ b/packages/builder-css-styles/index.ts @@ -11,6 +11,7 @@ export * from "./text-decoration"; export * from "./text-shadow"; export * from "./gradient"; export * from "./padding"; +export * from "./margin"; export * from "./position"; export * from "./justify-content"; export * from "./min-height"; diff --git a/packages/builder-css-styles/margin/index.ts b/packages/builder-css-styles/margin/index.ts new file mode 100644 index 00000000..82040495 --- /dev/null +++ b/packages/builder-css-styles/margin/index.ts @@ -0,0 +1,56 @@ +import { CSSProperties } from "@coli.codes/css"; +import { EdgeInsets } from "@reflect-ui/core"; +import { px } from "../dimensions"; + +type MarginValue = number | "auto"; + +export function margin(m: EdgeInsets): CSSProperties { + if (!m) { + return {}; + } + if (m.top === 0 && m.right === 0 && m.bottom === 0 && m.left === 0) { + return {}; + } + if (m.top === m.bottom && m.left === m.right) { + return { + margin: `${_mv(m.top)} ${_mv(m.left)}`, + }; + } else if (m.left === m.right) { + return { + margin: `${_mv(m.top)} ${_mv(m.left)} ${_mv(m.bottom)}`, + }; + } + return { + "margin-bottom": _makeifRequired(m?.bottom), + "margin-top": _makeifRequired(m?.top), + "margin-left": _makeifRequired(m?.left), + "margin-right": _makeifRequired(m?.right), + }; +} + +/** + * Margin Value - mv + * @param mv + * @returns + */ +function _mv(mv: MarginValue) { + if (mv === undefined) { + return; + } + if (mv === "auto") { + return "auto"; + } + return px(mv); +} + +function _makeifRequired(val: MarginValue): string | undefined { + if (val === undefined) { + return; + } + if (val === "auto") { + return "auto"; + } + if (val && val > 0) { + return px(val); + } +} diff --git a/packages/builder-web-core/widgets-native/container/index.ts b/packages/builder-web-core/widgets-native/container/index.ts index 2c4a9e41..6d57f033 100644 --- a/packages/builder-web-core/widgets-native/container/index.ts +++ b/packages/builder-web-core/widgets-native/container/index.ts @@ -5,6 +5,7 @@ import { BorderRadiusManifest, BoxShadowManifest, DimensionLength, + EdgeInsets, } from "@reflect-ui/core"; import { Background } from "@reflect-ui/core/lib/background"; import * as css from "@web-builder/styles"; @@ -17,6 +18,7 @@ export class Container extends StylableJsxWidget { children?: StylableJsxWidget[]; borderRadius?: BorderRadiusManifest; border?: Border; + margin?: EdgeInsets; constructor(p: { key: WidgetKey; @@ -30,6 +32,8 @@ export class Container extends StylableJsxWidget { minHeight?: DimensionLength; maxHeight?: DimensionLength; + margin?: EdgeInsets; + background?: Background; borderRadius?: BorderRadiusManifest; boxShadow?: BoxShadowManifest[]; @@ -44,6 +48,8 @@ export class Container extends StylableJsxWidget { this.minHeight = p.minHeight; this.maxHeight = p.maxHeight; + this.margin = p.margin; + this.x = p.x; this.y = p.y; this.background = p.background; @@ -60,7 +66,7 @@ export class Container extends StylableJsxWidget { "max-width": css.length(this.maxWidth), "min-height": css.length(this.minHeight), "max-height": css.length(this.maxHeight), - + ...css.margin(this.margin), "box-shadow": css.boxshadow(...(this.boxShadow ?? [])), ...css.background(this.background), ...css.border(this.border), diff --git a/packages/designto-token/support-flags/token-wh/index.ts b/packages/designto-token/support-flags/token-wh/index.ts index aa873f71..3aab303f 100644 --- a/packages/designto-token/support-flags/token-wh/index.ts +++ b/packages/designto-token/support-flags/token-wh/index.ts @@ -1,7 +1,9 @@ import { WHDeclarationFlag } from "@code-features/flags"; import { ReflectSceneNode } from "@design-sdk/figma-node"; import { + Container, DimensionLength, + EdgeInsets, isPossibleDimensionLength, IWHStyleWidget, Widget, @@ -58,6 +60,7 @@ export function tokenize_flagged_wh_declaration( const flag_target = unwrappedChild(widget) as IWHStyleWidget; + // set wh preference merged.width && (flag_target.width = merged.width); merged.minWidth && (flag_target.minWidth = merged.minWidth); merged.maxWidth && (flag_target.maxWidth = merged.maxWidth); @@ -65,5 +68,31 @@ export function tokenize_flagged_wh_declaration( merged.minHeight && (flag_target.minHeight = merged.minHeight); merged.maxHeight && (flag_target.maxHeight = merged.maxHeight); + // if the constraints are set to left & right or top & bottom, we have to add `margin-(?): auto;` to make align the item to center as it is on origin design. + // Learn more about this transformation - https://stackoverflow.com/questions/17993471/css-wont-center-div-with-max-width + // TODO: the margin's value to "auto" is not acceptable. this is a abberation, needs to fixed. + const container = widget as Container; + const _provide_initial_margin_if_none = () => { + if (!container.margin) { + container.margin = new EdgeInsets({ + top: undefined, + right: undefined, + bottom: undefined, + left: undefined, + }); + } + }; + if (node.constraints.horizontal == "STRETCH") { + _provide_initial_margin_if_none(); + container.margin.left = "auto" as any; + container.margin.right = "auto" as any; + } + + if (node.constraints.vertical == "STRETCH") { + _provide_initial_margin_if_none(); + container.margin.top = "auto" as any; + container.margin.bottom = "auto" as any; + } + return widget; } diff --git a/packages/designto-token/token-layout/index.ts b/packages/designto-token/token-layout/index.ts index 4ccf1991..68e6bec2 100644 --- a/packages/designto-token/token-layout/index.ts +++ b/packages/designto-token/token-layout/index.ts @@ -127,10 +127,31 @@ function flex_or_stack_from_frame( }; if (frame.isAutoLayout) { + // TODO: inspect me. We're not 100% sure this is the correct behaviour. switch (frame.layoutMode) { case Axis.horizontal: + if (frame.primaryAxisSizingMode === "AUTO") { + // when horizontal, primaryAxisSizingMode is x axis + // don't specify width + initializer.width = undefined; + } + if (frame.counterAxisSizingMode === "AUTO") { + // when horizontal, counterAxisSizingMode is y axis + // don't specify height + initializer.height = undefined; + } return new Row(initializer); case Axis.vertical: + if (frame.counterAxisSizingMode === "AUTO") { + // when vertical, counterAxisSizingMode is x axis + // don't specify width + initializer.width = undefined; + } + if (frame.primaryAxisSizingMode === "AUTO") { + // when vertical, primaryAxisSizingMode is y axis + // don't specify height + initializer.height = undefined; + } return new Column(initializer); default: console.info(`Frame: "${frame.name}" fallback to flex`); diff --git a/packages/support-flags/docs/--as-p.md b/packages/support-flags/docs/--as-p.md index f8705a1c..e5b84868 100644 --- a/packages/support-flags/docs/--as-p.md +++ b/packages/support-flags/docs/--as-p.md @@ -6,12 +6,11 @@ stage: - proposal - draft - experimental - - not-ready --- # `--as-p` As Paragraph (Text) -> This flag is for web platform. Otherwise, it will be ignored, have no impact on the final output. +> This flag is for web platform. On other platforms, this will be ignored, have no impact on the final output. **Accepted keys** @@ -25,7 +24,7 @@ stage: `--as-p${"="typeof boolean}` ``` -## Example +**Example** ``` --paragraph diff --git a/packages/support-flags/docs/translations/ko/--as-p.md b/packages/support-flags/docs/translations/ko/--as-p.md new file mode 100644 index 00000000..12585204 --- /dev/null +++ b/packages/support-flags/docs/translations/ko/--as-p.md @@ -0,0 +1,67 @@ +--- +title: As Paragraph flag +id: "--as-p" +locale: en +stage: + - proposal + - draft + - experimental +--- + +# `--as-p` Paragraph 명시 플래그 (Text) + +> 이 플래그는 웹 플랫폼을 위한것입니다. 다른 프랫폼에서는 무시되며, 결과물에 아무런 영향을 끼치지 않습니다. + +**지정 가능한 키** + +- `--as-p` +- `--as-paragraph` +- `--paragraph` + +## 문법 + +```ts +`--as-p${"="typeof boolean}` +``` + +**적용 예시** + +``` +--paragraph + +--paragraph=true +--paragraph=false + +--paragraph=yes +--paragraph=no + +----paragraph +``` + +## 언제 사용하면 좋을까 + + + +**SEO** + +element tag 를 명시하는것은 SEO 에 있어, 필수적입니다. 특히 헤딩일 경우, 그 효과는 더 큽니다. +모바일 앱의 경우, 해당 사항이 없겠지만, 웹어서는 의미에 맞게 h1~h6 과 함께 p 을 지정하는 것이 좋습니다. + +## 동작 + +**엘레먼트 (Element)** +이 플래그가 적용된다면, 해당 노드의 html 생성 엘레먼트는 `

` 로 렌더되어 표시됩니다. (이외의 로직에는 영향이 없으며, 태그가 변경되었기에 이에 따른 부작용은 사용자의 커스텀 css 또는 query 에 따라 변경될 수 있습니다.) + +**Text style** +아직 p 를 사용함으로써 자동으로 적용되는 텍스트 스타일은 없습니다. 지정 하지 않았을때와 동일한 방식으로 스타일링이 적용됩니다. 다만 기존 글로벌한 스타일에 p 에 대한 텍스트 스타일이 존재한다면, 이는 직접 영향을 받지 않도록 글로벌 스타일을 수정해주어야 합니다. + +## 같이보기 + +- [`--as-h1`](./--as-h1) +- [`--as-h2`](./--as-h2) +- [`--as-h3`](./--as-h3) +- [`--as-h4`](./--as-h4) +- [`--as-h5`](./--as-h5) +- [`--as-h6`](./--as-h6) +- [`--as-p`](./--as-p) +- [`--as-br`](./--as-br)