aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorArmand Philippot <git@armandphilippot.com>2022-01-15 22:45:57 +0100
committerArmand Philippot <git@armandphilippot.com>2022-01-15 22:51:30 +0100
commitaa1ca65e7c9807c6d6020e39166536297fe1cdae (patch)
tree2648da350fec3b71ab7f575d63e4c63ba08248b1
parent16dbb4742264edac82fa6bb8e461259d097f4437 (diff)
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.
-rw-r--r--src/components/PostHeader/PostHeader.module.scss5
-rw-r--r--src/components/PostPreview/PostPreview.module.scss2
-rw-r--r--src/components/PostPreview/PostPreview.tsx3
-rw-r--r--src/components/PostsList/PostsList.module.scss2
-rw-r--r--src/components/Sidebar/Sidebar.module.scss31
-rw-r--r--src/components/Sidebar/Sidebar.tsx30
-rw-r--r--src/components/ToC/ToC.module.scss27
-rw-r--r--src/components/Widget/Widget.module.scss7
-rw-r--r--src/components/WidgetParts/ExpandableWidget/ExpandableWidget.module.scss146
-rw-r--r--src/components/WidgetParts/ExpandableWidget/ExpandableWidget.tsx47
-rw-r--r--src/components/WidgetParts/List/List.module.scss47
-rw-r--r--src/components/WidgetParts/List/List.tsx7
-rw-r--r--src/components/WidgetParts/OrderedList/OrderedList.module.scss66
-rw-r--r--src/components/WidgetParts/OrderedList/OrderedList.tsx7
-rw-r--r--src/components/WidgetParts/index.tsx5
-rw-r--r--src/components/Widgets/CVPreview/CVPreview.module.scss (renamed from src/components/Widget/CVPreview/CVPreview.module.scss)0
-rw-r--r--src/components/Widgets/CVPreview/CVPreview.tsx (renamed from src/components/Widget/CVPreview/CVPreview.tsx)6
-rw-r--r--src/components/Widgets/RecentPosts/RecentPosts.module.scss (renamed from src/components/Widget/RecentPosts/RecentPosts.module.scss)0
-rw-r--r--src/components/Widgets/RecentPosts/RecentPosts.tsx (renamed from src/components/Widget/RecentPosts/RecentPosts.tsx)0
-rw-r--r--src/components/Widgets/RelatedThematics/RelatedThematics.tsx (renamed from src/components/Widget/RelatedThematics/RelatedThematics.tsx)14
-rw-r--r--src/components/Widgets/RelatedTopics/RelatedTopics.tsx (renamed from src/components/Widget/RelatedTopics/RelatedTopics.tsx)14
-rw-r--r--src/components/Widgets/Sharing/Sharing.module.scss (renamed from src/components/Widget/Sharing/Sharing.module.scss)14
-rw-r--r--src/components/Widgets/Sharing/Sharing.tsx (renamed from src/components/Widget/Sharing/Sharing.tsx)10
-rw-r--r--src/components/Widgets/SocialMedia/SocialMedia.module.scss (renamed from src/components/Widget/SocialMedia/SocialMedia.module.scss)1
-rw-r--r--src/components/Widgets/SocialMedia/SocialMedia.tsx (renamed from src/components/Widget/SocialMedia/SocialMedia.tsx)6
-rw-r--r--src/components/Widgets/ThematicsList/ThematicsList.tsx (renamed from src/components/Widget/ThematicsList/ThematicsList.tsx)18
-rw-r--r--src/components/Widgets/ToC/ToC.module.scss70
-rw-r--r--src/components/Widgets/ToC/ToC.tsx (renamed from src/components/ToC/ToC.tsx)13
-rw-r--r--src/components/Widgets/TopicsList/TopicsList.tsx (renamed from src/components/Widget/TopicsList/TopicsList.tsx)18
-rw-r--r--src/components/Widgets/index.tsx (renamed from src/components/Widget/index.tsx)2
m---------src/content0
-rw-r--r--src/pages/article/[slug].tsx9
-rw-r--r--src/pages/blog/index.tsx4
-rw-r--r--src/pages/contact.tsx4
-rw-r--r--src/pages/cv.tsx9
-rw-r--r--src/pages/mentions-legales.tsx7
-rw-r--r--src/pages/recherche/index.tsx4
-rw-r--r--src/pages/sujet/[slug].tsx12
-rw-r--r--src/pages/thematique/[slug].tsx12
-rw-r--r--src/styles/pages/Page.module.scss29
-rw-r--r--src/ts/types/app.ts4
41 files changed, 547 insertions, 165 deletions
diff --git a/src/components/PostHeader/PostHeader.module.scss b/src/components/PostHeader/PostHeader.module.scss
index 3db92da..33dc488 100644
--- a/src/components/PostHeader/PostHeader.module.scss
+++ b/src/components/PostHeader/PostHeader.module.scss
@@ -4,10 +4,13 @@
.wrapper {
composes: grid from "@styles/layout/_grid.scss";
max-width: 100%;
- margin-bottom: var(--spacing-md);
position: relative;
@include mix.media("screen") {
+ @include mix.dimensions("md") {
+ margin-bottom: var(--spacing-md);
+ }
+
@include mix.dimensions("lg") {
--grid-gap: var(--spacing-lg);
}
diff --git a/src/components/PostPreview/PostPreview.module.scss b/src/components/PostPreview/PostPreview.module.scss
index 8039a87..8c14000 100644
--- a/src/components/PostPreview/PostPreview.module.scss
+++ b/src/components/PostPreview/PostPreview.module.scss
@@ -48,7 +48,7 @@ h2.title {
.wrapper {
margin: 0;
padding: var(--spacing-sm) var(--spacing-sm) var(--spacing-md);
- border: fun.convert-px(1) solid var(--color-border-light);
+ border: fun.convert-px(1) solid var(--color-primary-dark);
border-radius: fun.convert-px(3);
box-shadow: fun.convert-px(1) fun.convert-px(1) fun.convert-px(1) 0
var(--color-shadow-light),
diff --git a/src/components/PostPreview/PostPreview.tsx b/src/components/PostPreview/PostPreview.tsx
index 3ea4c40..3bf7bdb 100644
--- a/src/components/PostPreview/PostPreview.tsx
+++ b/src/components/PostPreview/PostPreview.tsx
@@ -6,8 +6,7 @@ import styles from './PostPreview.module.scss';
import Image from 'next/image';
import { ButtonLink } from '@components/Buttons';
import { ArrowIcon } from '@components/Icons';
-
-type TitleLevel = 2 | 3 | 4 | 5 | 6;
+import { TitleLevel } from '@ts/types/app';
const PostPreview = ({
post,
diff --git a/src/components/PostsList/PostsList.module.scss b/src/components/PostsList/PostsList.module.scss
index 6c3f93e..5d3ee95 100644
--- a/src/components/PostsList/PostsList.module.scss
+++ b/src/components/PostsList/PostsList.module.scss
@@ -19,7 +19,7 @@
grid-column: 1;
justify-self: end;
position: sticky;
- top: 0;
+ top: var(--spacing-xs);
margin-right: var(--spacing-lg);
}
}
diff --git a/src/components/Sidebar/Sidebar.module.scss b/src/components/Sidebar/Sidebar.module.scss
index 83c1024..18291b6 100644
--- a/src/components/Sidebar/Sidebar.module.scss
+++ b/src/components/Sidebar/Sidebar.module.scss
@@ -2,37 +2,44 @@
.wrapper {
grid-column: 2;
- margin-top: var(--spacing-lg);
+ margin: var(--spacing-md) 0;
@include mix.media("screen") {
@include mix.dimensions("md") {
- grid-column: 3;
- grid-row: 2;
align-self: stretch;
display: flex;
- flex-flow: column nowrap;
- margin-top: 0;
- position: relative;
- visibility: hidden;
+ flex-flow: column;
+ justify-content: flex-start;
+ margin: var(--spacing-xs);
- &:hover {
- visibility: visible;
+ &--right {
+ grid-row: 2 / 4;
+ grid-column: 3;
}
+ }
- > * {
- visibility: visible;
+ @include mix.dimensions("lg") {
+ &--left {
+ grid-row: 2 / 4;
+ grid-column: 1;
}
}
}
}
.body {
+ display: flex;
+ flex-flow: column;
+ justify-content: flex-start;
+ max-height: 100vh;
+
@include mix.media("screen") {
@include mix.dimensions("md") {
align-self: flex-start;
width: 100%;
+ max-height: calc(100vh - (var(--spacing-xs) * 2));
position: sticky;
- top: 0;
+ top: var(--spacing-xs);
}
}
}
diff --git a/src/components/Sidebar/Sidebar.tsx b/src/components/Sidebar/Sidebar.tsx
index 8c9fa1d..f319f9e 100644
--- a/src/components/Sidebar/Sidebar.tsx
+++ b/src/components/Sidebar/Sidebar.tsx
@@ -1,10 +1,32 @@
-import { FunctionComponent } from 'react';
+import { Children, cloneElement, isValidElement, ReactNode } from 'react';
import styles from './Sidebar.module.scss';
-const Sidebar: FunctionComponent = ({ children }) => {
+type SidebarPosition = 'left' | 'right';
+
+const Sidebar = ({
+ children,
+ position,
+ title,
+}: {
+ children: ReactNode;
+ position: SidebarPosition;
+ title?: string;
+}) => {
+ const childrenWithProps = Children.map(children, (child) => {
+ if (isValidElement(child)) {
+ return cloneElement(child, { titleLevel: title ? 3 : 2 });
+ }
+ return child;
+ });
+
+ const positionClass = `wrapper--${position}`;
+
return (
- <aside className={styles.wrapper}>
- <div className={styles.body}>{children}</div>
+ <aside className={`${styles.wrapper} ${styles[positionClass]}`}>
+ <div className={styles.body}>
+ {title && <h2>{title}</h2>}
+ {childrenWithProps}
+ </div>
</aside>
);
};
diff --git a/src/components/ToC/ToC.module.scss b/src/components/ToC/ToC.module.scss
deleted file mode 100644
index 0f08b87..0000000
--- a/src/components/ToC/ToC.module.scss
+++ /dev/null
@@ -1,27 +0,0 @@
-@use "@styles/abstracts/mixins" as mix;
-
-.wrapper {
- padding-bottom: var(--spacing-sm);
-
- @include mix.media("screen") {
- @include mix.dimensions("lg") {
- max-height: 100vh;
- position: sticky;
- top: 0;
- overflow: auto;
- visibility: hidden;
-
- > * {
- visibility: visible;
- }
-
- &:hover {
- visibility: visible;
- }
- }
- }
-}
-
-.list {
- margin-bottom: 0;
-}
diff --git a/src/components/Widget/Widget.module.scss b/src/components/Widget/Widget.module.scss
deleted file mode 100644
index 5f37c7a..0000000
--- a/src/components/Widget/Widget.module.scss
+++ /dev/null
@@ -1,7 +0,0 @@
-.title {
- margin: 0;
-}
-
-.list {
- margin: var(--spacing-sm) 0;
-}
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<boolean>(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 (
+ <div className={wrapperClasses}>
+ <button type="button" className={styles.header} onClick={handleExpanse}>
+ <span className="screen-reader-text">
+ {isExpanded ? t`Collapse` : t`Expand`}
+ </span>
+ <TitleTag className={styles.title}>{title}</TitleTag>
+ <span className={styles.icon} aria-hidden={true}></span>
+ </button>
+ <div className={bodyClasses}>{children}</div>
+ </div>
+ );
+};
+
+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<any> }) => {
+ return <ul className={styles.list}>{items}</ul>;
+};
+
+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<any> }) => {
+ return <ol className={styles.list}>{items}</ol>;
+};
+
+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 };
diff --git a/src/components/Widget/CVPreview/CVPreview.module.scss b/src/components/Widgets/CVPreview/CVPreview.module.scss
index 6ddd696..6ddd696 100644
--- a/src/components/Widget/CVPreview/CVPreview.module.scss
+++ b/src/components/Widgets/CVPreview/CVPreview.module.scss
diff --git a/src/components/Widget/CVPreview/CVPreview.tsx b/src/components/Widgets/CVPreview/CVPreview.tsx
index f0bd0fe..e52a9b2 100644
--- a/src/components/Widget/CVPreview/CVPreview.tsx
+++ b/src/components/Widgets/CVPreview/CVPreview.tsx
@@ -1,3 +1,4 @@
+import { ExpandableWidget } from '@components/WidgetParts';
import { Trans } from '@lingui/macro';
import Image from 'next/image';
import Link from 'next/link';
@@ -13,8 +14,7 @@ const CVPreview = ({
pdf: string;
}) => {
return (
- <div>
- <h2>{title}</h2>
+ <ExpandableWidget title={title} expand={true}>
<div className={styles.preview}>
<Image
src={imgSrc}
@@ -29,7 +29,7 @@ const CVPreview = ({
Download <Link href={pdf}>CV in PDF</Link>
</Trans>
</p>
- </div>
+ </ExpandableWidget>
);
};
diff --git a/src/components/Widget/RecentPosts/RecentPosts.module.scss b/src/components/Widgets/RecentPosts/RecentPosts.module.scss
index 95ad7fe..95ad7fe 100644
--- a/src/components/Widget/RecentPosts/RecentPosts.module.scss
+++ b/src/components/Widgets/RecentPosts/RecentPosts.module.scss
diff --git a/src/components/Widget/RecentPosts/RecentPosts.tsx b/src/components/Widgets/RecentPosts/RecentPosts.tsx
index 1569284..1569284 100644
--- a/src/components/Widget/RecentPosts/RecentPosts.tsx
+++ b/src/components/Widgets/RecentPosts/RecentPosts.tsx
diff --git a/src/components/Widget/RelatedThematics/RelatedThematics.tsx b/src/components/Widgets/RelatedThematics/RelatedThematics.tsx
index 24d60e2..afe3460 100644
--- a/src/components/Widget/RelatedThematics/RelatedThematics.tsx
+++ b/src/components/Widgets/RelatedThematics/RelatedThematics.tsx
@@ -1,7 +1,7 @@
+import { ExpandableWidget, List } from '@components/WidgetParts';
import { t } from '@lingui/macro';
import { ThematicPreview } from '@ts/types/taxonomies';
import Link from 'next/link';
-import styles from '../Widget.module.scss';
const RelatedThematics = ({ thematics }: { thematics: ThematicPreview[] }) => {
const sortedThematics = [...thematics].sort((a, b) =>
@@ -19,12 +19,12 @@ const RelatedThematics = ({ thematics }: { thematics: ThematicPreview[] }) => {
});
return (
- <div>
- <h2 className={styles.title}>
- {thematics.length > 1 ? t`Related thematics` : t`Related thematic`}
- </h2>
- <ul className={styles.list}>{thematicsList}</ul>
- </div>
+ <ExpandableWidget
+ title={thematics.length > 1 ? t`Related thematics` : t`Related thematic`}
+ withBorders={true}
+ >
+ <List items={thematicsList} />
+ </ExpandableWidget>
);
};
diff --git a/src/components/Widget/RelatedTopics/RelatedTopics.tsx b/src/components/Widgets/RelatedTopics/RelatedTopics.tsx
index 422c06f..aab8cc1 100644
--- a/src/components/Widget/RelatedTopics/RelatedTopics.tsx
+++ b/src/components/Widgets/RelatedTopics/RelatedTopics.tsx
@@ -1,7 +1,7 @@
+import { ExpandableWidget, List } from '@components/WidgetParts';
import { t } from '@lingui/macro';
import { SubjectPreview } from '@ts/types/taxonomies';
import Link from 'next/link';
-import styles from '../Widget.module.scss';
const RelatedTopics = ({ topics }: { topics: SubjectPreview[] }) => {
const sortedSubjects = [...topics].sort((a, b) =>
@@ -19,12 +19,12 @@ const RelatedTopics = ({ topics }: { topics: SubjectPreview[] }) => {
});
return (
- <div>
- <h2 className={styles.title}>
- {topics.length > 1 ? t`Related topics` : t`Related topic`}
- </h2>
- <ul className={styles.list}>{subjects}</ul>
- </div>
+ <ExpandableWidget
+ title={topics.length > 1 ? t`Related topics` : t`Related topic`}
+ withBorders={true}
+ >
+ <List items={subjects} />
+ </ExpandableWidget>
);
};
diff --git a/src/components/Widget/Sharing/Sharing.module.scss b/src/components/Widgets/Sharing/Sharing.module.scss
index 7ecb5ff..3477c88 100644
--- a/src/components/Widget/Sharing/Sharing.module.scss
+++ b/src/components/Widgets/Sharing/Sharing.module.scss
@@ -2,22 +2,20 @@
@use "@styles/abstracts/mixins" as mix;
@use "@styles/abstracts/placeholders";
-.wrapper {
- padding-bottom: var(--spacing-sm);
+.list {
+ @extend %flex-list;
+
+ gap: var(--spacing-sm);
+ padding: var(--spacing-2xs) 0 0 var(--spacing-2xs);
@include mix.media("screen") {
@include mix.dimensions("md") {
+ gap: var(--spacing-xs);
width: min-content;
}
}
}
-.list {
- @extend %flex-list;
-
- gap: var(--spacing-sm);
-}
-
.link {
display: flex;
flex-flow: row nowrap;
diff --git a/src/components/Widget/Sharing/Sharing.tsx b/src/components/Widgets/Sharing/Sharing.tsx
index 4df8e0d..bc52f9b 100644
--- a/src/components/Widget/Sharing/Sharing.tsx
+++ b/src/components/Widgets/Sharing/Sharing.tsx
@@ -1,3 +1,4 @@
+import { ExpandableWidget } from '@components/WidgetParts';
import sharingMedia from '@config/sharing';
import { t } from '@lingui/macro';
import { useRouter } from 'next/router';
@@ -101,10 +102,11 @@ const Sharing = ({ excerpt, title }: { excerpt: string; title: string }) => {
};
return (
- <div className={styles.wrapper}>
- <h2>{t`Share`}</h2>
- <ul className={styles.list}>{getItems()}</ul>
- </div>
+ <ExpandableWidget title={t`Share`} expand={true}>
+ <ul className={`${styles.list} ${styles['list--sharing']}`}>
+ {getItems()}
+ </ul>
+ </ExpandableWidget>
);
};
diff --git a/src/components/Widget/SocialMedia/SocialMedia.module.scss b/src/components/Widgets/SocialMedia/SocialMedia.module.scss
index 70ef5d9..c8ad759 100644
--- a/src/components/Widget/SocialMedia/SocialMedia.module.scss
+++ b/src/components/Widgets/SocialMedia/SocialMedia.module.scss
@@ -6,6 +6,7 @@
gap: var(--spacing-xs);
align-items: center;
+ padding: var(--spacing-2xs) 0 0 var(--spacing-2xs);
}
.link {
diff --git a/src/components/Widget/SocialMedia/SocialMedia.tsx b/src/components/Widgets/SocialMedia/SocialMedia.tsx
index 9ca0627..351fd48 100644
--- a/src/components/Widget/SocialMedia/SocialMedia.tsx
+++ b/src/components/Widgets/SocialMedia/SocialMedia.tsx
@@ -4,6 +4,7 @@ import GitlabIcon from '@assets/images/social-media/gitlab.svg';
import LinkedInIcon from '@assets/images/social-media/linkedin.svg';
import TwitterIcon from '@assets/images/social-media/twitter.svg';
import styles from './SocialMedia.module.scss';
+import { ExpandableWidget } from '@components/WidgetParts';
const SocialMedia = ({
title,
@@ -62,10 +63,9 @@ const SocialMedia = ({
});
return (
- <div>
- <h2>{title}</h2>
+ <ExpandableWidget title={title} expand={true}>
<ul className={styles.list}>{items}</ul>
- </div>
+ </ExpandableWidget>
);
};
diff --git a/src/components/Widget/ThematicsList/ThematicsList.tsx b/src/components/Widgets/ThematicsList/ThematicsList.tsx
index d17dbd1..8523bd1 100644
--- a/src/components/Widget/ThematicsList/ThematicsList.tsx
+++ b/src/components/Widgets/ThematicsList/ThematicsList.tsx
@@ -1,11 +1,18 @@
+import { ExpandableWidget, List } from '@components/WidgetParts';
import { t } from '@lingui/macro';
import { getAllThematics } from '@services/graphql/queries';
+import { TitleLevel } from '@ts/types/app';
import Link from 'next/link';
import { useRouter } from 'next/router';
import useSWR from 'swr';
-import styles from '../Widget.module.scss';
-const ThematicsList = ({ title }: { title: string }) => {
+const ThematicsList = ({
+ title,
+ titleLevel,
+}: {
+ title: string;
+ titleLevel?: TitleLevel;
+}) => {
const router = useRouter();
const isThematic = () => router.asPath.includes('/thematique/');
const currentThematicSlug = isThematic()
@@ -30,10 +37,9 @@ const ThematicsList = ({ title }: { title: string }) => {
});
return (
- <div>
- <h2 className={styles.title}>{title}</h2>
- <ul className={styles.list}>{thematics}</ul>
- </div>
+ <ExpandableWidget title={title} titleLevel={titleLevel} withBorders={true}>
+ <List items={thematics} />
+ </ExpandableWidget>
);
};
diff --git a/src/components/Widgets/ToC/ToC.module.scss b/src/components/Widgets/ToC/ToC.module.scss
new file mode 100644
index 0000000..a296659
--- /dev/null
+++ b/src/components/Widgets/ToC/ToC.module.scss
@@ -0,0 +1,70 @@
+@use "@styles/abstracts/functions" as fun;
+@use "@styles/abstracts/mixins" as mix;
+
+.item {
+ width: 100%;
+ margin: 0;
+
+ &::before {
+ display: none;
+ }
+}
+
+.link {
+ display: flex;
+ flex-flow: row nowrap;
+ width: 100%;
+ padding: var(--spacing-2xs) var(--spacing-sm);
+ background: none;
+ border-bottom: fun.convert-px(1) solid var(--color-border-lighter);
+ 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;
+ }
+}
+
+.list {
+ width: 100%;
+ margin: 0;
+ counter-reset: link;
+
+ @include mix.media("screen") {
+ @include mix.dimensions("lg") {
+ font-size: var(--font-size-sm);
+ font-weight: 500;
+ }
+ }
+
+ > .item .link {
+ counter-increment: link;
+
+ &::before {
+ content: counters(link, ".") ". ";
+ color: var(--color-secondary);
+ padding-right: var(--spacing-2xs);
+ }
+ }
+
+ .item .item .link::before {
+ padding-left: var(--spacing-sm);
+ }
+
+ .item .item .item .link::before {
+ padding-left: var(--spacing-lg);
+ }
+}
diff --git a/src/components/ToC/ToC.tsx b/src/components/Widgets/ToC/ToC.tsx
index b172b3a..6010354 100644
--- a/src/components/ToC/ToC.tsx
+++ b/src/components/Widgets/ToC/ToC.tsx
@@ -1,7 +1,7 @@
+import { ExpandableWidget, OrderedList } from '@components/WidgetParts';
import { t } from '@lingui/macro';
import { Heading } from '@ts/types/app';
import useHeadingsTree from '@utils/hooks/useHeadingsTree';
-import styles from './ToC.module.scss';
const ToC = () => {
const headingsTree = useHeadingsTree('article');
@@ -12,17 +12,18 @@ const ToC = () => {
return (
<li key={heading.id}>
<a href={`#${heading.id}`}>{heading.title}</a>
- {heading.children.length > 0 && <ol>{getItems(heading.children)}</ol>}
+ {heading.children.length > 0 && (
+ <OrderedList items={getItems(heading.children)} />
+ )}
</li>
);
});
};
return (
- <div className={styles.wrapper}>
- <h2>{title}</h2>
- <ol className={styles.list}>{getItems(headingsTree)}</ol>
- </div>
+ <ExpandableWidget title={title} expand={true} withBorders={true}>
+ <OrderedList items={getItems(headingsTree)} />
+ </ExpandableWidget>
);
};
diff --git a/src/components/Widget/TopicsList/TopicsList.tsx b/src/components/Widgets/TopicsList/TopicsList.tsx
index 50205d7..5bf12b9 100644
--- a/src/components/Widget/TopicsList/TopicsList.tsx
+++ b/src/components/Widgets/TopicsList/TopicsList.tsx
@@ -1,11 +1,18 @@
+import { ExpandableWidget, List } from '@components/WidgetParts';
import { t } from '@lingui/macro';
import { getAllSubjects } from '@services/graphql/queries';
+import { TitleLevel } from '@ts/types/app';
import Link from 'next/link';
import { useRouter } from 'next/router';
import useSWR from 'swr';
-import styles from '../Widget.module.scss';
-const TopicsList = ({ title }: { title: string }) => {
+const TopicsList = ({
+ title,
+ titleLevel,
+}: {
+ title: string;
+ titleLevel?: TitleLevel;
+}) => {
const router = useRouter();
const isTopic = () => router.asPath.includes('/sujet/');
const currentTopicSlug = isTopic()
@@ -30,10 +37,9 @@ const TopicsList = ({ title }: { title: string }) => {
});
return (
- <div>
- <h2 className={styles.title}>{title}</h2>
- <ul className={styles.list}>{subjects}</ul>
- </div>
+ <ExpandableWidget title={title} titleLevel={titleLevel} withBorders={true}>
+ <List items={subjects} />
+ </ExpandableWidget>
);
};
diff --git a/src/components/Widget/index.tsx b/src/components/Widgets/index.tsx
index 08e3a5a..8354449 100644
--- a/src/components/Widget/index.tsx
+++ b/src/components/Widgets/index.tsx
@@ -5,6 +5,7 @@ import RelatedTopics from './RelatedTopics/RelatedTopics';
import Sharing from './Sharing/Sharing';
import SocialMedia from './SocialMedia/SocialMedia';
import ThematicsList from './ThematicsList/ThematicsList';
+import ToC from './ToC/ToC';
import TopicsList from './TopicsList/TopicsList';
export {
@@ -15,5 +16,6 @@ export {
Sharing,
SocialMedia,
ThematicsList,
+ ToC,
TopicsList,
};
diff --git a/src/content b/src/content
-Subproject f399fbcb373436ab05f3e01ce762ce1680e61f7
+Subproject c6f91781084aaf0b7d6f9b2a5d177e21e6d0d96
diff --git a/src/pages/article/[slug].tsx b/src/pages/article/[slug].tsx
index fb79b41..509be4f 100644
--- a/src/pages/article/[slug].tsx
+++ b/src/pages/article/[slug].tsx
@@ -3,7 +3,6 @@ import CommentsList from '@components/CommentsList/CommentsList';
import { getLayout } from '@components/Layouts/Layout';
import PostFooter from '@components/PostFooter/PostFooter';
import PostHeader from '@components/PostHeader/PostHeader';
-import ToC from '@components/ToC/ToC';
import { config } from '@config/website';
import { getAllPostsSlug, getPostBySlug } from '@services/graphql/queries';
import { NextPageWithLayout } from '@ts/types/app';
@@ -17,7 +16,7 @@ import Prism from 'prismjs';
import { ParsedUrlQuery } from 'querystring';
import { useEffect } from 'react';
import styles from '@styles/pages/Page.module.scss';
-import { Sharing } from '@components/Widget';
+import { Sharing, ToC } from '@components/Widgets';
import Sidebar from '@components/Sidebar/Sidebar';
const SingleArticle: NextPageWithLayout<ArticleProps> = ({ post }) => {
@@ -60,15 +59,15 @@ const SingleArticle: NextPageWithLayout<ArticleProps> = ({ post }) => {
</Head>
<article className={styles.article}>
<PostHeader intro={intro} meta={meta} title={title} />
- <aside className={styles.toc}>
+ <Sidebar position="left">
<ToC />
- </aside>
+ </Sidebar>
<div
className={styles.body}
dangerouslySetInnerHTML={{ __html: content }}
></div>
<PostFooter subjects={subjects} />
- <Sidebar>
+ <Sidebar position="right">
<Sharing title={title} excerpt={intro} />
</Sidebar>
<section className={styles.comments}>
diff --git a/src/pages/blog/index.tsx b/src/pages/blog/index.tsx
index e0d35cd..b20b647 100644
--- a/src/pages/blog/index.tsx
+++ b/src/pages/blog/index.tsx
@@ -12,7 +12,7 @@ import useSWRInfinite from 'swr/infinite';
import { Button } from '@components/Buttons';
import { getPublishedPosts } from '@services/graphql/queries';
import PostHeader from '@components/PostHeader/PostHeader';
-import { ThematicsList, TopicsList } from '@components/Widget';
+import { ThematicsList, TopicsList } from '@components/Widgets';
import Sidebar from '@components/Sidebar/Sidebar';
import styles from '@styles/pages/Page.module.scss';
import { useRef } from 'react';
@@ -74,7 +74,7 @@ const Blog: NextPageWithLayout<BlogPageProps> = ({ fallback }) => {
>{t`Load more?`}</Button>
)}
</div>
- <Sidebar>
+ <Sidebar position="right" title={t`Filter by`}>
<ThematicsList title={t`Thematics`} />
<TopicsList title={t`Topics`} />
</Sidebar>
diff --git a/src/pages/contact.tsx b/src/pages/contact.tsx
index 5e6d138..bafa5e9 100644
--- a/src/pages/contact.tsx
+++ b/src/pages/contact.tsx
@@ -11,7 +11,7 @@ import Head from 'next/head';
import { FormEvent, useState } from 'react';
import PostHeader from '@components/PostHeader/PostHeader';
import styles from '@styles/pages/Page.module.scss';
-import { SocialMedia } from '@components/Widget';
+import { SocialMedia } from '@components/Widgets';
import Sidebar from '@components/Sidebar/Sidebar';
const ContactPage: NextPageWithLayout = () => {
@@ -113,7 +113,7 @@ const ContactPage: NextPageWithLayout = () => {
</FormItem>
</Form>
</div>
- <Sidebar>
+ <Sidebar position="right">
<SocialMedia
title={t`Find me elsewhere`}
github={true}
diff --git a/src/pages/cv.tsx b/src/pages/cv.tsx
index c771bb2..01eab4c 100644
--- a/src/pages/cv.tsx
+++ b/src/pages/cv.tsx
@@ -1,5 +1,4 @@
import { getLayout } from '@components/Layouts/Layout';
-import ToC from '@components/ToC/ToC';
import { seo } from '@config/seo';
import { NextPageWithLayout } from '@ts/types/app';
import { loadTranslation } from '@utils/helpers/i18n';
@@ -9,7 +8,7 @@ import CVContent, { intro, meta, pdf, image } from '@content/pages/cv.mdx';
import PostHeader from '@components/PostHeader/PostHeader';
import { ArticleMeta } from '@ts/types/articles';
import styles from '@styles/pages/Page.module.scss';
-import { CVPreview, SocialMedia } from '@components/Widget';
+import { CVPreview, SocialMedia, ToC } from '@components/Widgets';
import { t } from '@lingui/macro';
import Sidebar from '@components/Sidebar/Sidebar';
@@ -33,13 +32,13 @@ const CV: NextPageWithLayout = () => {
className={`${styles.article} ${styles['article--no-comments']}`}
>
<PostHeader intro={intro} meta={pageMeta} title={meta.title} />
- <aside className={styles.toc}>
+ <Sidebar position="left">
<ToC />
- </aside>
+ </Sidebar>
<div className={styles.body}>
<CVContent />
</div>
- <Sidebar>
+ <Sidebar position="right">
<CVPreview title={t`Other formats`} imgSrc={image} pdf={pdf} />
<SocialMedia
title={t`Open-source projects`}
diff --git a/src/pages/mentions-legales.tsx b/src/pages/mentions-legales.tsx
index ea98e20..fcaef06 100644
--- a/src/pages/mentions-legales.tsx
+++ b/src/pages/mentions-legales.tsx
@@ -1,5 +1,4 @@
import { getLayout } from '@components/Layouts/Layout';
-import ToC from '@components/ToC/ToC';
import { seo } from '@config/seo';
import { NextPageWithLayout } from '@ts/types/app';
import { loadTranslation } from '@utils/helpers/i18n';
@@ -12,6 +11,8 @@ import LegalNoticeContent, {
import PostHeader from '@components/PostHeader/PostHeader';
import { ArticleMeta } from '@ts/types/articles';
import styles from '@styles/pages/Page.module.scss';
+import { ToC } from '@components/Widgets';
+import Sidebar from '@components/Sidebar/Sidebar';
const LegalNotice: NextPageWithLayout = () => {
const dates = {
@@ -33,9 +34,9 @@ const LegalNotice: NextPageWithLayout = () => {
className={`${styles.article} ${styles['article--no-comments']}`}
>
<PostHeader intro={intro} meta={pageMeta} title={meta.title} />
- <aside className={styles.toc}>
+ <Sidebar position="left">
<ToC />
- </aside>
+ </Sidebar>
<div className={styles.body}>
<LegalNoticeContent />
</div>
diff --git a/src/pages/recherche/index.tsx b/src/pages/recherche/index.tsx
index 57f40e2..c45f9f0 100644
--- a/src/pages/recherche/index.tsx
+++ b/src/pages/recherche/index.tsx
@@ -14,7 +14,7 @@ import { useRouter } from 'next/router';
import { useEffect, useRef, useState } from 'react';
import useSWRInfinite from 'swr/infinite';
import Sidebar from '@components/Sidebar/Sidebar';
-import { ThematicsList, TopicsList } from '@components/Widget';
+import { ThematicsList, TopicsList } from '@components/Widgets';
import styles from '@styles/pages/Page.module.scss';
const Search: NextPageWithLayout = () => {
@@ -97,7 +97,7 @@ const Search: NextPageWithLayout = () => {
>{t`Load more?`}</Button>
)}
</div>
- <Sidebar>
+ <Sidebar position="right">
<ThematicsList title={t`Thematics`} />
<TopicsList title={t`Topics`} />
</Sidebar>
diff --git a/src/pages/sujet/[slug].tsx b/src/pages/sujet/[slug].tsx
index a7adf89..b373041 100644
--- a/src/pages/sujet/[slug].tsx
+++ b/src/pages/sujet/[slug].tsx
@@ -13,10 +13,10 @@ import {
} from '@services/graphql/queries';
import PostHeader from '@components/PostHeader/PostHeader';
import { ArticleMeta } from '@ts/types/articles';
-import ToC from '@components/ToC/ToC';
-import { RelatedThematics, TopicsList } from '@components/Widget';
+import { RelatedThematics, ToC, TopicsList } from '@components/Widgets';
import { useRef } from 'react';
import Head from 'next/head';
+import Sidebar from '@components/Sidebar/Sidebar';
const Subject: NextPageWithLayout<SubjectProps> = ({ subject }) => {
const relatedThematics = useRef<ThematicPreview[]>([]);
@@ -64,9 +64,9 @@ const Subject: NextPageWithLayout<SubjectProps> = ({ subject }) => {
meta={meta}
title={subject.title}
/>
- <aside className={styles.toc}>
+ <Sidebar position="left">
<ToC />
- </aside>
+ </Sidebar>
<div className={styles.body}>
<div dangerouslySetInnerHTML={{ __html: subject.content }}></div>
{subject.posts.length > 0 && (
@@ -76,10 +76,10 @@ const Subject: NextPageWithLayout<SubjectProps> = ({ subject }) => {
</section>
)}
</div>
- <aside className={`${styles.aside} ${styles['aside--overflow']}`}>
+ <Sidebar position="right">
<RelatedThematics thematics={relatedThematics.current} />
<TopicsList title={t`Other topics`} />
- </aside>
+ </Sidebar>
</article>
</>
);
diff --git a/src/pages/thematique/[slug].tsx b/src/pages/thematique/[slug].tsx
index f23ad5b..4eee656 100644
--- a/src/pages/thematique/[slug].tsx
+++ b/src/pages/thematique/[slug].tsx
@@ -12,11 +12,11 @@ import {
getThematicBySlug,
} from '@services/graphql/queries';
import PostHeader from '@components/PostHeader/PostHeader';
-import ToC from '@components/ToC/ToC';
-import { RelatedTopics, ThematicsList } from '@components/Widget';
+import { RelatedTopics, ThematicsList, ToC } from '@components/Widgets';
import { useRef } from 'react';
import { ArticleMeta } from '@ts/types/articles';
import Head from 'next/head';
+import Sidebar from '@components/Sidebar/Sidebar';
const Thematic: NextPageWithLayout<ThematicProps> = ({ thematic }) => {
const relatedSubjects = useRef<SubjectPreview[]>([]);
@@ -58,9 +58,9 @@ const Thematic: NextPageWithLayout<ThematicProps> = ({ thematic }) => {
className={`${styles.article} ${styles['article--no-comments']}`}
>
<PostHeader intro={thematic.intro} meta={meta} title={thematic.title} />
- <aside className={styles.toc}>
+ <Sidebar position="left">
<ToC />
- </aside>
+ </Sidebar>
<div className={styles.body}>
<div dangerouslySetInnerHTML={{ __html: thematic.content }}></div>
{thematic.posts.length > 0 && (
@@ -70,10 +70,10 @@ const Thematic: NextPageWithLayout<ThematicProps> = ({ thematic }) => {
</section>
)}
</div>
- <aside className={`${styles.aside} ${styles['aside--overflow']}`}>
+ <Sidebar position="right">
<RelatedTopics topics={relatedSubjects.current} />
<ThematicsList title={t`Other thematics`} />
- </aside>
+ </Sidebar>
</article>
</>
);
diff --git a/src/styles/pages/Page.module.scss b/src/styles/pages/Page.module.scss
index 69b25c0..ac6646b 100644
--- a/src/styles/pages/Page.module.scss
+++ b/src/styles/pages/Page.module.scss
@@ -20,25 +20,6 @@
}
}
-.toc {
- grid-column: 2;
-
- @include mix.media("screen") {
- @include mix.dimensions("lg") {
- grid-column: 1;
- grid-row: 2 / 4;
- align-self: stretch;
- justify-self: end;
- padding: 0 var(--spacing-sm);
-
- ol:first-of-type {
- font-size: var(--font-size-sm);
- font-weight: 500;
- }
- }
- }
-}
-
.list {
@extend %reset-ordered-list;
}
@@ -60,13 +41,3 @@ li.item {
grid-column: 2;
}
}
-
-.aside {
- max-height: 100vh;
- position: sticky;
- top: 0;
-
- &--overflow {
- overflow: auto;
- }
-}
diff --git a/src/ts/types/app.ts b/src/ts/types/app.ts
index d9bd041..b5707a2 100644
--- a/src/ts/types/app.ts
+++ b/src/ts/types/app.ts
@@ -57,6 +57,8 @@ export type RequestType =
// Globals
//==============================================================================
+export type ButtonKind = 'primary' | 'secondary' | 'tertiary';
+
export type ButtonPosition = 'left' | 'right' | 'center';
export type ContentParts = {
@@ -95,3 +97,5 @@ export type PageInfo = {
export type Slug = {
slug: string;
};
+
+export type TitleLevel = 2 | 3 | 4 | 5 | 6;