From 5ffcd155b89346e61478198df3ee085a08e70a23 Mon Sep 17 00:00:00 2001 From: Thomas Guillot Date: Fri, 10 May 2024 11:03:52 +0100 Subject: [PATCH] feat: add comments sidebar (#135) --- parts/comments-contents.html | 37 +++++++ parts/comments-menu.html | 9 ++ parts/comments.html | 37 ------- src/images/icon-comments.svg | 1 + src/js/front-end/main.js | 1 + src/js/front-end/menus/comments-menu.js | 63 ++++++++++++ src/scss/_base.scss | 8 +- src/scss/_comments-overlay.scss | 89 +++++++++++++++++ src/scss/_forms.scss | 48 +++++++++ src/scss/_gutenberg-shim.scss | 36 ------- src/scss/_header.scss | 15 +-- src/scss/_mixins.scss | 98 +++++++++++++++++-- src/scss/_sass-utils.scss | 1 + src/scss/blocks/_post-comments.scss | 124 ++++++++++++++++++++++-- src/scss/blocks/_query-pagination.scss | 15 +-- src/scss/style.scss | 2 + templates/single.html | 2 +- templates/single/large-image.html | 2 +- theme.json | 81 ++++++++++++---- 19 files changed, 545 insertions(+), 124 deletions(-) create mode 100644 parts/comments-contents.html create mode 100644 parts/comments-menu.html delete mode 100644 parts/comments.html create mode 100644 src/images/icon-comments.svg create mode 100644 src/js/front-end/menus/comments-menu.js create mode 100644 src/scss/_comments-overlay.scss create mode 100644 src/scss/_forms.scss diff --git a/parts/comments-contents.html b/parts/comments-contents.html new file mode 100644 index 00000000..8963c37e --- /dev/null +++ b/parts/comments-contents.html @@ -0,0 +1,37 @@ + +
+ +
+ + + +
+ + + + + +
+
+ + + + + +
+ + + + +
+ + + + + + + + + +
+ \ No newline at end of file diff --git a/parts/comments-menu.html b/parts/comments-menu.html new file mode 100644 index 00000000..1a98f325 --- /dev/null +++ b/parts/comments-menu.html @@ -0,0 +1,9 @@ + +
+
+ +
+ + +
+ \ No newline at end of file diff --git a/parts/comments.html b/parts/comments.html deleted file mode 100644 index 055b8bff..00000000 --- a/parts/comments.html +++ /dev/null @@ -1,37 +0,0 @@ - -
- - - -
-
-
- - -
- - -
- -
-
-
- - - - -
-
- - - - - - - - - - - -
- \ No newline at end of file diff --git a/src/images/icon-comments.svg b/src/images/icon-comments.svg new file mode 100644 index 00000000..985537c7 --- /dev/null +++ b/src/images/icon-comments.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/js/front-end/main.js b/src/js/front-end/main.js index dbb88c66..55e04c13 100644 --- a/src/js/front-end/main.js +++ b/src/js/front-end/main.js @@ -1,2 +1,3 @@ +import './menus/comments-menu'; import './menus/mobile-menu'; import './menus/search-menu'; diff --git a/src/js/front-end/menus/comments-menu.js b/src/js/front-end/menus/comments-menu.js new file mode 100644 index 00000000..2e217c6c --- /dev/null +++ b/src/js/front-end/menus/comments-menu.js @@ -0,0 +1,63 @@ +/** + * Internal dependencies. + */ +import { domReady } from '../utils'; // Global utils. +import { MENU_OPEN_CLASS_NAME } from './consts'; // Menu constants. +import { createOverlay, removeOverlay } from './utils'; // Menu utils. + +// A class name to append to the body element when the comments menu is open. +const openClassName = MENU_OPEN_CLASS_NAME + 'comments-menu'; + +domReady( function () { + /** + * Comments Menu toggle and overlay JavaScript. + */ + const body = document.body, + headerContain = document.querySelector( '.comments-menu' ), + commentsToggle = document.querySelectorAll( '.comments-menu-toggle' ), + commentsContents = document.querySelector( '.comments-contents' ); + + if ( ! headerContain || ! commentsToggle.length || ! commentsContents ) { + return; + } + + const commentsOpenButton = headerContain.querySelector( '.comments-menu-toggle a' ), + commentsCloseButton = commentsContents.querySelector( '.comments-menu-toggle a' ); + + /** + * @description Fires either the opening or closing functions for a menu. + * @param {event} event Click event. + */ + const menuToggle = event => { + event.preventDefault(); + + if ( body.classList.contains( openClassName ) ) { + closeMenu(); + } else { + openMenu(); + } + }; + + /** + * @description Opens specifed slide-out menu. + */ + const openMenu = () => { + body.classList.add( openClassName ); + commentsCloseButton.focus(); + createOverlay(); + }; + + /** + * @description Closes specifed slide-out menu. + */ + const closeMenu = () => { + body.classList.remove( openClassName ); + commentsOpenButton.focus(); + removeOverlay(); + }; + + // Find each comments toggle and attaches an event listener. + for ( let i = 0; i < commentsToggle.length; i++ ) { + commentsToggle[ i ].addEventListener( 'click', menuToggle, false ); + } +} ); diff --git a/src/scss/_base.scss b/src/scss/_base.scss index 8a890c46..9f89b51d 100644 --- a/src/scss/_base.scss +++ b/src/scss/_base.scss @@ -64,14 +64,14 @@ body .has-drop-cap:not(:focus)::first-letter { } } -.newspack-icon-menu .wp-block-button__link::after { - mask: url('../../src/images/icon-menu.svg') 0 0 no-repeat; -} - .newspack-icon-close .wp-block-button__link::after { mask: url('../../src/images/icon-close.svg') 0 0 no-repeat; } +.newspack-icon-menu .wp-block-button__link::after { + mask: url('../../src/images/icon-menu.svg') 0 0 no-repeat; +} + .newspack-icon-search .wp-block-button__link::after { mask: url('../../src/images/icon-search.svg') 0 0 no-repeat; } diff --git a/src/scss/_comments-overlay.scss b/src/scss/_comments-overlay.scss new file mode 100644 index 00000000..601daf8f --- /dev/null +++ b/src/scss/_comments-overlay.scss @@ -0,0 +1,89 @@ +@use 'sass-utils'; +@use 'mixins'; + +/** + * Comments menu styles + */ +.comments-contents { + background: var(--wp--preset--color--base); + inset: 0 -100% 0 auto; + margin: 0; + max-width: var(--wp--custom--width--medium); + opacity: 0; + overflow: auto; + padding: 0 var(--wp--preset--spacing--30) var(--wp--preset--spacing--30); + position: fixed; + right: -100%; + transition: opacity 125ms ease-in-out, right 250ms ease-in-out; + width: 100%; + z-index: sass-utils.$zindex-overlay-menu; + + @include sass-utils.media( medium ) { + padding: 0 var(--wp--preset--spacing--40) var(--wp--preset--spacing--40); + } + + .admin-bar & { + @include sass-utils.media( small ) { + padding-top: 46px; + } + + @include sass-utils.media( medium ) { + padding-top: 32px; + } + } + + > * { + visibility: hidden; + } +} + +.comments-menu-toggle { + &.newspack-icon-close { + display: grid; + height: 48px; + margin-right: calc( -1 * var(--wp--preset--spacing--30) ); + place-items: center; + width: 48px; + + @include sass-utils.media( medium ) { + height: 64px; + margin-right: calc( -1 * var(--wp--preset--spacing--40) ); + width: 64px; + } + } + + &:not( .newspack-icon-close ) { + .wp-block-button__link { + align-items: center; + display: inline-flex; + gap: var(--wp--preset--spacing--20); + justify-content: center; + + &::before { + background: currentcolor; + content: ""; + height: 24px; + mask: url('../../src/images/icon-comments.svg') 0 0 no-repeat; + width: 24px; + } + } + } +} + +.menu-open--comments-menu { + .comments-contents { + opacity: 1; + right: 0; + + @include mixins.elevation( 3 ); + + > * { + visibility: visible; + } + } + + .overlay-mask { + display: block; + opacity: 1; + } +} diff --git a/src/scss/_forms.scss b/src/scss/_forms.scss new file mode 100644 index 00000000..d13b437e --- /dev/null +++ b/src/scss/_forms.scss @@ -0,0 +1,48 @@ +@use 'mixins'; + +/* + * Form Styles + * https://github.com/WordPress/gutenberg/issues/34198 + */ +label { + color: var(--wp--preset--color--contrast); + display: inline-block; + font-family: var( --wp--preset--font-family--system-font ); + font-size: var(--wp--preset--font-size--small); + font-weight: 600; + line-height: var(--wp--custom--line-height--small); + margin-bottom: var(--wp--preset--spacing--20); +} + +input[type='text'], +input[type='email'], +input[type='url'], +input[type='password'], +input[type='search'], +input[type='number'], +input[type='tel'], +input[type='range'], +input[type='date'], +input[type='month'], +input[type='week'], +input[type='time'], +input[type='datetime'], +input[type='datetime-local'], +input[type='zip'], +input[type='color'], +textarea { + @include mixins.input; +} + +input[type='checkbox'], +input[type='radio'] { + @include mixins.checkbox-radio; +} + +input[type='checkbox'] { + @include mixins.checkbox; +} + +input[type='radio'] { + @include mixins.radio; +} \ No newline at end of file diff --git a/src/scss/_gutenberg-shim.scss b/src/scss/_gutenberg-shim.scss index 1c83b103..2a7d1215 100644 --- a/src/scss/_gutenberg-shim.scss +++ b/src/scss/_gutenberg-shim.scss @@ -1,5 +1,3 @@ -@use 'mixins'; - // Add CSS for theme.json options that don't exist yet. /* @@ -69,40 +67,6 @@ figcaption a { } } -/* - * Form Styles - * https://github.com/WordPress/gutenberg/issues/34198 - */ -label { - color: var(--wp--preset--color--contrast); - display: inline-block; - font-family: var( --wp--preset--font-family--system-font ); - font-size: var(--wp--preset--font-size--small); - font-weight: 600; - line-height: var(--wp--custom--line-height--small); - margin-bottom: var(--wp--preset--spacing--20); -} - -input[type='text'], -input[type='email'], -input[type='url'], -input[type='password'], -input[type='search'], -input[type='number'], -input[type='tel'], -input[type='range'], -input[type='date'], -input[type='month'], -input[type='week'], -input[type='time'], -input[type='datetime'], -input[type='datetime-local'], -input[type='zip'], -input[type='color'], -textarea { - @include mixins.input; -} - /* * Editor styles * diff --git a/src/scss/_header.scss b/src/scss/_header.scss index 38d71c67..1bbabc81 100644 --- a/src/scss/_header.scss +++ b/src/scss/_header.scss @@ -19,16 +19,19 @@ // Overlay .overlay-mask { - background: var(--wp--custom--color--mobile-menu-overlay); + background: var( --wp--custom--color--mobile-menu-overlay ); content: ''; display: none; inset: 0; + opacity: 0; position: fixed; - z-index: sass-utils.$zindex-overlay-menu; + transition: opacity 125ms ease-in-out; + z-index: sass-utils.$zindex-overlay-mask; } .menu-open--mobile-menu .overlay-mask { display: block; + opacity: 1; } // Mobile sidebar @@ -42,7 +45,7 @@ position: fixed; transition: opacity 0.2s; width: 100%; - z-index: 999999; + z-index: sass-utils.$zindex-overlay-menu; > * { visibility: hidden; @@ -57,10 +60,10 @@ .mobile-sidebar { opacity: 1; right: 0; - } - .mobile-sidebar > * { - visibility: visible; + > * { + visibility: visible; + } } } diff --git a/src/scss/_mixins.scss b/src/scss/_mixins.scss index 51ff223c..81361e55 100644 --- a/src/scss/_mixins.scss +++ b/src/scss/_mixins.scss @@ -14,14 +14,9 @@ } &:focus { - border-color: var( --wp--preset--color--contrast-3 ); - outline: 2px solid var( --wp--preset--color--contrast-3 ); + border-color: var( --wp--preset--color--contrast ); + outline: 2px solid var( --wp--preset--color--contrast ); outline-offset: -1px; - - @media ( prefers-contrast: more ) { - border-color: var( --wp--preset--color--contrast ); - outline-color: var( --wp--preset--color--contrast ); - } } &:disabled { @@ -35,6 +30,85 @@ } } +@mixin checkbox-radio { + appearance: none; + background: white; + border: 1px solid var( --wp--preset--color--base-4 ); + color: white; + cursor: pointer; + display: inline-grid; + font: inherit; + height: 20px !important; + margin: 2px 0 0; + place-content: center; + transition: background-color 125ms ease-in-out, border-color 125ms ease-in-out, outline 125ms ease-in-out; + width: 20px !important; + + @media ( prefers-contrast: more ) { + border-color: var( --wp--preset--color--contrast-3 ); + } + + &::before { + content: ''; + display: block; + opacity: 0; + } + + &:checked { + &::before { + opacity: 1; + } + } + + &:focus-visible { + outline: 2px solid var( --wp--preset--color--contrast ); + outline-offset: 1px; + + &:not( :checked ) { + border: 0; + outline-offset: -1px; + } + } + + &:disabled { + cursor: not-allowed; + opacity: 0.75; + } +} + +@mixin checkbox { + border-radius: var( --wp--custom--border--radius-xx-small ); + + &::before { + background: transparent + url( "data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' width='24' height='24'%3E%3Cpath d='M16.7 7.1l-6.3 8.5-3.3-2.5-.9 1.2 4.5 3.4L17.9 8z' fill='white'%3E%3C/path%3E%3C/svg%3E" ) + 0 0 no-repeat; + height: 24px; + width: 24px; + } + + &:checked { + background: var( --wp--preset--color--contrast ); + border-color: transparent; + } +} + +@mixin radio { + border-radius: 100%; + + &::before { + background: var( --newspack-ui-color-neutral-0 ); + border-radius: 100%; + height: var(--wp--preset--spacing--20); + width: var(--wp--preset--spacing--20); + } + + &:checked { + background: var( --wp--preset--color--contrast ); + border-color: var( --wp--preset--color--contrast ); + } +} + @mixin button-icon { background: transparent; display: grid; @@ -55,6 +129,16 @@ } } +@mixin elevation($size: 1) { + @if $size == 1 { + box-shadow: 0 1px 10px rgba( 0, 0, 0, 0.07 ); + } @else if $size == 2 { + box-shadow: 0 2px 20px rgba( 0, 0, 0, 0.14 ); + } @else if $size == 3 { + box-shadow: 0 3px 30px rgba( 0, 0, 0, 0.21 ); + } +} + @mixin notice( $type, $margin: var( --wp--preset--spacing--50 ) 0 ) { --np--notice--color--border: var( --wp--custom--color--neutral-90 ); --np--notice--color--background: var( --wp--custom--color--neutral-5 ); diff --git a/src/scss/_sass-utils.scss b/src/scss/_sass-utils.scss index 9f0ea20b..ff456a39 100644 --- a/src/scss/_sass-utils.scss +++ b/src/scss/_sass-utils.scss @@ -11,6 +11,7 @@ $xlarge-screen: 1312px; // Z-indexes $zindex-sticky-header: 1000; +$zindex-overlay-mask: 1999; $zindex-overlay-menu: 2000; $zindex-screen-reader-text: 100000; /* Above WP toolbar. */ diff --git a/src/scss/blocks/_post-comments.scss b/src/scss/blocks/_post-comments.scss index 3fe75f06..485630d3 100644 --- a/src/scss/blocks/_post-comments.scss +++ b/src/scss/blocks/_post-comments.scss @@ -4,8 +4,8 @@ form { display: flex; flex-direction: column; - gap: var(--wp--preset--spacing--50); - margin-top: var(--wp--preset--spacing--50); + gap: var(--wp--preset--spacing--30); + margin-top: var(--wp--preset--spacing--30); p { margin-top: 0; @@ -28,26 +28,132 @@ @include mixins.input; } - .bypostauthor { - // we probably don't want to inline text via CSS; can we filter the author post? + input[type="checkbox"] { + @include mixins.checkbox-radio; + @include mixins.checkbox; + } + + .comment-reply-title { + margin-top: 0; + font-size: var(--wp--preset--font-size--medium); + font-weight: 600; + line-height: var(--wp--custom--line-height--medium); + } + + .comment-form-cookies-consent { + gap: var(--wp--preset--spacing--20); + + input[type='checkbox'] { + margin-top: 2px !important; + } + + label { + font-weight: normal; + margin-bottom: 0; + } + } + + .comment-form-url { + display: none; + } + + .required { + color: var(--wp--custom--color--error-50); + } + + .required-field-message { + display: block; } } .wp-block-comment-template { - > li { + ol { + border-left: 1px solid var( --wp--preset--color--base-3 ); + margin: var(--wp--preset--spacing--50) 0 0; + padding-left: var(--wp--preset--spacing--50); + } + + .comment { + font-size: var(--wp--preset--font-size--small); + line-height: var(--wp--custom--line-height--small); + &:not(:first-of-type) { padding-top: var(--wp--preset--spacing--50); } &:not(:last-of-type) { - border-bottom: 1px solid var(--wp--custom--color--gray-300); + border-bottom: 1px solid var( --wp--preset--color--base-3 ); padding-bottom: var(--wp--preset--spacing--50); } } - ol { - border-left: 1px solid var(--wp--custom--color--gray-300); + .comment-respond { margin: var(--wp--preset--spacing--50) 0 0; - padding-left: var(--wp--preset--spacing--50); + + .comment-reply-title { + align-items: baseline; + display: flex; + flex-wrap: wrap; + gap: var(--wp--preset--spacing--20); + justify-content: space-between; + + a { + color: inherit; + } + + small { + font-size: var(--wp--preset--font-size--small); + font-weight: 400; + line-height: var(--wp--custom--line-height--small); + margin: 0; + } + } + } +} + +.wp-block-comment-content { + > * { + margin: var(--wp--preset--spacing--30) 0; + } + + .comment-awaiting-moderation { + font-size: inherit; + line-height: inherit; } } + +.wp-block-comment-author-name { + a { + border-radius: var(--wp--custom--border--radius-x-small); + transition: color 125ms ease-in-out; + } + + .bypostauthor & { + background: var(--wp--preset--color--base-2); + border-radius: var(--wp--custom--border--radius-x-small); + + &:not( :has(a) ) { + padding: 0 0.375em; + } + + a { + display: block; + padding: 0 0.375em; + + &:focus { + outline-offset: -3px; + } + } + } +} + +.wp-block-comments-pagination { + border-top: 1px solid var(--wp--preset--color--base-3); + padding-top: var(--wp--preset--spacing--30); + + > .wp-block-comments-pagination-next, + > .wp-block-comments-pagination-numbers, + > .wp-block-comments-pagination-previous { + margin: 0; + } +} \ No newline at end of file diff --git a/src/scss/blocks/_query-pagination.scss b/src/scss/blocks/_query-pagination.scss index 084addf1..e63769d8 100644 --- a/src/scss/blocks/_query-pagination.scss +++ b/src/scss/blocks/_query-pagination.scss @@ -1,18 +1,19 @@ @use '../sass-utils'; +.wp-block-comments-pagination, .wp-block-query-pagination { a, .current, - .wp-block-query-pagination-numbers, - .wp-block-comments-pagination-numbers { + .wp-block-comments-pagination-numbers, + .wp-block-query-pagination-numbers { align-items: center; display: flex; justify-content: center; } - .wp-block-query-pagination-numbers, - .wp-block-comments-pagination-numbers { - gap: calc(var(--wp--preset--spacing--20) / 4); + .wp-block-comments-pagination-numbers, + .wp-block-query-pagination-numbers { + gap: calc(var(--wp--preset--spacing--20) / 2); a, .current { @@ -23,7 +24,9 @@ @include sass-utils.all-transition; } } +} +.wp-block-query-pagination { // Justification = Space Between &.is-content-justification-space-between { @include sass-utils.media(small) { @@ -50,4 +53,4 @@ } } } -} +} \ No newline at end of file diff --git a/src/scss/style.scss b/src/scss/style.scss index 0aaddc18..aa97d5f3 100644 --- a/src/scss/style.scss +++ b/src/scss/style.scss @@ -1,8 +1,10 @@ @import url('./_theme-description.scss'); @import url('./_css-variables.scss'); @import url('./_base.scss'); +@import url('./_forms.scss'); @import url('./_gutenberg-shim.scss'); @import url('./blocks/_blocks.scss'); @import url('./block-styles/_block-styles.scss'); @import url('./_header.scss'); +@import url('./_comments-overlay.scss'); @import url('./_search-overlay.scss'); diff --git a/templates/single.html b/templates/single.html index 936e68ab..e8c3a4e6 100644 --- a/templates/single.html +++ b/templates/single.html @@ -21,7 +21,7 @@ -
+
\ No newline at end of file diff --git a/templates/single/large-image.html b/templates/single/large-image.html index 7a0a151f..df9a4077 100644 --- a/templates/single/large-image.html +++ b/templates/single/large-image.html @@ -27,7 +27,7 @@ -
+
\ No newline at end of file diff --git a/theme.json b/theme.json index 8d46c669..b44e7c5f 100644 --- a/theme.json +++ b/theme.json @@ -233,6 +233,12 @@ "xxxx-large": "1.125", "xxxxx-large": "1.1", "xxxxxx-large": "1.08333333333" + }, + "width": { + "x-small": "300px", + "small": "410px", + "medium": "632px", + "large": "964px" } } }, @@ -310,35 +316,36 @@ "color": { "text": "var( --wp--preset--color--contrast )" }, + ":hover": { + "color": { + "text": "var( --wp--preset--color--contrast-3 )" + } + }, "typography": { "textDecoration": "none" } } }, "typography": { - "fontSize": "var( --wp--preset--font-size--medium )", - "fontWeight": "700" + "fontSize": "var( --wp--preset--font-size--small )", + "lineHeight": "var( --wp--custom--line-height--small )", + "fontWeight": "600" } }, "core/comment-date": { + "color": { + "text": "var( --wp--preset--color--contrast-3 )" + }, "elements": { "link": { "color": { - "text": "var( --wp--preset--color--contrast-3 )" - }, - ":hover": { - "typography": { - "textDecoration": "underline" - } - }, - "typography": { - "textDecoration": "none" + "text": "inherit" } } }, "typography": { - "fontSize": "var( --wp--preset--font-size--small )", - "lineHeight": "var( --wp--custom--line-height--small )" + "fontSize": "var( --wp--preset--font-size--x-small )", + "lineHeight": "var( --wp--custom--line-height--x-small )" } }, "core/comment-edit-link": { @@ -350,8 +357,8 @@ } }, "typography": { - "fontSize": "var( --wp--preset--font-size--small )", - "lineHeight": "var( --wp--custom--line-height--small )" + "fontSize": "var( --wp--preset--font-size--x-small )", + "lineHeight": "var( --wp--custom--line-height--x-small )" } }, "core/comment-reply-link": { @@ -363,8 +370,21 @@ } }, "typography": { - "fontSize": "var( --wp--preset--font-size--small )", - "lineHeight": "var( --wp--custom--line-height--small )" + "fontSize": "var( --wp--preset--font-size--x-small )", + "lineHeight": "var( --wp--custom--line-height--x-small )" + } + }, + "core/comments-title": { + "spacing": { + "margin": { + "bottom": 0, + "top": "var( --wp--preset--spacing--80 )" + } + }, + "typography": { + "fontSize": "var( --wp--preset--font-size--medium )", + "fontWeight": 600, + "lineHeight": "var( --wp--custom--line-height--medium )" } }, "core/post-comments-form": { @@ -389,11 +409,32 @@ } } }, + "spacing": { + "blockGap": "var( --wp--preset--spacing--30 )", + "margin": { + "top": "var( --wp--preset--spacing--50 )" + } + }, "typography": { "fontSize": "var( --wp--preset--font-size--small )", + "fontWeight": "500", "lineHeight": "var( --wp--custom--line-height--small )" } }, + "core/comments-pagination-numbers": { + "elements": { + "link": { + ":hover": { + "color": { + "background": "var( --wp--preset--color--base-2 )" + }, + "typography": { + "textDecoration": "none !important" + } + } + } + } + }, "core/gallery": { "spacing": { "margin": { @@ -642,6 +683,12 @@ }, "color": { "text": "var( --wp--preset--color--base-3 )" + }, + "spacing": { + "margin": { + "bottom": "0", + "top": "var( --wp--preset--spacing--50 )" + } } }, "core/social-links": {