mirror of
https://github.com/penpot/penpot.git
synced 2025-05-21 17:56:11 +02:00
Merge pull request #4845 from penpot/ladybenko-8265-raw-svg-component
RawSVG component (design system) + generate SVG sprite for assets
This commit is contained in:
commit
9ce3f6da45
26 changed files with 916 additions and 19 deletions
|
@ -7,11 +7,16 @@
|
|||
(ns app.main.ui.ds
|
||||
(:require
|
||||
[app.main.ui.ds.foundations.icon :refer [icon* icon-list]]
|
||||
[app.main.ui.ds.foundations.raw-svg :refer [raw-svg* raw-svg-list]]
|
||||
[app.main.ui.ds.storybook :as sb]))
|
||||
|
||||
(def default
|
||||
"A export used for storybook"
|
||||
#js {:Icon icon*
|
||||
:RawSvg raw-svg*
|
||||
;; meta / misc
|
||||
:meta #js {:icons icon-list}
|
||||
:storybook #js {:StoryWrapper sb/story-wrapper* :IconGrid sb/icon-grid*}})
|
||||
:meta #js {:icons icon-list :svgs raw-svg-list}
|
||||
:storybook #js {:StoryGrid sb/story-grid*
|
||||
:StoryGridCell sb/story-grid-cell*
|
||||
:StoryHeader sb/story-header*
|
||||
:StoryWrapper sb/story-wrapper*}})
|
||||
|
|
|
@ -253,7 +253,7 @@
|
|||
{::mf/props :obj}
|
||||
[{:keys [icon size class] :rest props}]
|
||||
(let [class (dm/str (or class "") " " (stl/css :icon))
|
||||
props (mf/spread props {:class class :width icon-size-m :height icon-size-m})
|
||||
props (mf/spread-props props {:class class :width icon-size-m :height icon-size-m})
|
||||
size-px (cond (= size "s") icon-size-s :else icon-size-m)
|
||||
offset (/ (- icon-size-m size-px) 2)]
|
||||
[:> "svg" props
|
||||
|
|
|
@ -2,7 +2,8 @@ import * as React from "react";
|
|||
import Components from "@target/components";
|
||||
|
||||
const { Icon } = Components;
|
||||
const { StoryWrapper, IconGrid } = Components.storybook;
|
||||
const { StoryWrapper, StoryGrid, StoryGridCell, StoryHeader } =
|
||||
Components.storybook;
|
||||
const { icons } = Components.meta;
|
||||
|
||||
export default {
|
||||
|
@ -17,23 +18,32 @@ const iconList = Object.entries(icons)
|
|||
export const AllIcons = {
|
||||
render: () => (
|
||||
<StoryWrapper theme="default">
|
||||
<h1>All Icons</h1>
|
||||
<p>Hover on an icon to see its ID</p>
|
||||
<IconGrid>
|
||||
<StoryHeader>
|
||||
<h1>All Icons</h1>
|
||||
<p>Hover on an icon to see its ID</p>
|
||||
</StoryHeader>
|
||||
<StoryGrid>
|
||||
{iconList.map((iconId) => (
|
||||
<div title={iconId} key={iconId}>
|
||||
<StoryGridCell
|
||||
title={iconId}
|
||||
key={iconId}
|
||||
style={{ color: "var(--color-accent-primary)" }}
|
||||
>
|
||||
<Icon icon={iconId} />
|
||||
</div>
|
||||
</StoryGridCell>
|
||||
))}
|
||||
</IconGrid>
|
||||
</StoryGrid>
|
||||
</StoryWrapper>
|
||||
),
|
||||
parameters: {
|
||||
backgrounds: { disable: true },
|
||||
},
|
||||
};
|
||||
|
||||
export const Default = {
|
||||
render: () => (
|
||||
<StoryWrapper theme="default">
|
||||
<Icon icon="pin" />
|
||||
<Icon icon={icons.Pin} />
|
||||
</StoryWrapper>
|
||||
),
|
||||
};
|
||||
|
@ -41,7 +51,7 @@ export const Default = {
|
|||
export const Small = {
|
||||
render: () => (
|
||||
<StoryWrapper theme="default">
|
||||
<Icon icon="pin" size="s" />
|
||||
<Icon icon={icons.Pin} size="s" />
|
||||
</StoryWrapper>
|
||||
),
|
||||
};
|
||||
|
|
21
frontend/src/app/main/ui/ds/foundations/raw_svg.clj
Normal file
21
frontend/src/app/main/ui/ds/foundations/raw_svg.clj
Normal file
|
@ -0,0 +1,21 @@
|
|||
;; 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.main.ui.ds.foundations.raw-svg
|
||||
(:require
|
||||
[clojure.core :as c]
|
||||
[cuerdas.core :as str]
|
||||
[rumext.v2]))
|
||||
|
||||
(defmacro collect-raw-svgs
|
||||
[]
|
||||
(let [ns-info (:ns &env)]
|
||||
`(cljs.core/js-obj
|
||||
~@(->> (:defs ns-info)
|
||||
(map val)
|
||||
(filter (fn [entry] (-> entry :meta :svg-id)))
|
||||
(mapcat (fn [{:keys [name]}]
|
||||
[(-> name c/name str/camel str/capital) name]))))))
|
37
frontend/src/app/main/ui/ds/foundations/raw_svg.cljs
Normal file
37
frontend/src/app/main/ui/ds/foundations/raw_svg.cljs
Normal file
|
@ -0,0 +1,37 @@
|
|||
;; 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.main.ui.ds.foundations.raw-svg
|
||||
(:refer-clojure :exclude [mask])
|
||||
(:require-macros
|
||||
[app.common.data.macros :as dm]
|
||||
[app.main.ui.ds.foundations.raw-svg :refer [collect-raw-svgs]])
|
||||
(:require
|
||||
[rumext.v2 :as mf]))
|
||||
|
||||
(def ^:svg-id brand-openid "brand-openid")
|
||||
(def ^:svg-id brand-github "brand-github")
|
||||
(def ^:svg-id brand-gitlab "brand-gitlab")
|
||||
(def ^:svg-id brand-google "brand-google")
|
||||
|
||||
(def ^:svg-id loader "loader")
|
||||
(def ^:svg-id logo "penpot-logo")
|
||||
(def ^:svg-id logo-icon "penpot-logo-icon")
|
||||
(def ^:svg-id logo-error-screen "logo-error-screen")
|
||||
(def ^:svg-id login-illustration "login-illustration")
|
||||
|
||||
(def ^:svg-id v2-icon-1 "v2-icon-1")
|
||||
(def ^:svg-id v2-icon-2 "v2-icon-2")
|
||||
(def ^:svg-id v2-icon-3 "v2-icon-3")
|
||||
(def ^:svg-id v2-icon-4 "v2-icon-4")
|
||||
|
||||
(def raw-svg-list "A collection of all raw SVG assets" (collect-raw-svgs))
|
||||
|
||||
(mf/defc raw-svg*
|
||||
{::mf/props :obj}
|
||||
[{:keys [asset] :rest props}]
|
||||
[:> "svg" props
|
||||
[:use {:href (dm/str "#asset-" asset)}]])
|
28
frontend/src/app/main/ui/ds/foundations/raw_svg.mdx
Normal file
28
frontend/src/app/main/ui/ds/foundations/raw_svg.mdx
Normal file
|
@ -0,0 +1,28 @@
|
|||
import { Canvas, Meta } from "@storybook/blocks";
|
||||
import * as RawSvgStories from "./raw_svg.stories";
|
||||
|
||||
<Meta of={RawSvgStories} />
|
||||
|
||||
# SVG Assets
|
||||
|
||||
## Technical notes
|
||||
|
||||
There are some SVG assets that are not icons or cursors, and that are mostly
|
||||
meant to be used as is (although depending on the context, some will be required
|
||||
to be used with a specific color or size).
|
||||
|
||||
The assets are located in the `frontend/resources/images/assets` folder.
|
||||
|
||||
### Using asset IDs
|
||||
|
||||
For convenience, asset IDs are available in the component namespace.
|
||||
|
||||
```clj
|
||||
(ns app.main.ui.foo
|
||||
(:require
|
||||
[app.main.ui.ds.foundations.raw-svg :as svg]))
|
||||
```
|
||||
|
||||
```clj
|
||||
[:> svg/svg-asset* {:asset svg/logo}]
|
||||
```
|
46
frontend/src/app/main/ui/ds/foundations/raw_svg.stories.jsx
Normal file
46
frontend/src/app/main/ui/ds/foundations/raw_svg.stories.jsx
Normal file
|
@ -0,0 +1,46 @@
|
|||
import * as React from "react";
|
||||
import Components from "@target/components";
|
||||
|
||||
const { RawSvg } = Components;
|
||||
const { StoryWrapper, StoryGrid, StoryGridCell, StoryHeader } =
|
||||
Components.storybook;
|
||||
const { svgs } = Components.meta;
|
||||
|
||||
export default {
|
||||
title: "Foundations/RawSvg",
|
||||
component: Components.RawSvg,
|
||||
};
|
||||
|
||||
const assetList = Object.entries(svgs)
|
||||
.map(([_, value]) => value)
|
||||
.sort();
|
||||
|
||||
export const AllAssets = {
|
||||
render: () => (
|
||||
<StoryWrapper theme="light">
|
||||
<StoryHeader>
|
||||
<h1>All assets</h1>
|
||||
<p>Hover on a asset to see its id.</p>
|
||||
</StoryHeader>
|
||||
|
||||
<StoryGrid size="200">
|
||||
{assetList.map((x) => (
|
||||
<StoryGridCell key={x} title={x}>
|
||||
<RawSvg asset={x} style={{ maxWidth: "100%" }} />
|
||||
</StoryGridCell>
|
||||
))}
|
||||
</StoryGrid>
|
||||
</StoryWrapper>
|
||||
),
|
||||
parameters: {
|
||||
backgrounds: { values: [{ name: "debug", value: "#ccc" }] },
|
||||
},
|
||||
};
|
||||
|
||||
export const Default = {
|
||||
render: () => (
|
||||
<StoryWrapper theme="default">
|
||||
<RawSvg asset={svgs.BrandGitlab} width="200" />
|
||||
</StoryWrapper>
|
||||
),
|
||||
};
|
|
@ -6,7 +6,9 @@
|
|||
;; Copyright (c) KALEIDOS INC
|
||||
|
||||
(ns app.main.ui.ds.storybook
|
||||
(:require-macros [app.main.style :as stl])
|
||||
(:require-macros
|
||||
[app.common.data.macros :as dm]
|
||||
[app.main.style :as stl])
|
||||
(:require
|
||||
[rumext.v2 :as mf]))
|
||||
|
||||
|
@ -20,7 +22,26 @@
|
|||
[:section {:class "default"} children]
|
||||
[:section {:class "light"} children]])])
|
||||
|
||||
(mf/defc icon-grid*
|
||||
(mf/defc story-grid*
|
||||
{::mf/props :obj}
|
||||
[{:keys [children]}]
|
||||
[:article {:class (stl/css :icon-grid)} children])
|
||||
[{:keys [children size style] :rest other}]
|
||||
(let [class (stl/css :story-grid)
|
||||
size (or size 16)
|
||||
style (or style {})
|
||||
style (mf/spread style :--component-grid-size (dm/str size "px"))
|
||||
props (mf/spread-props other {:class class :style style})]
|
||||
[:> "article" props children]))
|
||||
|
||||
(mf/defc story-grid-cell*
|
||||
{::mf/props :obj}
|
||||
[{:keys [children] :rest other}]
|
||||
(let [class (stl/css :story-grid-cell)
|
||||
props (mf/spread-props other {:class class})]
|
||||
[:> "article" props children]))
|
||||
|
||||
(mf/defc story-header*
|
||||
{::mf/props :obj}
|
||||
[{:keys [children] :rest other}]
|
||||
(let [class (stl/css :story-header)
|
||||
props (mf/spread-props other {:class class})]
|
||||
[:> "header" props children]))
|
||||
|
|
|
@ -5,9 +5,17 @@
|
|||
row-gap: 1rem;
|
||||
}
|
||||
|
||||
.icon-grid {
|
||||
.story-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, 16px);
|
||||
grid-template-columns: repeat(auto-fit, var(--component-grid-size, 16px));
|
||||
gap: 1rem;
|
||||
color: var(--color-foreground-primary);
|
||||
}
|
||||
|
||||
.story-grid-cell {
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
.story-header {
|
||||
color: var(--color-foreground-primary);
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue