From aa1ca65e7c9807c6d6020e39166536297fe1cdae Mon Sep 17 00:00:00 2001 From: Armand Philippot Date: Sat, 15 Jan 2022 22:45:57 +0100 Subject: chore: update sidebar and widgets styles I'm now using a widget that can be expanded/collapsed. It also allows me to handle more effectively widgets overflow and to avoid styles repetitions. However, with stylelint rule "no-descending-specificity", I'm not sure if the stylesheets are really logical... Maybe I should deactivate this rule. --- .../ExpandableWidget/ExpandableWidget.module.scss | 146 +++++++++++++++++++++ .../ExpandableWidget/ExpandableWidget.tsx | 47 +++++++ src/components/WidgetParts/List/List.module.scss | 47 +++++++ src/components/WidgetParts/List/List.tsx | 7 + .../OrderedList/OrderedList.module.scss | 66 ++++++++++ .../WidgetParts/OrderedList/OrderedList.tsx | 7 + src/components/WidgetParts/index.tsx | 5 + 7 files changed, 325 insertions(+) create mode 100644 src/components/WidgetParts/ExpandableWidget/ExpandableWidget.module.scss create mode 100644 src/components/WidgetParts/ExpandableWidget/ExpandableWidget.tsx create mode 100644 src/components/WidgetParts/List/List.module.scss create mode 100644 src/components/WidgetParts/List/List.tsx create mode 100644 src/components/WidgetParts/OrderedList/OrderedList.module.scss create mode 100644 src/components/WidgetParts/OrderedList/OrderedList.tsx create mode 100644 src/components/WidgetParts/index.tsx (limited to 'src/components/WidgetParts') diff --git a/src/components/WidgetParts/ExpandableWidget/ExpandableWidget.module.scss b/src/components/WidgetParts/ExpandableWidget/ExpandableWidget.module.scss new file mode 100644 index 0000000..058d805 --- /dev/null +++ b/src/components/WidgetParts/ExpandableWidget/ExpandableWidget.module.scss @@ -0,0 +1,146 @@ +@use "@styles/abstracts/functions" as fun; +@use "@styles/abstracts/mixins" as mix; + +.title { + margin: 0; + padding: 0; + background: none; + font-size: var(--font-size-xl); + text-align: left; +} + +.icon { + display: flex; + flex-flow: row nowrap; + align-items: center; + justify-content: center; + width: fun.convert-px(30); + height: fun.convert-px(30); + background: var(--color-bg); + border: fun.convert-px(1) solid var(--color-primary); + border-radius: fun.convert-px(3); + color: var(--color-primary); + font-weight: 800; + transition: all 0.25s ease-in-out 0s; + + &::before, + &::after { + content: ""; + background: var(--color-primary); + transition: all 0.4s ease-out 0s; + } + + &::before { + width: 10%; + height: 60%; + position: relative; + left: 30%; + } + + &::after { + width: 60%; + height: 10%; + position: relative; + left: -5%; + } +} + +.body { + width: 100%; + margin: 0; + overflow-y: auto; + visibility: hidden; + opacity: 0; + height: 0; + transition: all 0.5s ease-in-out 0s; + + &--borders { + border: fun.convert-px(2) solid var(--color-primary-dark); + } + + > *:last-child { + margin-bottom: 0; + } + + @include mix.media("screen") { + @include mix.dimensions("md") { + font-size: var(--font-size-sm); + font-weight: 500; + } + } +} + +.header { + flex: 0 0 auto; + display: flex; + flex-flow: row nowrap; + align-items: center; + justify-content: space-between; + gap: var(--spacing-md); + width: 100%; + min-height: var(--header-height); + position: sticky; + top: 0; + background: var(--color-bg); + border: none; + border-bottom: fun.convert-px(2) solid var(--color-primary-dark); + cursor: pointer; + transition: background 0.2s ease-in-out 0s; + + > button { + padding: 0 var(--spacing-xs); + } +} + +.wrapper--expanded .icon { + &::before { + height: 0; + } +} + +.header:hover, +.header:focus { + .icon { + background: var(--color-primary-light); + color: var(--color-fg-inverted); + transform: scale(1.2); + + &::before, + &::after { + background: var(--color-bg); + } + } +} + +.wrapper { + --header-height: #{fun.convert-px(65)}; + + display: flex; + flex-flow: column; + min-height: var(--header-height); + position: relative; + overflow-y: hidden; + + &:first-of-type { + .header { + border-top: fun.convert-px(2) solid var(--color-primary-dark); + } + } +} + +.wrapper--expanded { + ~ .wrapper { + .header { + border-top: fun.convert-px(2) solid var(--color-primary-dark); + } + } + + .body { + visibility: visible; + opacity: 1; + min-height: inherit; + height: 100%; + margin: var(--spacing-sm) 0; + transition: all 0.45s ease-in-out 0s; + } +} diff --git a/src/components/WidgetParts/ExpandableWidget/ExpandableWidget.tsx b/src/components/WidgetParts/ExpandableWidget/ExpandableWidget.tsx new file mode 100644 index 0000000..52b5c06 --- /dev/null +++ b/src/components/WidgetParts/ExpandableWidget/ExpandableWidget.tsx @@ -0,0 +1,47 @@ +import { t } from '@lingui/macro'; +import { TitleLevel } from '@ts/types/app'; +import { ReactNode, useState } from 'react'; +import styles from './ExpandableWidget.module.scss'; + +const ExpandableWidget = ({ + children, + title, + titleLevel = 2, + expand = false, + withBorders = false, +}: { + children: ReactNode; + title: string; + titleLevel?: TitleLevel; + expand?: boolean; + withBorders?: boolean; +}) => { + const [isExpanded, setIsExpanded] = useState(expand); + + const handleExpanse = () => setIsExpanded((prev) => !prev); + + const TitleTag = `h${titleLevel}` as keyof JSX.IntrinsicElements; + + const wrapperClasses = `${styles.wrapper} ${ + isExpanded ? styles['wrapper--expanded'] : '' + }`; + + const bodyClasses = `${styles.body} ${ + withBorders ? styles['body--borders'] : '' + }`; + + return ( +
+ +
{children}
+
+ ); +}; + +export default ExpandableWidget; diff --git a/src/components/WidgetParts/List/List.module.scss b/src/components/WidgetParts/List/List.module.scss new file mode 100644 index 0000000..5da5741 --- /dev/null +++ b/src/components/WidgetParts/List/List.module.scss @@ -0,0 +1,47 @@ +@use "@styles/abstracts/functions" as fun; + +.list { + margin: 0; + padding: 0; + list-style-type: none; + + .list { + border: none; + border-top: fun.convert-px(1) solid var(--color-primary-dark); + } + + li { + margin: 0; + + &:not(:last-of-type) { + border-bottom: fun.convert-px(1) solid var(--color-primary-dark); + } + } + + a { + display: flex; + flex-flow: row nowrap; + width: 100%; + padding: var(--spacing-2xs) var(--spacing-xs); + background: none; + text-decoration: underline solid transparent 0; + transition: all 0.16s ease-in-out 0s, text-decoration-color 0s; + + &:hover, + &:focus { + background: var(--color-bg-secondary); + } + + &:focus { + color: var(--color-primary); + text-decoration-color: var(--color-primary-light); + text-decoration-thickness: 0.25ex; + } + + &:active { + background: var(--color-bg-tertiary); + text-decoration-color: transparent; + text-decoration-thickness: 0; + } + } +} diff --git a/src/components/WidgetParts/List/List.tsx b/src/components/WidgetParts/List/List.tsx new file mode 100644 index 0000000..317c4d1 --- /dev/null +++ b/src/components/WidgetParts/List/List.tsx @@ -0,0 +1,7 @@ +import styles from './List.module.scss'; + +const List = ({ items }: { items: Array }) => { + return
    {items}
; +}; + +export default List; diff --git a/src/components/WidgetParts/OrderedList/OrderedList.module.scss b/src/components/WidgetParts/OrderedList/OrderedList.module.scss new file mode 100644 index 0000000..a286932 --- /dev/null +++ b/src/components/WidgetParts/OrderedList/OrderedList.module.scss @@ -0,0 +1,66 @@ +@use "@styles/abstracts/functions" as fun; +@use "@styles/abstracts/placeholders"; + +.list { + @extend %reset-ordered-list; + counter-reset: link; + + .list { + border-top: fun.convert-px(1) solid var(--color-primary-dark); + } + + a { + display: flex; + flex-flow: row nowrap; + width: 100%; + padding: var(--spacing-2xs) var(--spacing-xs); + background: none; + text-decoration: underline solid transparent 0; + transition: all 0.16s ease-in-out 0s, text-decoration-color 0s; + counter-increment: link; + + &:hover, + &:focus { + background: var(--color-bg-secondary); + } + + &:focus { + color: var(--color-primary); + text-decoration-color: var(--color-primary-light); + text-decoration-thickness: 0.25ex; + } + + &:active { + background: var(--color-bg-tertiary); + text-decoration-color: transparent; + text-decoration-thickness: 0; + } + + &::before { + content: counters(link, ".") ". "; + color: var(--color-secondary); + padding-right: var(--spacing-2xs); + } + } + + li { + width: 100%; + margin: 0; + + &:not(:last-of-type) { + border-bottom: fun.convert-px(1) solid var(--color-primary-dark); + } + + &::before { + display: none; + } + } + + li li a::before { + padding-left: var(--spacing-sm); + } + + li li li a::before { + padding-left: var(--spacing-lg); + } +} diff --git a/src/components/WidgetParts/OrderedList/OrderedList.tsx b/src/components/WidgetParts/OrderedList/OrderedList.tsx new file mode 100644 index 0000000..a12ec06 --- /dev/null +++ b/src/components/WidgetParts/OrderedList/OrderedList.tsx @@ -0,0 +1,7 @@ +import styles from './OrderedList.module.scss'; + +const OrderedList = ({ items }: { items: Array }) => { + return
    {items}
; +}; + +export default OrderedList; diff --git a/src/components/WidgetParts/index.tsx b/src/components/WidgetParts/index.tsx new file mode 100644 index 0000000..59df3bd --- /dev/null +++ b/src/components/WidgetParts/index.tsx @@ -0,0 +1,5 @@ +import ExpandableWidget from './ExpandableWidget/ExpandableWidget'; +import List from './List/List'; +import OrderedList from './OrderedList/OrderedList'; + +export { ExpandableWidget, List, OrderedList }; -- cgit v1.2.3