diff --git a/.changeset/fair-chicken-joke.md b/.changeset/fair-chicken-joke.md new file mode 100644 index 0000000000..68decec3b2 --- /dev/null +++ b/.changeset/fair-chicken-joke.md @@ -0,0 +1,5 @@ +--- +"@stackoverflow/stacks": patch +--- + +feat(sidebar-widget): initial SHINE design changes diff --git a/MIGRATION_GUIDE.md b/MIGRATION_GUIDE.md index c173481b5c..9460843c03 100755 --- a/MIGRATION_GUIDE.md +++ b/MIGRATION_GUIDE.md @@ -139,6 +139,13 @@ The menu component has been updated to use new class names and structure. The fo #### Select - `md` and `xl` sizes removed +#### Sidebar Widget +- `s-sidebarwidget__items` renamed to `s-sidebarwidget--items` and must be nested inside `s-sidebarwidget--content` now +- `s-sidebarwidget--item` is only supported for navigation items now +- `s-sidebarwidget__small-bold-text` class removed +- Table layout support removed +- Expandable sidebar support removed + #### Tags - `.s-tag__xs` removed - `.s-tag__md` removed diff --git a/packages/stacks-classic/lib/components/sidebar-widget/sidebar-widget.less b/packages/stacks-classic/lib/components/sidebar-widget/sidebar-widget.less index 0b0a72efb9..4c5a987b49 100644 --- a/packages/stacks-classic/lib/components/sidebar-widget/sidebar-widget.less +++ b/packages/stacks-classic/lib/components/sidebar-widget/sidebar-widget.less @@ -1,42 +1,13 @@ -.s-sidebarwidget { - // COMPONENT-SPECIFIC CUSTOM PROPERTIES - --_sw-bc: var(--bc-medium); - - // MODIFIERS - &:not(.s-anchors) { - a:not(.button):not(.s-tag):not(.post-tag):not(.s-btn):not(.s-sidebarwidget--action):not(.s-user-card--link) { - &, - &:visited { - color: var(--black-600); - } - } - } +@headings: h1, h2, h3, h4, h5, h6; +.s-sidebarwidget { // VARIANTS .alternate-color(blue); .alternate-color(yellow); .alternate-color(green); // CHILD ELEMENTS - & &--action { - color: var(--blue-400); - font-size: var(--fs-body1); - font-weight: normal; - margin-left: auto; - } - & &--content { - &:not(table) { - &:not(.s-sidebarwidget__items), - &:not(.s-sidebarwidget__block-items) .s-sidebarwidget--item { - display: flex; - } - } - - + .s-sidebarwidget--content { - border-top: var(--su-static1) solid var(--bc-light); - } - &.s-sidebarwidget__items { &, &.s-sidebarwidget__block-items .s-sidebarwidget--item { @@ -50,98 +21,80 @@ outline: none; } + .s-sidebarwidget--action { + font-size: var(--fs-fine); + margin-left: var(--su16); + } - margin: 0; - padding: var(--su16); + display: flex; + padding: calc(var(--su16) + var(--su2)); //18px + font-size: var(--fs-body2); } & &--header { - &:first-child { - border-top: none; + > @{headings} { + margin: 0; + font-size: var(--fs-body1); + font-weight: 600; } - + .s-expandable:not(.is-expanded) { - margin-bottom: var(--su16); + .s-sidebarwidget--action { + margin-left: auto; + font-size: var(--fs-fine); + font-weight: 600; } - &.s-sidebarwidget { - &__expanding-control { - &:before { - border: calc(var(--su-static4) + var(--su-static1)) solid transparent; - border-left-color: var(--black-400); - border-right-width: 0; - content: ''; - float: left; - margin-right: var(--su12); - margin-top: calc(calc(var(--lh-base) * 1em) / 2 - 5px); // 1.3 is our standard line height - transition: transform 0.3s cubic-bezier(0.4, 0.4, 0.6, 1); - } - - &[aria-expanded='true']:before { - transform: rotate(90deg); - } - - cursor: pointer; - } - - &__small-bold-text { - .s-sidebarwidget--action { - font-weight: normal; - line-height: calc(var(--lh-base) * var(--fs-caption)); // line-height should be the same as in the outside element, so the header and action baselines line up - } - - font-size: var(--fs-caption); - font-weight: bold; - } - } + align-items: center; + display: flex; + padding: var(--su16) var(--su16) 0; + } - &:active { - outline: none; + & &--footer { + .s-sidebarwidget--action { + flex: 1; } - - align-items: center; - border-top: var(--su-static1) solid var(--bc-light); - color: var(--black-600); + display: flex; + padding: 0 var(--su16); font-size: var(--fs-body2); - font-weight: bold; - justify-content: flex-start; - line-height: var(--lh-xs); - margin: 0; - padding: var(--su16) var(--su16) 0; } - & &--item { - &, - & > :first-child { - &[aria-current="true"], - &[aria-current="page"] { - &:before { - border-left-color: var(--theme-primary); - border-left-style: solid; - border-left-width: calc(var(--su-static1) * 3); // 3px - content: ''; - height: calc(100% + var(--su16)); - left: 0; - margin-left: var(--sun16); // the orange selection indicator overlaps with the widget border - margin-top: var(--sun8); - position: absolute; - } + & &--items { + .s-sidebarwidget--item { + &, + & > :first-child { + &[aria-current="true"], + &[aria-current="page"] { + &:before { + border-left-color: var(--theme-primary); + border-left-style: solid; + border-left-width: calc(var(--su-static1) * 3); // 3px + content: ''; + height: calc(100% + var(--su16)); + left: 0; + margin-left: var(--sun16); // the orange selection indicator overlaps with the widget border + margin-top: var(--sun8); + position: absolute; + } - a { // TODO: this isn't the best way to go about this. There should be a "is current" highlight without font modification for more complex cases - &, - &:visited { - color: inherit; + a { // TODO: this isn't the best way to go about this. There should be a "is current" highlight without font modification for more complex cases + &, + &:visited { + color: inherit; + } } - } - color: var(--black); - font-weight: bold; - position: relative; + color: var(--black); + font-weight: bold; + position: relative; + } } + + margin: var(--su12) 0; } - margin: var(--su12) 0; + margin: 0; + list-style: none; } & &--subnav { @@ -173,46 +126,16 @@ padding-left: 0; } - & table&--content&__items { - tr.s-sidebarwidget--item { - td { - padding: 0; - } - - display: table-row; - } - - border-collapse: separate; - border-spacing: var(--su16) var(--su12); - padding: var(--su6) 0 0; + & &--action:is(a, button) { + white-space: nowrap; } - background-color: var(--white); - border: var(--su-static1) solid var(--_sw-bc); - border-radius: var(--br-md); font-size: var(--fs-body1); } // COLOR ALTERNATIVES .alternate-color(@name) { &.s-sidebarwidget__@{name} { - --_sw-bc: var(~"--@{name}-300"); - - .highcontrast-mode({ - --_sw-bc: var(~"--@{name}-500"); - }); - - &:after, - .s-sidebarwidget--content + .s-sidebarwidget--content, - .s-sidebarwidget--header { - border-color: var(--_sw-bc); - } - - .s-sidebarwidget--header { - color: var(--fc-medium); - } - background-color: var(~"--@{name}-100"); - border-color: var(--_sw-bc); } } \ No newline at end of file diff --git a/packages/stacks-classic/lib/components/sidebar-widget/sidebar-widget.test.setup.ts b/packages/stacks-classic/lib/components/sidebar-widget/sidebar-widget.test.setup.ts index bffbff3549..29014a3a72 100644 --- a/packages/stacks-classic/lib/components/sidebar-widget/sidebar-widget.test.setup.ts +++ b/packages/stacks-classic/lib/components/sidebar-widget/sidebar-widget.test.setup.ts @@ -1,90 +1,55 @@ import type { TestVariationArgs } from "../../test/test-utils"; +import { IconAward, IconPlus } from "@stackoverflow/stacks-icons/icons"; import "../../index"; const getChild = (child?: string): string => { switch (child) { - case "accordions": - return `
| asked | -4 years, 4 months ago | -
| viewed | -7,437 times | -
| active | -2 months ago | -
- In its simplest form, the sidebar widget is an element with class .s-sidebarwidget and a child of class .s-sidebarwidget--content.
- This sets up a sidebar widget with the appropriate inner spacing, and you can put into it whatever you want.
+ In its simplest form, .s-sidebarwidget is comprised of a .s-sidebarwidget--content section and optional .s-sidebarwidget--header and .s-sidebarwidget--footer sections.
+ Together these classes create a widget with appropriate inner spacing for you to put whatever you want into it.
- By default the content is a flex container. If you require display: block instead, add the d-block class.
-
display: block instead, add the d-block class.
+ Oftentimes, your widget will be a list of similar, relatively simple items. By giving the s-sidebarwidget--content a modifier class s-sidebarwidget__items, and giving the items a class of s-sidebarwidget--item, the content will be spaced out nicely.
In this case, each item is a flex container by default. If you require display: block instead, specifically add the d-block class to the s-sidebarwidget--item, or add the s-sidebarwidget__block-items modifier class to the s-sidebarwidget--content to make the change to all items.
- There is built-in support for table content. The table element should have the classes s-sidebarwidget--content s-sidebarwidget__items, and the tr elements should be s-sidebarwidget--item.
-
- If your items are more complex than that, whitespace may not be enough to separate them clearly. In this case instead of a single s-sidebarwidget--content element with multile items, use multiple s-sidebarwidget--content elements, which will be separated by subtle divider lines.
+ If different sections are required within the body of the sidebar you may use multiple s-sidebarwidget--content elements which will space things appropriately.
- Besides s-sidebarwidget--content, the other possible child class is s-sidebarwidget--header, which unsurprisingly creates a header. Headers can be used both as a title for the widget, as well as to create several sections inside the widget.
-
s-sidebarwidget--header are shown shown added to h2 elements in examples, but the appropriate heading level may differ depending on context. Please use the appropriate heading level for the context to ensure heading levels only increase by 1.
- {% endtip %}
-
- | asked | -4 years, 4 months ago | -
| viewed | -7,437 times | -
| active | -2 months ago | -
| asked | -4 years, 4 months ago | -
| viewed | -7,437 times | -
| active | -2 months ago | -
- The s-sidebarwidget__small-bold-text modifier is available for headers to modify the text appearance.
-
| created | -9 years, 1 month ago | -
| viewed | -88,020 times | -
| active | -3 days ago | -
| editors | -164 | -
- A common use for sidebar widgets is as a navigation block or table of contents, including a highlight of the page that the user is currently looking at. + A common use for sidebar widgets is as a navigation block or table of contents, including a highlight of the page/section that the user is currently looking at.
- The recommended pattern, as shown in the example below, is to make the s-sidebarwidget a nav element, and for each group of links to create a ul with the classes s-sidebarwidget--content s-sidebarwidget__items, within which each li is of class s-sidebarwidget--item.
+ The recommended pattern, as shown in the example below, is to make the s-sidebarwidget a nav element, and for each group of links to create a ul with the class s-sidebarwidget--items, within which each li is of class s-sidebarwidget--item.
The currently active navigation item should have the aria-current attribute set to "page" (if it is a direct link to the very page that the user is looking at) or "true" (in all other cases, e.g. if it is a link to a page that is conceptually a parent or the current page). This aria-current attribute should be placed on the a element.
@@ -359,58 +232,79 @@
- If you have a second level of navigation, you can add a ul of class -subnav to the top-level item. Highlighting the currently active navigation is a little more constrained in this case:
+ If you have a second level of navigation, you can add a ul of class s-sidebarwidget--subnav to the top-level item. Highlighting the currently active navigation is a little more constrained in this case:
If the currently active top-level element has a subnavigation, the top-level aria-current must be on the a, not the li.
@@ -422,254 +316,75 @@
- There is often a need for a header to contain a link or link-like clickable that refers to the whole widget or to the section that this header starts. We call this an “action link”, and it’s created by adding the class s-sidebarwidget--action.
-
- This link must come before the header text, otherwise it will not be placed correctly should the header ever wrap to multiple lines. -
- -| 64 | -remote jobs | -
| 238 | -- jobs in Berlin, Deutschland (within 20 km) - | -
- In order to create an accordion, i.e. to make part of the sidebar widget expandable / collapsible, you can make use of the s-expandable component.
-
The s-sidebarwidget-header element that controls the accordion needs a modifier class of s-sidebarwidget__expanding-control in order to display the expander arrow. Beyond that, it needs all the attributes as described for the controlling button in the expandable documentation.
The (one or more) content elements that are meant to be collapsed must be wrapped in the s-expandable element; inside this wrapper element there is the s-expandable--content. This can be the same element as the s-sidebarwidget--content element (if there’s only one content element that is meant to be collapsed), or it can be an additional wrapper element around the content element(s).
| … | -- remote jobs - | -
| … | -- … - | -
| 64 | -remote jobs | -
| 238 | -jobs in Berlin, Deutschland (within 20 km) | -