-
Notifications
You must be signed in to change notification settings - Fork 3
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* Add WIP Comment component * Add size.edge.control token * Add Jabber and lodash Typescript definitions Co-authored-by: Caleb Eby <[email protected]>
- Loading branch information
1 parent
60baacf
commit 157fad1
Showing
13 changed files
with
5,092 additions
and
11,630 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
--- | ||
'@cloudfour/patterns': minor | ||
--- | ||
|
||
Add initial version of Comment component |
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,131 @@ | ||
@use 'sass:math'; | ||
@use '../../compiled/tokens/scss/color'; | ||
@use '../../compiled/tokens/scss/font-weight'; | ||
@use '../../compiled/tokens/scss/size'; | ||
@use '../../mixins/headings'; | ||
@use '../../mixins/theme'; | ||
|
||
.c-comment { | ||
display: grid; | ||
grid-column-gap: size.$spacing-gap-inline-medium; | ||
grid-row-gap: size.$rhythm-condensed; | ||
grid-template-areas: | ||
'object header' | ||
'thread-line content' | ||
'thread-line footer'; | ||
// We set the object column size directly (instead of relying on `auto`) | ||
// because the container for child comments will be setting a negative margin | ||
// based on this value, and we don't want the layout to break if the wrong | ||
// avatar size is set in the HTML. | ||
grid-template-columns: #{size.$square-avatar-small} 1fr; | ||
grid-template-rows: minmax(0, auto) 1fr minmax(0, auto); | ||
} | ||
|
||
/// Display a vertical line if the comment contains a reply thread to connect | ||
/// those comments visually with their parent. | ||
.c-comment--thread::after { | ||
border-radius: size.$border-radius-full; | ||
content: ''; | ||
display: block; | ||
grid-area: thread-line; | ||
height: 100%; | ||
margin-left: auto; | ||
margin-right: auto; | ||
width: size.$edge-medium; | ||
|
||
@include theme.styles() { | ||
background-color: color.$base-gray-light; | ||
} | ||
|
||
@include theme.styles(dark) { | ||
background-color: color.$base-blue-darker; | ||
} | ||
} | ||
|
||
/// Named object for consistency with the Media component. | ||
.c-comment__object { | ||
grid-area: object; | ||
} | ||
|
||
.c-comment__header { | ||
// We generally want comment contents to align to the start/top, but the | ||
// heading looks better center-aligned with the avatar. | ||
align-self: center; | ||
grid-area: header; | ||
} | ||
|
||
/// The heading level will change depending on comment depth, but we want it to | ||
/// appear consistent. We lighten the weight a bit from usual headings to offset | ||
/// it from the main article/page content. | ||
.c-comment__heading { | ||
@include headings.level($level: 3, $include-weight: false); | ||
font-weight: font-weight.$semibold; | ||
} | ||
|
||
.c-comment__content { | ||
grid-area: content; | ||
// The fluid heading size changes depending on the viewport, but the content | ||
// always looks just a *tad* close to the header. This offsets that. | ||
margin-top: math.div(size.$rhythm-condensed, -4); | ||
} | ||
|
||
.c-comment__footer { | ||
grid-area: footer; | ||
} | ||
|
||
.c-comment__meta { | ||
align-items: center; | ||
display: flex; | ||
flex-wrap: wrap; | ||
} | ||
|
||
.c-comment__meta-detail { | ||
color: var(--theme-color-text-muted); | ||
|
||
&:not(:last-child) { | ||
margin-right: size.$spacing-gap-inline-small; | ||
} | ||
} | ||
|
||
/// We don't want to reduce the padding of a button, but we also don't want the | ||
/// overall height of the meta elements changing between comments with a button | ||
/// and comments without. This negates the margin on the button's container | ||
/// to minimize this layout shift. | ||
/// | ||
/// The horizontal value is less than the vertical value to account for the | ||
/// possibility of icons being present (which rest closer to the edge than the | ||
/// text label would on its own). | ||
.c-comment__meta-control { | ||
// If the edge and padding sizes for controls use the same units, just crunch | ||
// the numbers in Sass. Otherwise, use `calc` to do it in the browser. | ||
@if (math.compatible(size.$edge-control, size.$padding-control-vertical)) { | ||
margin: ((size.$edge-control + size.$padding-control-vertical) * -1) | ||
(math.div((size.$edge-control + size.$padding-control-horizontal), -2)); | ||
} @else { | ||
margin: calc( | ||
(#{size.$edge-control} + #{size.$padding-control-vertical}) * -1 | ||
) | ||
calc((#{size.$edge-control} + #{size.$padding-control-horizontal}) / -2); | ||
} | ||
} | ||
|
||
/// Normally we would avoid obscuring links, but in this case things like | ||
/// permalinks and source links are quite tertiary in comparison to the main | ||
/// content. I found several accessibility resources that also do this in their | ||
/// comments (Deque being the most prominent example), so I feel okay about it! | ||
.c-comment__meta-link { | ||
&:not(:hover):not(:focus) { | ||
color: inherit; | ||
text-decoration: inherit; | ||
} | ||
} | ||
|
||
.c-comment__replies { | ||
// Visually centers the child avatars with the indentation of the parent | ||
// comment. Without this, the replies feel nested too far to the right. | ||
margin-left: math.div(size.$square-avatar-small, -2); | ||
// Since the replies are likely wrapped in a Rhythm object intended to inherit | ||
// the parent rhythm, we can use that custom property to inherit that same | ||
// spacing between the meta and replies. | ||
margin-top: var(--rhythm, #{size.$rhythm-default}); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,78 @@ | ||
import { Story, Canvas, Meta } from '@storybook/addon-docs/blocks'; | ||
import { makeComment } from './demo/data.ts'; | ||
import template from './comment.twig'; | ||
|
||
<Meta title="Components/Comment" /> | ||
|
||
# Comment | ||
|
||
Displays a single comment in a comment thread, optionally with replies. Multiple comments can be displayed within [a Rhythm layout object](/docs/objects-rhythm--default-story). | ||
|
||
## Status | ||
|
||
This component is still a work in progress. The following features are still in development: | ||
|
||
- Indicating when a comment's author is a Cloud Four team member. | ||
- Displaying a message when a comment is not yet approved. | ||
- Integrating the comment reply form. | ||
- Adding blocks to the template to allow for more customization. | ||
|
||
## Single | ||
|
||
At minimum, a single comment consists of: | ||
|
||
- Author name | ||
- Author avatar | ||
- Comment content (HTML) | ||
- Publication date | ||
- Permalink to the comment | ||
|
||
This information may be passed to the component as a `comment` object matching the structure of a [Timber comment](https://timber.github.io/docs/reference/timber-comment/). | ||
|
||
<Canvas> | ||
<Story name="Single">{template({ comment: makeComment() })}</Story> | ||
</Canvas> | ||
|
||
## With source | ||
|
||
Additionally, a `source` object may be passed to the template consisting of a `url` and `name`. This is helpful if integrating [webmentions](https://indieweb.org/Webmention) into comment threads. | ||
|
||
<Canvas> | ||
<Story name="With source"> | ||
{template({ | ||
comment: makeComment(), | ||
source: { | ||
url: 'https://twitter.com/smashingmag/status/1371521325236416516', | ||
name: 'twitter.com', | ||
}, | ||
})} | ||
</Story> | ||
</Canvas> | ||
|
||
## With reply button | ||
|
||
This feature is still a work in progress. | ||
|
||
<Canvas> | ||
<Story name="With reply button"> | ||
{template({ | ||
comment: makeComment(), | ||
demo_control: true, | ||
})} | ||
</Story> | ||
</Canvas> | ||
|
||
## With reply thread | ||
|
||
If a `comment` contains an array of `children`, they will be display in the footer of the original comment. A vertical line is used to visually associate the replies with the original comment. If the parent comment is contained within [a Rhythm layout object](/docs/objects-rhythm--default-story),the child comments will inherit that spacing. | ||
|
||
While it is theoretically possible to infinitely nest `children`, it's recommended to limit the depth to a single level. This is for two reasons: | ||
|
||
- Increasingly narrow comments will become difficult to read on narrow screens. | ||
- The heading levels for comment threads increment up to a maximum of six (since HTML only provides six heading levels). This means that levels beyond that will be harder to traverse for user agents navigating via the document outline. | ||
|
||
<Canvas> | ||
<Story name="With reply thread"> | ||
{template({ comment: makeComment({ replies: 2 }) })} | ||
</Story> | ||
</Canvas> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,90 @@ | ||
{% set _heading_depth = min(heading_depth|default(3), 6) %} | ||
|
||
<article class="c-comment{% if comment.children is not empty %} c-comment--thread{% endif %}" id="comment-{{comment.ID}}"> | ||
<header class="c-comment__header"> | ||
<h{{_heading_depth}} class="c-comment__heading"> | ||
{{comment.author.name}} | ||
<span class="u-hidden-visually"> | ||
{% if comment.is_child %}replied{% else %}said{% endif %}: | ||
</span> | ||
</h{{_heading_depth}}> | ||
</header> | ||
<div class="c-comment__object"> | ||
{% include '@cloudfour/components/avatar/avatar.twig' with { | ||
src: comment.avatar, | ||
size: 'full' | ||
} only %} | ||
</div> | ||
{% embed '@cloudfour/objects/rhythm/rhythm.twig' with { | ||
class: 'c-comment__content o-rhythm--condensed' | ||
} %} | ||
{% block content %} | ||
{{comment.comment_content|raw}} | ||
{% endblock %} | ||
{% endembed %} | ||
<footer class="c-comment__footer"> | ||
<div class="c-comment__meta"> | ||
<div class="c-comment__meta-detail"> | ||
<a class="c-comment__meta-link" | ||
href="{{comment.link}}"> | ||
<span class="c-comment__meta-icon"> | ||
{% include '@cloudfour/components/icon/icon.twig' with { | ||
name: 'link', | ||
inline: true, | ||
aria_hidden: 'true', | ||
} only %} | ||
</span> | ||
<span class="u-hidden-visually"> | ||
Permalink to {{comment.author.name}}’s | ||
</span> | ||
<time datetime="{{comment.date|date('Y-m-d')}}"> | ||
{{comment.date|date('M j, Y')}} | ||
</time> | ||
<span class="u-hidden-visually"> | ||
{% if comment.is_child %}reply{% else %}comment{% endif %} | ||
</span> | ||
</a> | ||
</div> | ||
{% if source %} | ||
<div class="c-comment__meta-detail"> | ||
via <a class="c-comment__meta-link" href="{{source.url}}">{{source.name}}</a> | ||
</div> | ||
{% endif %} | ||
{# | ||
TODO: Replace `demo_control` with a more meaningful block or properties | ||
once we have a better idea of how we want to implement the reply | ||
functionality. For now, this property exists to allow us to test the | ||
presentation of the control. | ||
#} | ||
{% if demo_control %} | ||
<div class="c-comment__meta-control"> | ||
{% include '@cloudfour/components/button/button.twig' with { | ||
type: 'button', | ||
class: 'c-button--tertiary', | ||
content_start_icon: 'speech-balloon', | ||
label: 'Reply' | ||
} only %} | ||
</div> | ||
{% endif %} | ||
</div> | ||
{% if comment.children is not empty %} | ||
{% set _section_heading_depth = min(_heading_depth + 1, 6) %} | ||
{% set _child_heading_depth = min(_section_heading_depth + 1, 6) %} | ||
<h{{_section_heading_depth}} class="u-hidden-visually"> | ||
Replies to {{comment.author.name}} | ||
</h{{_section_heading_depth}}> | ||
{% embed '@cloudfour/objects/rhythm/rhythm.twig' with { | ||
class: 'c-comment__replies' | ||
} %} | ||
{% block content %} | ||
{% for child in comment.children %} | ||
{% include '@cloudfour/components/comment/comment.twig' with { | ||
comment: child, | ||
heading_depth: _child_heading_depth | ||
} only %} | ||
{% endfor %} | ||
{% endblock %} | ||
{% endembed %} | ||
{% endif %} | ||
</footer> | ||
</article> |
Oops, something went wrong.