From e6856bf5617200841073c10da04e8edf63f35c33 Mon Sep 17 00:00:00 2001 From: Josh Winn <965114+jawinn@users.noreply.github.com> Date: Mon, 9 Dec 2024 14:06:13 -0500 Subject: [PATCH 01/28] feat(appframe): beginning of new component layout and styles Initial markup and prototyping for the overall app frame layout. --- components/appframe/README.md | 7 + components/appframe/index.css | 158 ++++++++++++++++++ components/appframe/package.json | 42 +++++ components/appframe/project.json | 16 ++ .../appframe/stories/appframe.stories.js | 38 +++++ components/appframe/stories/template.js | 108 ++++++++++++ components/appframe/themes/express.css | 15 ++ components/appframe/themes/spectrum.css | 13 ++ yarn.lock | 12 ++ 9 files changed, 409 insertions(+) create mode 100644 components/appframe/README.md create mode 100644 components/appframe/index.css create mode 100644 components/appframe/package.json create mode 100644 components/appframe/project.json create mode 100644 components/appframe/stories/appframe.stories.js create mode 100644 components/appframe/stories/template.js create mode 100644 components/appframe/themes/express.css create mode 100644 components/appframe/themes/spectrum.css diff --git a/components/appframe/README.md b/components/appframe/README.md new file mode 100644 index 00000000000..b598e7cdebf --- /dev/null +++ b/components/appframe/README.md @@ -0,0 +1,7 @@ +# @spectrum-css/appframe + +> The Spectrum CSS app frame component + +This package is part of the [Spectrum CSS project](https://github.com/adobe/spectrum-css). + +See the [Spectrum CSS documentation](https://opensource.adobe.com/spectrum-css/appframe). diff --git a/components/appframe/index.css b/components/appframe/index.css new file mode 100644 index 00000000000..9ab9bfbc3a4 --- /dev/null +++ b/components/appframe/index.css @@ -0,0 +1,158 @@ +/*! +Copyright 2023 Adobe. All rights reserved. +This file is licensed to you under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. You may obtain a copy +of the License at http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software distributed under +the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS +OF ANY KIND, either express or implied. See the License for the specific language +governing permissions and limitations under the License. +*/ + +.spectrum-AppFrame { + --spectrum-app-frame-background: var(--spectrum-background-layer-1-color); + --spectrum-app-frame-content-background: var(--spectrum-background-base-color); + --spectrum-app-frame-intro-background: linear-gradient(93.59deg, #ffeccf 0%, #ffa213 63%, #ff709f 100%); + + --spectrum-app-frame-content-corner-radius: var(--spectrum-corner-radius-extra-large-default); + + --spectrum-app-frame-section-gap: var(--spectrum-spacing-200); + --spectrum-app-frame-to-edge: var(--spectrum-spacing-200); + --spectrum-app-frame-section-padding: var(--spectrum-spacing-400) var(--spectrum-spacing-600) var(--spectrum-spacing-600); + + --spectrum-header-height: var(--spectrum-component-height-400); + --spectrum-app-frame-side-nav-minimum-inline-size: var(--spectrum-component-height-400); + + --spectrum-app-frame-section-grid-gap: var(--spectrum-spacing-300); + --spectrum-app-frame-section-heading-margin-block: 0px var(--spectrum-spacing-400); + --spectrum-app-frame-section-inner-area-vertical-gap: var(--spectrum-spacing-600); + + /* To-do: not sure about the best way to include this limit and where to apply. */ + --spectrum-app-frame-max-readable-characters: 80ch; + + /* To-do: For demo purposes only; would not convert to SWC. They would need a way of providing different gradients for light/dark. */ + .spectrum--dark & { + --spectrum-app-frame-intro-background: linear-gradient(94.13deg, #003041 0%, #03638c 100%); + } +} + +.spectrum-AppFrame { + --spectrum-app-frame-start-side-column-inline-size: minmax(var(--spectrum-app-frame-side-nav-minimum-inline-size), max-content); + --spectrum-app-frame-end-side-column-inline-size: var(--spectrum-app-frame-to-edge); + + background: var(--highcontrast-app-frame-background, var(--mod-app-frame-background, var(--spectrum-app-frame-background))); + inline-size: 100%; + block-size: 100vh; + position: relative; + display: grid; + grid-template-areas: + "head head head" + "side main endside"; + grid-template-rows: var(--mod-header-height, var(--spectrum-header-height)) 1fr; + grid-template-columns: var(--spectrum-app-frame-start-side-column-inline-size) 1fr var(--spectrum-app-frame-end-side-column-inline-size); +} + +.spectrum-AppFrame--noSideNav { + grid-template-columns: var(--spectrum-app-frame-to-edge) 1fr var(--spectrum-app-frame-to-edge); +} + +.spectrum-AppFrame-header { + grid-area: head; +} + +.spectrum-AppFrame-side-nav { + grid-area: side; +} + +/* Main scrollable content area */ +.spectrum-AppFrame-content { + grid-area: main; + block-size: 100%; + border-radius: var(--mod-app-frame-content-corner-radius, var(--spectrum-app-frame-content-corner-radius) var(--spectrum-app-frame-content-corner-radius) 0 0); + overflow: auto; + position: relative; + container-type: size; + container-name: app-frame-content; +} + +/* The use of a main element keeps an option for it to have a document level footer element or another aside. */ +.spectrum-AppFrame-content > main { + min-block-size: 100%; + display: grid; + grid-template-rows: max-content 1fr; +} + +/* Sections within the content area */ +.spectrum-AppFrame-section { + background: var(--highcontrast-app-frame-content-background, var(--mod-app-frame-content-background, var(--spectrum-app-frame-content-background))); + border-radius: var(--mod-app-frame-content-corner-radius, var(--spectrum-app-frame-content-corner-radius)); + padding: var(--mod-app-frame-section-padding, var(--spectrum-app-frame-section-padding)); + + + .spectrum-AppFrame-section { + margin-block-start: var(--spectrum-app-frame-section-gap); + } +} + +.spectrum-AppFrame-content .spectrum-AppFrame-section:last-of-type { + border-radius: var(--mod-app-frame-content-corner-radius, var(--spectrum-app-frame-content-corner-radius)) 0; +} + +/* To-do: option for rounded at the bottom content when it is not scrolling. May be an option or require JS for application. */ +.spectrum-AppFrame-content--rounded { + > main { + min-block-size: calc(100% - var(--spectrum-app-frame-to-edge, 0px)); + } +} + +/* Section heading */ +.spectrum-AppFrame-section .spectrum-AppFrame-section-heading { + margin-block: var(--spectrum-app-frame-section-heading-margin-block); + max-inline-size: var(--mod-app-frame-max-readable-characters, var(--spectrum-app-frame-max-readable-characters)); +} + +/* Section inner area; area nested within a section that is spaced out and typically has a section heading within it. */ +.spectrum-AppFrame-section-inner:not(:last-child) { + margin-block-end: var(--mod-app-frame-section-inner-area-vertical-gap, var(--spectrum-app-frame-section-inner-area-vertical-gap)); +} + +/* To-do: not sure about the best selector to apply this limit to. */ +.spectrum-AppFrame-section-inner > .spectrum-Heading, +.spectrum-AppFrame-section-inner > .spectrum-Body { + max-inline-size: var(--mod-app-frame-max-readable-characters, var(--spectrum-app-frame-max-readable-characters)); +} + +/* Featured or onboarding intro section with with branded background */ +.spectrum-AppFrame-content-intro { + background: var(--mod-app-frame-intro-background, var(--spectrum-app-frame-intro-background)); +} + +/* Inner grid that can be used for landing page sections. */ +.spectrum-AppFrame-section-grid { + display: grid; + padding: 0; + margin: 0; + + /* To-do: not sure about the intended responsiveness, and this should be moddable. */ + grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); + gap: var(--mod-app-frame-section-grid-gap, var(--spectrum-app-frame-section-grid-gap)); + + &:is(ul) { + list-style-type: none; + } +} + +/* To-do: not sure about the intended responsiveness, and would ideally use a calculatd min-width with tokens. */ +@container (min-width: 700px) { + .spectrum-AppFrame-section-grid > .spectrum-AppFrame-section-grid-item--wide { + grid-column: span 2; + } +} + +/* To-do: probably want some borders present on some containers for high contrast mode only. */ +@media (forced-colors: active) { + .spectrum-AppFrame { + --highcontrast-app-frame-background: Canvas; + --highcontrast-app-frame-content-background: Canvas; + } +} diff --git a/components/appframe/package.json b/components/appframe/package.json new file mode 100644 index 00000000000..eae90040b94 --- /dev/null +++ b/components/appframe/package.json @@ -0,0 +1,42 @@ +{ + "name": "@spectrum-css/appframe", + "version": "0.1.0", + "description": "The Spectrum CSS app frame component", + "license": "Apache-2.0", + "author": "Adobe", + "homepage": "https://opensource.adobe.com/spectrum-css/", + "repository": { + "type": "git", + "url": "https://github.com/adobe/spectrum-css.git", + "directory": "components/appframe" + }, + "bugs": { + "url": "https://github.com/adobe/spectrum-css/issues" + }, + "main": "dist/index.css", + "files": [ + "dist/*", + "CHANGELOG.md", + "package.json", + "stories/template.js", + "metadata/mods.md" + ], + "peerDependencies": { + "@spectrum-css/tokens": "^14.0.0-next.9", + "@spectrum-css/typography": ">=6" + }, + "peerDependenciesMeta": { + "@spectrum-css/typography": { + "optional": true + } + }, + "keywords": [ + "spectrum", + "css", + "design system", + "adobe" + ], + "publishConfig": { + "access": "public" + } +} diff --git a/components/appframe/project.json b/components/appframe/project.json new file mode 100644 index 00000000000..2e7ac3d4cc3 --- /dev/null +++ b/components/appframe/project.json @@ -0,0 +1,16 @@ +{ + "$schema": "../../node_modules/nx/schemas/project-schema.json", + "name": "appframe", + "tags": ["component"], + "targets": { + "build": {}, + "clean": {}, + "compare": {}, + "format": {}, + "lint": {}, + "test": { + "defaultConfiguration": "scope" + }, + "validate": {} + } +} diff --git a/components/appframe/stories/appframe.stories.js b/components/appframe/stories/appframe.stories.js new file mode 100644 index 00000000000..5b02384811c --- /dev/null +++ b/components/appframe/stories/appframe.stories.js @@ -0,0 +1,38 @@ + +import { Template } from "./template.js"; + +/** + * The app frame component is a starting point for an app's overall layout. It contains the header, side navigation, and main content area. + * + * ⚠️ This is currently an early prototype based on a draft version of design specs. + */ +export default { + title: "Components/App frame", + component: "AppFrame", + argTypes: { + hasSideNavigation: { + name: "Has side navigation", + type: { name: "boolean" }, + defaultValue: true, + table: { + type: { summary: "boolean" }, + category: "Component", + defaultValue: { summary: "true" } + }, + control: "boolean", + }, + }, + args: { + rootClass: "spectrum-AppFrame", + hasSideNavigation: true, + }, + parameters: { + layout: "fullscreen", + }, +}; + +/** + * Default, with side navigation + */ +export const Default = Template.bind({}); +Default.args = {}; diff --git a/components/appframe/stories/template.js b/components/appframe/stories/template.js new file mode 100644 index 00000000000..98a89bc3a59 --- /dev/null +++ b/components/appframe/stories/template.js @@ -0,0 +1,108 @@ +import { Template as Typography } from "@spectrum-css/typography/stories/template.js"; +import { html } from "lit"; +import { classMap } from "lit/directives/class-map.js"; +import { ifDefined } from "lit/directives/if-defined.js"; +import { styleMap } from "lit/directives/style-map.js"; + +import "@spectrum-css/appframe/index.css"; + +// Example only emphasized container +const emphasizedContainerStyles = { + background: "var(--spectrum-background-layer-1-color)", + boxShadow: "var(--spectrum-drop-shadow-emphasized-default-x) var(--spectrum-drop-shadow-emphasized-default-y) var(--spectrum-drop-shadow-emphasized-default-blur) var(--spectrum-drop-shadow-emphasized-default-color)", + minHeight: "200px", + borderRadius: "var(--spectrum-corner-radius-extra-large-default)", +}; + +export const Template = ({ + rootClass = "spectrum-AppFrame", + hasSideNavigation = true, + id, + customClasses = [], + customStyles = {}, +}) => html` +
({ ...a, [c]: true }), {}), + })} + id=${ifDefined(id)} + style=${ifDefined(styleMap(customStyles))} + > +
+ +
+
+
+
+

Welcome to Example App, Frodo

+
+
+ ${Array.from({length: 3}, () => + html`
` + )} +
+
+
+
+
+ ${Typography({ + semantics: "heading", + size: "m", + content: ["Start something new"], + customClasses: ["spectrum-AppFrame-section-heading"], + })} +
+
+ ${Array.from({length: 3}, () => + html`
` + )} +
+
+
+ ${Typography({ + semantics: "heading", + size: "m", + content: ["Recent files"], + customClasses: ["spectrum-AppFrame-section-heading"], + })} +
    + ${Array.from({length: 20}, () => + html`
  • ` + )} +
+
+
+ ${Typography({ + semantics: "heading", + size: "m", + content: ["Another example inner area within a section"], + customClasses: ["spectrum-AppFrame-section-heading"], + })} + ${Typography({ + semantics: "body", + size: "m", + content: ["Lorem ipsum odor amet, consectetuer adipiscing elit. Imperdiet suscipit convallis cubilia etiam taciti nascetur ad. Eros parturient molestie curabitur dui risus arcu. Luctus dictum in ultricies nisl dolor parturient mus. Lorem ipsum odor amet, consectetuer adipiscing elit."], + })} + ${Typography({ + semantics: "body", + size: "m", + content: ["Pretium adipiscing felis facilisi sem primis primis scelerisque placerat. Facilisi mus curabitur rutrum mus, velit quisque neque vitae tempor. Efficitur mauris pharetra lectus pulvinar pulvinar sociosqu feugiat sociosqu mi. Efficitur dis est mattis interdum fermentum potenti ligula efficitur. Montes per ligula tempus aliquet tortor nam magnis nibh. Mi venenatis risus magnis nec elit eget aenean purus."], + })} + ${Typography({ + semantics: "body", + size: "m", + content: ["Nec venenatis dapibus dictum laoreet litora, pulvinar pretium mi. Accumsan eget erat euismod; nullam egestas porttitor imperdiet odio. Rhoncus gravida metus platea maecenas eleifend. Maximus dictum quis orci vehicula hac euismod lorem arcu. Velit fames fermentum montes fusce consectetur finibus diam. Ex fames eros a habitant urna molestie. Sit congue porttitor proin facilisi consectetur litora facilisi. Aliquam maecenas feugiat mi integer erat. Molestie gravida augue dapibus aenean purus maximus facilisis venenatis metus."], + })} + ${Typography({ + semantics: "body", + size: "m", + content: ["Lorem ipsum odor amet, consectetuer adipiscing elit. Imperdiet suscipit convallis cubilia etiam taciti nascetur ad. Eros parturient molestie curabitur dui risus arcu. Luctus dictum in ultricies nisl dolor parturient mus. Lorem ipsum odor amet, consectetuer adipiscing elit."], + })} +
+
+
+
+
+`; diff --git a/components/appframe/themes/express.css b/components/appframe/themes/express.css new file mode 100644 index 00000000000..4baa0fb770e --- /dev/null +++ b/components/appframe/themes/express.css @@ -0,0 +1,15 @@ +/*! +Copyright 2023 Adobe. All rights reserved. +This file is licensed to you under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. You may obtain a copy +of the License at http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software distributed under +the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS +OF ANY KIND, either express or implied. See the License for the specific language +governing permissions and limitations under the License. +*/ + +@import "./spectrum.css"; + +@container (--system: express) {} diff --git a/components/appframe/themes/spectrum.css b/components/appframe/themes/spectrum.css new file mode 100644 index 00000000000..d963d64ba60 --- /dev/null +++ b/components/appframe/themes/spectrum.css @@ -0,0 +1,13 @@ +/*! +Copyright 2023 Adobe. All rights reserved. +This file is licensed to you under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. You may obtain a copy +of the License at http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software distributed under +the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS +OF ANY KIND, either express or implied. See the License for the specific language +governing permissions and limitations under the License. +*/ + +@container (--system: spectrum) {} diff --git a/yarn.lock b/yarn.lock index 94b89c2cf16..6598c46775f 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4176,6 +4176,18 @@ __metadata: languageName: unknown linkType: soft +"@spectrum-css/appframe@workspace:components/appframe": + version: 0.0.0-use.local + resolution: "@spectrum-css/appframe@workspace:components/appframe" + peerDependencies: + "@spectrum-css/tokens": ^14.0.0-next.9 + "@spectrum-css/typography": ">=6" + peerDependenciesMeta: + "@spectrum-css/typography": + optional: true + languageName: unknown + linkType: soft + "@spectrum-css/asset@npm:8.0.0-next.0, @spectrum-css/asset@workspace:components/asset": version: 0.0.0-use.local resolution: "@spectrum-css/asset@workspace:components/asset" From 23fe58ec4c035b497a43b2f87e42bef9bcfc741c Mon Sep 17 00:00:00 2001 From: Josh Winn <965114+jawinn@users.noreply.github.com> Date: Mon, 9 Dec 2024 17:24:47 -0500 Subject: [PATCH 02/28] feat(appframesidenav): initial setup of new component Newly created alpha version of component. A work in progress based on a draft spec. --- components/appframesidenav/README.md | 7 + components/appframesidenav/index.css | 135 ++++++++++++++++++ components/appframesidenav/package.json | 37 +++++ components/appframesidenav/project.json | 16 +++ .../stories/appframesidenav.stories.js | 63 ++++++++ .../appframesidenav/stories/template.js | 115 +++++++++++++++ components/appframesidenav/themes/express.css | 15 ++ .../appframesidenav/themes/spectrum.css | 13 ++ yarn.lock | 9 ++ 9 files changed, 410 insertions(+) create mode 100644 components/appframesidenav/README.md create mode 100644 components/appframesidenav/index.css create mode 100644 components/appframesidenav/package.json create mode 100644 components/appframesidenav/project.json create mode 100644 components/appframesidenav/stories/appframesidenav.stories.js create mode 100644 components/appframesidenav/stories/template.js create mode 100644 components/appframesidenav/themes/express.css create mode 100644 components/appframesidenav/themes/spectrum.css diff --git a/components/appframesidenav/README.md b/components/appframesidenav/README.md new file mode 100644 index 00000000000..de9c4ce0f35 --- /dev/null +++ b/components/appframesidenav/README.md @@ -0,0 +1,7 @@ +# @spectrum-css/appframesidenav + +> The Spectrum CSS app frame side nav component + +This package is part of the [Spectrum CSS project](https://github.com/adobe/spectrum-css). + +See the [Spectrum CSS documentation](https://opensource.adobe.com/spectrum-css/appframesidenav). diff --git a/components/appframesidenav/index.css b/components/appframesidenav/index.css new file mode 100644 index 00000000000..e8cb9c20849 --- /dev/null +++ b/components/appframesidenav/index.css @@ -0,0 +1,135 @@ +/*! +Copyright 2023 Adobe. All rights reserved. +This file is licensed to you under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. You may obtain a copy +of the License at http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software distributed under +the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS +OF ANY KIND, either express or implied. See the License for the specific language +governing permissions and limitations under the License. +*/ + +.spectrum-AppFrameSideNav { + --spectrum-app-side-nav-min-inline-size: 140px; + --spectrum-app-side-nav-padding: var(--spectrum-spacing-200); + --spectrum-app-side-nav-item-gap: var(--spectrum-spacing-100); + --spectrum-app-side-nav-top-button-to-items: var(--spectrum-spacing-300); + --spectrum-app-side-nav-items-to-end-section: var(--spectrum-spacing-300); + --spectrum-app-side-nav-label-padding-block: var(--spectrum-component-top-to-text-100) var(--spectrum-component-bottom-to-text-100); + --spectrum-app-side-nav-label-padding-inline: var(--spectrum-spacing-100); + + --spectrum-app-side-nav-line-height: var(--spectrum-line-height-100); + --spectrum-app-side-nav-font-family: var(--spectrum-sans-font-family-stack); + --spectrum-app-side-nav-font-weight: var(--spectrum-medium-font-weight); + --spectrum-app-side-nav-font-style: var(--spectrum-default-font-style); + --spectrum-app-side-nav-font-size: var(--spectrum-font-size-100); + + --spectrum-app-side-nav-content-color: var(--spectrum-neutral-content-color-default); + --spectrum-app-side-nav-icon-color: var(--spectrum-neutral-content-color-default); + --spectrum-app-side-nav-focus-indicator-color: var(--spectrum-focus-indicator-color); + --spectrum-app-side-nav-icon-background-default: transparent; + --spectrum-app-side-nav-icon-background-focus: var(--spectrum-gray-200); + + --spectrum-app-side-nav-icon-background-current: #292929; + --spectrum-app-side-nav-icon-color-current: var(--spectrum-white); + + &:lang(ja), + &:lang(zh), + &:lang(ko) { + --spectrum-app-side-nav-line-height: var(--spectrum-cjk-line-height-100); + } + + /* To-do: For demo purposes only; would not convert to SWC. Would need a token. This large scale number is also a guesstimate. */ + .spectrum--large & { + --spectrum-app-side-nav-min-inline-size: 160px; + } +} + +.spectrum-AppFrameSideNav--condensed { + --spectrum-app-side-nav-min-inline-size: var(--spectrum-component-height-400); +} + +.spectrum-AppFrameSideNav { + --_spectrum-app-side-nav-icon-background: var(--spectrum-app-side-nav-icon-background-default); + --_spectrum-app-side-nav-icon-color: var(--spectrum-app-side-nav-icon-color); + + box-sizing: border-box; + margin: 0; + padding: var(--spectrum-app-side-nav-padding); + + /* To-do: we may want to set inline-size instead, or both min-inline-size and max-inline-size, depending on how we want this to respond to the width of the content. */ + min-inline-size: var(--spectrum-app-side-nav-min-inline-size); +} + +.spectrum-AppFrameSideNav .spectrum-AppFrameSideNav-button { + margin-block-end: var(--spectrum-app-side-nav-top-button-to-items); +} + +.spectrum-AppFrameSideNav-list { + list-style-type: none; + margin: 0; + padding: 0; + box-sizing: border-box; + + display: grid; + gap: var(--spectrum-app-side-nav-item-gap); + line-height: var(--spectrum-app-side-nav-line-height); + + color: var(--spectrum-app-side-nav-content-color); + font-family: var(--spectrum-app-side-nav-font-family); + font-weight: var(--spectrum-app-side-nav-font-weight); + font-style: var(--spectrum-app-side-nav-font-style); + font-size: var(--spectrum-app-side-nav-font-size); +} + +.spectrum-AppFrameSideNav-list-item { + display: block; +} + +.spectrum-AppFrameSideNav-list-item-icon { + inline-size: var(--spectrum-component-height-100); + block-size: var(--spectrum-component-height-100); + border-radius: 6px; + display: flex; + align-items: center; + justify-content: center; + background: var(--_spectrum-app-side-nav-icon-background); + color: var(--_spectrum-app-side-nav-icon-color); +} + +.spectrum-AppFrameSideNav-list-item-link { + display: flex; + flex-direction: row; + flex-wrap: nowrap; + + text-decoration: none; + outline: none; + color: var(--spectrum-app-side-nav-content-color); + + &:focus-visible { + outline: 2px solid var(--spectrum-app-side-nav-focus-indicator-color); + outline-offset: 2px; + border-radius: 6px; + } + + &:focus-visible, + &:active, + &:hover { + --_spectrum-app-side-nav-icon-background: var(--spectrum-app-side-nav-icon-background-focus); + } + + .spectrum-AppFrameSideNav-list-item.spectrum-AppFrameSideNav-list-item--current & { + --_spectrum-app-side-nav-icon-background: var(--spectrum-app-side-nav-icon-background-current); + --_spectrum-app-side-nav-icon-color: var(--spectrum-app-side-nav-icon-color-current); + } +} + +.spectrum-AppFrameSideNav-list-item-label { + padding-block: var(--spectrum-app-side-nav-label-padding-block); + padding-inline: var(--spectrum-app-side-nav-label-padding-inline); +} + +.spectrum-AppFrameSideNav--condensed .spectrum-AppFrameSideNav-list-item-label { + display: none; +} diff --git a/components/appframesidenav/package.json b/components/appframesidenav/package.json new file mode 100644 index 00000000000..0daeb4060bd --- /dev/null +++ b/components/appframesidenav/package.json @@ -0,0 +1,37 @@ +{ + "name": "@spectrum-css/appframesidenav", + "version": "0.1.0", + "description": "The Spectrum CSS app frame side nav component", + "license": "Apache-2.0", + "author": "Adobe", + "homepage": "https://opensource.adobe.com/spectrum-css/appframesidenav", + "repository": { + "type": "git", + "url": "https://github.com/adobe/spectrum-css.git", + "directory": "components/appframesidenav" + }, + "bugs": { + "url": "https://github.com/adobe/spectrum-css/issues" + }, + "main": "dist/index.css", + "files": [ + "dist/*", + "CHANGELOG.md", + "package.json", + "stories/template.js", + "metadata/mods.md" + ], + "peerDependencies": { + "@spectrum-css/icon": ">=7", + "@spectrum-css/tokens": "^14.0.0-next.9" + }, + "keywords": [ + "spectrum", + "css", + "design system", + "adobe" + ], + "publishConfig": { + "access": "public" + } +} diff --git a/components/appframesidenav/project.json b/components/appframesidenav/project.json new file mode 100644 index 00000000000..a15d158a37c --- /dev/null +++ b/components/appframesidenav/project.json @@ -0,0 +1,16 @@ +{ + "$schema": "../../node_modules/nx/schemas/project-schema.json", + "name": "appframesidenav", + "tags": ["component"], + "targets": { + "build": {}, + "clean": {}, + "compare": {}, + "format": {}, + "lint": {}, + "test": { + "defaultConfiguration": "scope" + }, + "validate": {} + } +} diff --git a/components/appframesidenav/stories/appframesidenav.stories.js b/components/appframesidenav/stories/appframesidenav.stories.js new file mode 100644 index 00000000000..4ba012ae08b --- /dev/null +++ b/components/appframesidenav/stories/appframesidenav.stories.js @@ -0,0 +1,63 @@ +import { Template, defaultSideNavItems } from "./template.js"; + +/** + * The app frame side navigation has a series of navigation items with an icon and a text label and can be + * viewed expanded or collapsed with icons only. It has an option for a button above the navigation items, + * and for some navigation item(s) to be displayed at the vertical end. + */ +export default { + title: "Components/App frame side nav", + component: "App frame side nav", + argTypes: { + isCondensed: { + name: "Condensed (icons only)", + description: "Displays a horizontally condensed version of the side nav menu items where only the icon is visible.", + table: { + type: { summary: "boolean" }, + defaultValue: { summary: false }, + category: "Component", + }, + type: { required: true }, + control: "boolean", + }, + showTopButton: { + name: "Show top button", + description: "Displays a button above the navigation items.", + table: { + type: { summary: "boolean" }, + defaultValue: { summary: true }, + category: "Component", + }, + type: { required: true }, + control: "boolean", + }, + topButtonText: { + name: "Top button label text", + type: { name: "string" }, + table: { + type: { summary: "string" }, + category: "Content", + }, + control: "text", + }, + items: { + name: "Navigation items", + description: "Array of objects with `label` and `workflowIconName`. Optionally `isCurrent` marks the current page.", + table: { + category: "Content", + }, + type: { required: true }, + control: "object", + }, + }, + args: { + rootClass: "spectrum-AppFrameSideNav", + showTopButton: true, + topButtonText: "Create", + items: defaultSideNavItems, + isCondensed: false, + }, +}; + +export const Default = Template.bind({}); +Default.args = {}; diff --git a/components/appframesidenav/stories/template.js b/components/appframesidenav/stories/template.js new file mode 100644 index 00000000000..27cfb10ceaf --- /dev/null +++ b/components/appframesidenav/stories/template.js @@ -0,0 +1,115 @@ +import { Template as Button } from "@spectrum-css/button/stories/template.js"; +import { html, svg } from "lit"; +import { classMap } from "lit/directives/class-map.js"; +import { ifDefined } from "lit/directives/if-defined.js"; +import { styleMap } from "lit/directives/style-map.js"; +import { when } from "lit/directives/when.js"; + +import "@spectrum-css/appframesidenav/index.css"; + +export const Template = ({ + rootClass = "spectrum-AppFrameSideNav", + showTopButton = true, + topButtonText = "Create", + topButtonWorkflowIconName = "Add", + items = defaultSideNavItems, + isCondensed = false, + id, + customClasses = [], + customStyles = {}, +}) => html` + +`; + +/** + * Data for the side navigation items. + * Array of objects with `label` and `workflowIconName`. + * Optionally: + * - `isCurrent` marks the current page. + * - `isEndSection` marks the nav item that should be aligned at the bottom "end section". + */ +export const defaultSideNavItems = [ + { + label: "Home", + isCurrent: true, + workflowIconName: "Home", + }, + { + label: "Files", + workflowIconName: "Folder", + }, + { + label: "Brands", + workflowIconName: "Brand", + }, + { + label: "Discover", + workflowIconName: "Discover", + }, + { + label: "Schedule", + workflowIconName: "Calendar", + }, + { + label: "Learn", + workflowIconName: "Lightbulb", + }, + { + label: "Plugins", + workflowIconName: "Plugin", + }, + { + label: "Settings", + workflowIconName: "Settings", + isEndSection: true, + }, +]; + +/** + * This temporarily contains the SVG markup for the S2 icon names used in this prototype. + * + * To-do: Replace testing SVGs with Icon() component template using navItem.workflowIconName once S2 icons are in use on this branch. + */ +const tempSpectrum2Icons = { + Home: svg``, + Folder: svg``, + Brand: svg``, + Discover: svg``, + Calendar: svg``, + Plugin: svg``, + Lightbulb: svg``, + Settings: svg``, +}; diff --git a/components/appframesidenav/themes/express.css b/components/appframesidenav/themes/express.css new file mode 100644 index 00000000000..4baa0fb770e --- /dev/null +++ b/components/appframesidenav/themes/express.css @@ -0,0 +1,15 @@ +/*! +Copyright 2023 Adobe. All rights reserved. +This file is licensed to you under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. You may obtain a copy +of the License at http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software distributed under +the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS +OF ANY KIND, either express or implied. See the License for the specific language +governing permissions and limitations under the License. +*/ + +@import "./spectrum.css"; + +@container (--system: express) {} diff --git a/components/appframesidenav/themes/spectrum.css b/components/appframesidenav/themes/spectrum.css new file mode 100644 index 00000000000..d963d64ba60 --- /dev/null +++ b/components/appframesidenav/themes/spectrum.css @@ -0,0 +1,13 @@ +/*! +Copyright 2023 Adobe. All rights reserved. +This file is licensed to you under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. You may obtain a copy +of the License at http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software distributed under +the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS +OF ANY KIND, either express or implied. See the License for the specific language +governing permissions and limitations under the License. +*/ + +@container (--system: spectrum) {} diff --git a/yarn.lock b/yarn.lock index 6598c46775f..abe75abc0a8 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4188,6 +4188,15 @@ __metadata: languageName: unknown linkType: soft +"@spectrum-css/appframesidenav@workspace:components/appframesidenav": + version: 0.0.0-use.local + resolution: "@spectrum-css/appframesidenav@workspace:components/appframesidenav" + peerDependencies: + "@spectrum-css/icon": ">=7" + "@spectrum-css/tokens": ^14.0.0-next.9 + languageName: unknown + linkType: soft + "@spectrum-css/asset@npm:8.0.0-next.0, @spectrum-css/asset@workspace:components/asset": version: 0.0.0-use.local resolution: "@spectrum-css/asset@workspace:components/asset" From 95690e731300f78ea71287b3804c3ec85c84bb25 Mon Sep 17 00:00:00 2001 From: Josh Winn <965114+jawinn@users.noreply.github.com> Date: Fri, 13 Dec 2024 14:50:27 -0500 Subject: [PATCH 03/28] feat(appframe): use app frame side nav template Use newly created appframesidenav component within the template, along with some other minor adjustments. --- components/appframe/index.css | 12 +- .../appframe/stories/appframe.stories.js | 14 +- components/appframe/stories/template.js | 176 +++++++++--------- 3 files changed, 113 insertions(+), 89 deletions(-) diff --git a/components/appframe/index.css b/components/appframe/index.css index 9ab9bfbc3a4..33e07acdb23 100644 --- a/components/appframe/index.css +++ b/components/appframe/index.css @@ -22,7 +22,9 @@ governing permissions and limitations under the License. --spectrum-app-frame-section-padding: var(--spectrum-spacing-400) var(--spectrum-spacing-600) var(--spectrum-spacing-600); --spectrum-header-height: var(--spectrum-component-height-400); - --spectrum-app-frame-side-nav-minimum-inline-size: var(--spectrum-component-height-400); + + --spectrum-app-frame-start-side-column-inline-size: minmax(var(--spectrum-component-height-400), max-content); + --spectrum-app-frame-end-side-column-inline-size: var(--spectrum-app-frame-to-edge); --spectrum-app-frame-section-grid-gap: var(--spectrum-spacing-300); --spectrum-app-frame-section-heading-margin-block: 0px var(--spectrum-spacing-400); @@ -38,9 +40,6 @@ governing permissions and limitations under the License. } .spectrum-AppFrame { - --spectrum-app-frame-start-side-column-inline-size: minmax(var(--spectrum-app-frame-side-nav-minimum-inline-size), max-content); - --spectrum-app-frame-end-side-column-inline-size: var(--spectrum-app-frame-to-edge); - background: var(--highcontrast-app-frame-background, var(--mod-app-frame-background, var(--spectrum-app-frame-background))); inline-size: 100%; block-size: 100vh; @@ -76,7 +75,10 @@ governing permissions and limitations under the License. container-name: app-frame-content; } -/* The use of a main element keeps an option for it to have a document level footer element or another aside. */ +/** + * The use of a main element keeps an option for it to have a document level