0
Fork 0
mirror of https://github.com/penpot/penpot.git synced 2025-04-13 07:21:40 -05:00

Implement icon* component

This commit is contained in:
Belén Albeza 2024-07-01 14:52:56 +02:00
parent c6a7ad0520
commit 6295fbf7e2
8 changed files with 459 additions and 7 deletions

View file

@ -7,9 +7,13 @@
(ns app.main.ui.ds
(:require
[app.main.ui.ds.buttons.simple-button :refer [simple-button]]
[app.main.ui.ds.foundations.icon :refer [icon* icon-list]]
[app.main.ui.ds.storybook :as sb]))
(def default
"A export used for storybook"
#js {:SimpleButton simple-button
:StoryWrapper sb/story-wrapper})
#js {:Icon icon*
:SimpleButton simple-button
;; meta / misc
:meta #js {:icons icon-list}
:storybook #js {:StoryWrapper sb/story-wrapper* :IconGrid sb/icon-grid*}})

View 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.icon
(:require
[clojure.core :as c]
[cuerdas.core :as str]
[rumext.v2]))
(defmacro collect-icons
[]
(let [ns-info (:ns &env)]
`(cljs.core/js-obj
~@(->> (:defs ns-info)
(map val)
(filter (fn [entry] (-> entry :meta :icon-id)))
(mapcat (fn [{:keys [name]}]
[(-> name c/name str/camel str/capital) name]))))))

View file

@ -0,0 +1,260 @@
;; 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.icon
(:refer-clojure :exclude [mask])
(:require-macros
[app.common.data.macros :as dm]
[app.main.style :as stl]
[app.main.ui.ds.foundations.icon :refer [collect-icons]])
(:require
[rumext.v2 :as mf]))
(def ^:icon-id absolute "absolute")
(def ^:icon-id add "add")
(def ^:icon-id align-bottom "align-bottom")
(def ^:icon-id align-content-column-around "align-content-column-around")
(def ^:icon-id align-content-column-between "align-content-column-between")
(def ^:icon-id align-content-column-center "align-content-column-center")
(def ^:icon-id align-content-column-end "align-content-column-end")
(def ^:icon-id align-content-column-evenly "align-content-column-evenly")
(def ^:icon-id align-content-column-start "align-content-column-start")
(def ^:icon-id align-content-column-stretch "align-content-column-stretch")
(def ^:icon-id align-content-row-around "align-content-row-around")
(def ^:icon-id align-content-row-between "align-content-row-between")
(def ^:icon-id align-content-row-center "align-content-row-center")
(def ^:icon-id align-content-row-end "align-content-row-end")
(def ^:icon-id align-content-row-evenly "align-content-row-evenly")
(def ^:icon-id align-content-row-start "align-content-row-start")
(def ^:icon-id align-content-row-stretch "align-content-row-stretch")
(def ^:icon-id align-horizontal-center "align-horizontal-center")
(def ^:icon-id align-items-column-center "align-items-column-center")
(def ^:icon-id align-items-column-end "align-items-column-end")
(def ^:icon-id align-items-column-start "align-items-column-start")
(def ^:icon-id align-items-row-center "align-items-row-center")
(def ^:icon-id align-items-row-end "align-items-row-end")
(def ^:icon-id align-items-row-start "align-items-row-start")
(def ^:icon-id align-left "align-left")
(def ^:icon-id align-right "align-right")
(def ^:icon-id align-self-column-bottom "align-self-column-bottom")
(def ^:icon-id align-self-column-center "align-self-column-center")
(def ^:icon-id align-self-column-stretch "align-self-column-stretch")
(def ^:icon-id align-self-column-top "align-self-column-top")
(def ^:icon-id align-self-row-center "align-self-row-center")
(def ^:icon-id align-self-row-left "align-self-row-left")
(def ^:icon-id align-self-row-right "align-self-row-right")
(def ^:icon-id align-self-row-stretch "align-self-row-stretch")
(def ^:icon-id align-top "align-top")
(def ^:icon-id align-vertical-center "align-vertical-center")
(def ^:icon-id arrow "arrow")
(def ^:icon-id asc-sort "asc-sort")
(def ^:icon-id board "board")
(def ^:icon-id boards-thumbnail "boards-thumbnail")
(def ^:icon-id boolean-difference "boolean-difference")
(def ^:icon-id boolean-exclude "boolean-exclude")
(def ^:icon-id boolean-flatten "boolean-flatten")
(def ^:icon-id boolean-intersection "boolean-intersection")
(def ^:icon-id boolean-union "boolean-union")
(def ^:icon-id bug "bug")
(def ^:icon-id clip-content "clip-content")
(def ^:icon-id clipboard "clipboard")
(def ^:icon-id close-small "close-small")
(def ^:icon-id close "close")
(def ^:icon-id code "code")
(def ^:icon-id column-reverse "column-reverse")
(def ^:icon-id column "column")
(def ^:icon-id comments "comments")
(def ^:icon-id component-copy "component-copy")
(def ^:icon-id component "component")
(def ^:icon-id constraint-horizontal "constraint-horizontal")
(def ^:icon-id constraint-vertical "constraint-vertical")
(def ^:icon-id corner-bottom-left "corner-bottom-left")
(def ^:icon-id corner-bottom-right "corner-bottom-right")
(def ^:icon-id corner-bottom "corner-bottom")
(def ^:icon-id corner-center "corner-center")
(def ^:icon-id corner-radius "corner-radius")
(def ^:icon-id corner-top "corner-top")
(def ^:icon-id corner-top-left "corner-top-left")
(def ^:icon-id corner-top-right "corner-top-right")
(def ^:icon-id curve "curve")
(def ^:icon-id delete-text "delete-text")
(def ^:icon-id delete "delete")
(def ^:icon-id desc-sort "desc-sort")
(def ^:icon-id detach "detach")
(def ^:icon-id detached "detached")
(def ^:icon-id distribute-horizontally "distribute-horizontally")
(def ^:icon-id distribute-vertical-spacing "distribute-vertical-spacing")
(def ^:icon-id document "document")
(def ^:icon-id download "download")
(def ^:icon-id drop-icon "drop")
(def ^:icon-id easing-ease-in-out "easing-ease-in-out")
(def ^:icon-id easing-ease-in "easing-ease-in")
(def ^:icon-id easing-ease-out "easing-ease-out")
(def ^:icon-id easing-ease "easing-ease")
(def ^:icon-id easing-linear "easing-linear")
(def ^:icon-id effects "effects")
(def ^:icon-id elipse "elipse")
(def ^:icon-id exit "exit")
(def ^:icon-id expand "expand")
(def ^:icon-id feedback "feedback")
(def ^:icon-id fill-content "fill-content")
(def ^:icon-id filter-icon "filter")
(def ^:icon-id fixed-width "fixed-width")
(def ^:icon-id flex-grid "flex-grid")
(def ^:icon-id flex-horizontal "flex-horizontal")
(def ^:icon-id flex-vertical "flex-vertical")
(def ^:icon-id flex "flex")
(def ^:icon-id flip-horizontal "flip-horizontal")
(def ^:icon-id flip-vertical "flip-vertical")
(def ^:icon-id gap-horizontal "gap-horizontal")
(def ^:icon-id gap-vertical "gap-vertical")
(def ^:icon-id graphics "graphics")
(def ^:icon-id grid-column "grid-column")
(def ^:icon-id grid-columns "grid-columns")
(def ^:icon-id grid-gutter "grid-gutter")
(def ^:icon-id grid-margin "grid-margin")
(def ^:icon-id grid "grid")
(def ^:icon-id grid-row "grid-row")
(def ^:icon-id grid-rows "grid-rows")
(def ^:icon-id grid-square "grid-square")
(def ^:icon-id group "group")
(def ^:icon-id gutter-horizontal "gutter-horizontal")
(def ^:icon-id gutter-vertical "gutter-vertical")
(def ^:icon-id help "help")
(def ^:icon-id hide "hide")
(def ^:icon-id history "history")
(def ^:icon-id hsva "hsva")
(def ^:icon-id hug-content "hug-content")
(def ^:icon-id icon "icon")
(def ^:icon-id img "img")
(def ^:icon-id interaction "interaction")
(def ^:icon-id join-nodes "join-nodes")
(def ^:icon-id external-link "external-link")
(def ^:icon-id justify-content-column-around "justify-content-column-around")
(def ^:icon-id justify-content-column-between "justify-content-column-between")
(def ^:icon-id justify-content-column-center "justify-content-column-center")
(def ^:icon-id justify-content-column-end "justify-content-column-end")
(def ^:icon-id justify-content-column-evenly "justify-content-column-evenly")
(def ^:icon-id justify-content-column-start "justify-content-column-start")
(def ^:icon-id justify-content-row-around "justify-content-row-around")
(def ^:icon-id justify-content-row-between "justify-content-row-between")
(def ^:icon-id justify-content-row-center "justify-content-row-center")
(def ^:icon-id justify-content-row-end "justify-content-row-end")
(def ^:icon-id justify-content-row-evenly "justify-content-row-evenly")
(def ^:icon-id justify-content-row-start "justify-content-row-start")
(def ^:icon-id layers "layers")
(def ^:icon-id library "library")
(def ^:icon-id locate "locate")
(def ^:icon-id lock "lock")
(def ^:icon-id margin "margin")
(def ^:icon-id margin-bottom "margin-bottom")
(def ^:icon-id margin-left "margin-left")
(def ^:icon-id margin-left-right "margin-left-right")
(def ^:icon-id margin-right "margin-right")
(def ^:icon-id margin-top "margin-top")
(def ^:icon-id margin-top-bottom "margin-top-bottom")
(def ^:icon-id mask "mask")
(def ^:icon-id masked "masked")
(def ^:icon-id menu "menu")
(def ^:icon-id merge-nodes "merge-nodes")
(def ^:icon-id move "move")
(def ^:icon-id msg-error "msg-error")
(def ^:icon-id msg-neutral "msg-neutral")
(def ^:icon-id msg-success "msg-success")
(def ^:icon-id msg-warning "msg-warning")
(def ^:icon-id open-link "open-link")
(def ^:icon-id padding-bottom "padding-bottom")
(def ^:icon-id padding-extended "padding-extended")
(def ^:icon-id padding-left "padding-left")
(def ^:icon-id padding-left-right "padding-left-right")
(def ^:icon-id padding-right "padding-right")
(def ^:icon-id padding-top "padding-top")
(def ^:icon-id padding-top-bottom "padding-top-bottom")
(def ^:icon-id path "path")
(def ^:icon-id pentool "pentool")
(def ^:icon-id picker "picker")
(def ^:icon-id pin "pin")
(def ^:icon-id play "play")
(def ^:icon-id rectangle "rectangle")
(def ^:icon-id reload "reload")
(def ^:icon-id remove-icon "remove")
(def ^:icon-id rgba "rgba")
(def ^:icon-id rgba-complementary "rgba-complementary")
(def ^:icon-id rocket "rocket")
(def ^:icon-id rotation "rotation")
(def ^:icon-id row "row")
(def ^:icon-id row-reverse "row-reverse")
(def ^:icon-id search "search")
(def ^:icon-id separate-nodes "separate-nodes")
(def ^:icon-id shown "shown")
(def ^:icon-id size-horizontal "size-horizontal")
(def ^:icon-id size-vertical "size-vertical")
(def ^:icon-id snap-nodes "snap-nodes")
(def ^:icon-id status-alert "status-alert")
(def ^:icon-id status-tick "status-tick")
(def ^:icon-id status-update "status-update")
(def ^:icon-id status-wrong "status-wrong")
(def ^:icon-id stroke-arrow "stroke-arrow")
(def ^:icon-id stroke-circle "stroke-circle")
(def ^:icon-id stroke-diamond "stroke-diamond")
(def ^:icon-id stroke-rectangle "stroke-rectangle")
(def ^:icon-id stroke-rounded "stroke-rounded")
(def ^:icon-id stroke-size "stroke-size")
(def ^:icon-id stroke-squared "stroke-squared")
(def ^:icon-id stroke-triangle "stroke-triangle")
(def ^:icon-id svg "svg")
(def ^:icon-id swatches "swatches")
(def ^:icon-id switch "switch")
(def ^:icon-id text "text")
(def ^:icon-id text-align-center "text-align-center")
(def ^:icon-id text-align-left "text-align-left")
(def ^:icon-id text-align-right "text-align-right")
(def ^:icon-id text-auto-height "text-auto-height")
(def ^:icon-id text-auto-width "text-auto-width")
(def ^:icon-id text-bottom "text-bottom")
(def ^:icon-id text-fixed "text-fixed")
(def ^:icon-id text-justify "text-justify")
(def ^:icon-id text-letterspacing "text-letterspacing")
(def ^:icon-id text-lineheight "text-lineheight")
(def ^:icon-id text-lowercase "text-lowercase")
(def ^:icon-id text-ltr "text-ltr")
(def ^:icon-id text-middle "text-middle")
(def ^:icon-id text-mixed "text-mixed")
(def ^:icon-id text-palette "text-palette")
(def ^:icon-id text-paragraph "text-paragraph")
(def ^:icon-id text-rtl "text-rtl")
(def ^:icon-id text-stroked "text-stroked")
(def ^:icon-id text-top "text-top")
(def ^:icon-id text-underlined "text-underlined")
(def ^:icon-id text-uppercase "text-uppercase")
(def ^:icon-id thumbnail "thumbnail")
(def ^:icon-id tick "tick")
(def ^:icon-id to-corner "to-corner")
(def ^:icon-id to-curve "to-curve")
(def ^:icon-id tree "tree")
(def ^:icon-id unlock "unlock")
(def ^:icon-id user "user")
(def ^:icon-id vertical-align-items-center "vertical-align-items-center")
(def ^:icon-id vertical-align-items-end "vertical-align-items-end")
(def ^:icon-id vertical-align-items-start "vertical-align-items-start")
(def ^:icon-id view-as-icons "view-as-icons")
(def ^:icon-id view-as-list "view-as-list")
(def ^:icon-id wrap "wrap")
(def icon-list "A collection of all icons" (collect-icons))
(def ^:private icon-size-m 16)
(def ^:private icon-size-s 12)
(mf/defc icon*
{::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})
size-px (cond (= size "s") icon-size-s :else icon-size-m)
offset (/ (- icon-size-m size-px) 2)]
[:> "svg" props
[:use {:href (dm/str "#icon-" icon) :width size-px :height size-px :x offset :y offset}]]))

View file

@ -0,0 +1,101 @@
import { Canvas, Meta } from '@storybook/blocks';
import * as IconStories from "./icon.stories"
<Meta of={IconStories} />
# Iconography
See the [list of all available icons](?path=/story/foundations-icons--all-icons).
## Variants
### Medium (default)
- Used in the majority of the interface, and **it is the default variant**.
- Displayed within a box of 16×16 pixels.
- 1 px stroke (centered).
This is enabled with `size` prop set to `"m"`.
### Small
- Displayed within a box of 16×16 pixels.
- Bigger padding (4 pixels)
- Best used when the space is limited. Use in components such text inputs os in
dense interfaces such layers or chevrons to indicate a collapsible element.
This is enabled with `size` prop set to `"s"`.
## Technical notes
### Using icons IDs
There are icon ID definitions you can use in your code rather than typing the
icon ID by hand.
**Using these IDs is recommended**, since they are invariant to the icon asset
filename.
Assuming the namespace is required as `i`:
```clj
(ns app.main.ui.foo
(:require
[app.main.ui.ds.foundations.icon :as i]))
```
You can now use the icon IDs defined in the namespace:
```clj
[:> i/icon* {:icon i/pin}]
```
### Customizing colors
Icon color is set internally with the `stroke` property and it's set to
`currentColor` by default.
If you need to override this behavior, you can use a `class` in the `<Icon>`
component and set `color` to whatever value you prefer:
```clj
[:> i/icon* {:icon i/add :class (stl/css :toolbar-icon)}]
```
```scss
.toolbar-icon {
color: var(--component-toolbar-icon-color);
}
```
### Accessibility
By default, icons do not have any accessible text attached to them. You should
add an `aria-label` attribute to set a proper text:
```clj
[:> i/icon* {:icon i/add :aria-label (tr "foo.bar")}]
```
## Usage guidelines for design
### Layout
Icon content should remain inside of the live area. In specific icons that need
to adjust visual weight, content may extend into the padding between live area
and trim area, never outside the trim area.
### Color
Icons are normally displayed with the chromatic characteristics of the component
in which they are included. They are normally based on foreground and neutral
colours, but may also, in some cases, be displayed in semantic colours when
their function is to accompany system status messages.
### Accessibility
Icons must meet the contrast requirement.
They should be designed with the correct transmission of the concept they
communicate in mind, reviewing cultural and generational differences to avoid
comprehension problems.

View file

@ -0,0 +1,4 @@
.icon {
fill: none;
stroke: currentColor;
}

View file

@ -0,0 +1,47 @@
import * as React from "react";
import Components from "@target/components";
const { Icon } = Components;
const { StoryWrapper, IconGrid } = Components.storybook;
const { icons } = Components.meta;
export default {
title: "Foundations/Icons",
component: Components.Icon,
};
const iconList = Object.entries(icons)
.map(([_, value]) => value)
.sort();
export const AllIcons = {
render: () => (
<StoryWrapper theme="default">
<h1>All Icons</h1>
<p>Hover on an icon to see its ID</p>
<IconGrid>
{iconList.map((iconId) => (
<div title={iconId} key={iconId}>
<Icon icon={iconId} />
</div>
))}
</IconGrid>
</StoryWrapper>
),
};
export const Default = {
render: () => (
<StoryWrapper theme="default">
<Icon icon="pin" />
</StoryWrapper>
),
};
export const Small = {
render: () => (
<StoryWrapper theme="default">
<Icon icon="pin" size="s" />
</StoryWrapper>
),
};

View file

@ -10,9 +10,17 @@
(:require
[rumext.v2 :as mf]))
(mf/defc story-wrapper
{::mf/wrap-props false}
[{:keys [children]}]
(mf/defc story-wrapper*
{::mf/props :obj}
[{:keys [theme children]}]
[:article {:class (stl/css :story-wrapper)}
[:section {:class "default"} children]
[:section {:class "light"} children]])
(if (some? theme)
[:section {:class theme} children]
[*
[:section {:class "default"} children]
[:section {:class "light"} children]])])
(mf/defc icon-grid*
{::mf/props :obj}
[{:keys [children]}]
[:article {:class (stl/css :icon-grid)} children])

View file

@ -4,3 +4,10 @@
display: grid;
row-gap: 1rem;
}
.icon-grid {
display: grid;
grid-template-columns: repeat(auto-fit, 16px);
gap: 1rem;
color: var(--color-foreground-primary);
}