Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(article-footer): redesign footer + add feedback buttons #10625

Merged
merged 31 commits into from
Mar 5, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
82bf12a
refactor(article-footer): rename Metadata => ArticleFooter
caugner Mar 1, 2024
043c4bf
enhance(article-footer): apply new structure
caugner Mar 1, 2024
a6cd303
fix(article-footer): consolidate CSS
caugner Mar 1, 2024
82d7445
refactor(article-footer): extract Contribute component
caugner Mar 1, 2024
bcc7489
feat(article-footer): add feedback buttons
caugner Mar 1, 2024
4ad4cf3
feat(article-footer): add background image
caugner Mar 1, 2024
8c4ebe0
fix(article-footer): avoid layout shift on vote
caugner Mar 1, 2024
cfaf915
refactor(document): move article-footer out of main-page-content
caugner Mar 1, 2024
e8b92a4
chore(article-footer): replace pipe by bullet
caugner Mar 1, 2024
2d3bc43
feat(article-footer): add feedback form on "No" vote
caugner Mar 1, 2024
e4e94a8
fixup! refactor(document): move article-footer out of main-page-content
caugner Mar 1, 2024
3221139
Merge branch 'main' into MP-907-article-footer-redesign
caugner Mar 4, 2024
96b8a33
refactor(article-footer): rename article-footer-{content-container =>…
caugner Mar 4, 2024
720f3d3
fix(article-footer): use 0.75rem margin between form elements
caugner Mar 4, 2024
51d9e93
chore(article-footer): crop background image
caugner Mar 4, 2024
dcfe617
chore(article-footer): move background-image to inner container
caugner Mar 4, 2024
bc13b7f
Revert "fix(article-footer): use 0.75rem margin between form elements"
caugner Mar 4, 2024
a26a117
chore(article-footer): remove label padding
caugner Mar 4, 2024
d615c53
chore(article-footer): remove button margin
caugner Mar 4, 2024
8c797cd
fix(article-footer): restrict label style
caugner Mar 4, 2024
25b5770
chore(article-footer): add consistent 0.5rem margin
caugner Mar 4, 2024
0501173
chore(article-footer): always show Contribute link
caugner Mar 4, 2024
1012974
fixup! chore(article-footer): add consistent 0.5rem margin
caugner Mar 4, 2024
241a612
fix(article-footer): adjust space between thanks and contribute
caugner Mar 4, 2024
6a62d5b
feat(ui): redefine background-tertiary
caugner Mar 4, 2024
8a6fa7c
fix(article-footer): use SVG element + --background-tertiary
caugner Mar 4, 2024
2597912
fixup! fix(article-footer): use SVG element + --background-tertiary
caugner Mar 4, 2024
b1c10c1
chore(article-footer): use single heading
caugner Mar 4, 2024
952c91f
chore(article-footer): remove periods from GitHub links
caugner Mar 4, 2024
9edb36c
chore(article-footer): reuse thumbs key to reuse queries
caugner Mar 5, 2024
e1a178d
fixup! chore(article-footer): reuse thumbs key to reuse queries
caugner Mar 5, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions client/src/assets/article-footer/article-footer.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
7 changes: 5 additions & 2 deletions client/src/document/index.scss
Original file line number Diff line number Diff line change
Expand Up @@ -254,10 +254,13 @@

@media screen and (min-width: $screen-sm) {
padding: 3rem;
// Reduce space to article footer.
padding-bottom: 0;
}

@media screen and (min-width: $screen-md) {
margin-bottom: 0.5rem;
// Reduce space to article footer.
margin-bottom: 0;
padding: 0;
}
}
Expand All @@ -276,7 +279,7 @@ table {
width: 100%;

th {
background: var(--background-tertiary);
background: var(--background-primary);
font-weight: var(--font-body-strong-weight);
line-height: 1.5;
text-align: left;
Expand Down
4 changes: 2 additions & 2 deletions client/src/document/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ import { RenderSideBar } from "./organisms/sidebar";
import { RetiredLocaleNote } from "./molecules/retired-locale-note";
import { MainContentContainer } from "../ui/atoms/page-content";
import { Loading } from "../ui/atoms/loading";
import { Metadata } from "./organisms/metadata";
import { ArticleFooter } from "./organisms/article-footer";
import { PageNotFound } from "../page-not-found";

import "./index.scss";
Expand Down Expand Up @@ -265,8 +265,8 @@ export function Document(props /* TODO: define a TS interface for this */) {
</header>
<DocumentSurvey doc={doc} />
<RenderDocumentBody doc={doc} />
<Metadata doc={doc} locale={locale} />
</article>
<ArticleFooter doc={doc} locale={locale} />
</MainContentContainer>
{false && <PlayQueue standalone={true} />}
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
}

th {
background: var(--background-tertiary);
background: var(--background-primary);
padding: 0.4rem;
vertical-align: bottom;
}
Expand Down
56 changes: 7 additions & 49 deletions client/src/document/on-github.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,59 +3,17 @@ import { Doc } from "../../../libs/types/document";
export function OnGitHubLink({ doc }: { doc: Doc }) {
return (
<div id="on-github" className="on-github">
<h3>Found a content problem with this page?</h3>
<ul>
<li>
<EditOnGitHubLink doc={doc}>Edit the page on GitHub</EditOnGitHubLink>
.
</li>
<li>
<NewIssueOnGitHubLink doc={doc}>
Report the content issue
</NewIssueOnGitHubLink>
.
</li>
<li>
<SourceOnGitHubLink doc={doc}>
View the source on GitHub
</SourceOnGitHubLink>
.
</li>
</ul>
Want to get more involved?{" "}
<a
href="https://github.com/mdn/content/blob/main/CONTRIBUTING.md"
title={`This will take you to our contribution guidelines on GitHub.`}
target="_blank"
rel="noopener noreferrer"
>
Learn how to contribute
</a>
.
<SourceOnGitHubLink doc={doc}>
View this page on GitHub
</SourceOnGitHubLink>
•{" "}
<NewIssueOnGitHubLink doc={doc}>
Report a problem with this content
</NewIssueOnGitHubLink>
</div>
);
}

function EditOnGitHubLink({
doc,
children,
}: {
doc: Doc;
children: React.ReactNode;
}) {
const { github_url } = doc.source;
return (
<a
href={github_url.replace("/blob/", "/edit/")}
title={`This will take you to GitHub, where you'll need to sign in first.`}
target="_blank"
rel="noopener noreferrer"
>
{children}
</a>
);
}

const METADATA_TEMPLATE = `
<!-- Do not make changes below this line -->
<details>
Expand Down
105 changes: 105 additions & 0 deletions client/src/document/organisms/article-footer/index.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
@use "../../../ui/vars" as *;

.article-footer {
background-color: var(--background-secondary);
border: 1px solid var(--border-primary);
border-radius: var(--elem-radius);
box-shadow: var(--shadow-01);
margin: 0;
padding: 1rem;

@media screen and (max-width: $screen-md) {
margin: 3rem;
// Reduce space to article content.
margin-top: 0;
}

.article-footer-inner {
margin: 0 auto;
max-width: 1440px;
width: 100%;

.svg-container {
position: relative;

svg {
height: auto;
position: absolute;
right: 0;
top: 0;
width: 25%;
}
}

h2 {
margin-top: 0;
padding: 0;
}

.feedback {
border: none;
margin: 0;
margin-bottom: 0.25rem;
padding: 0;

> label {
display: block;
margin-bottom: 0.25rem;
}

.thank-you {
display: block;
margin-bottom: calc(2.75rem + 2px);
}

.button-container {
// Ensure both buttons take minimal width.
display: inline-flex;
gap: 0.75rem;
margin: 0.25rem 0;
}

button {
// Ensure both buttons have same size.
flex: 1;
min-width: 0;

&:not(:hover) {
--button-bg: var(--background-secondary);
--button-color: var(--text-primary);
}

&.yes {
--button-bg-hover: var(--text-primary-green);
}

&.no {
--button-bg-hover: var(--text-primary-red);
}
}

.button-wrap {
display: flex;
// Increase space between icon and button label.
gap: 0.5rem;
padding: 1rem;
}

.radio-container {
align-items: center;
display: flex;
gap: 0.25rem;
margin: 0.25rem 0;
}
}

.contribute {
margin-top: 0.25rem;
}

.last-modified-date {
margin-bottom: 0;
margin-top: 3rem;
}
}
}
154 changes: 154 additions & 0 deletions client/src/document/organisms/article-footer/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,154 @@
import { useState } from "react";
import { Button } from "../../../ui/atoms/button";
import { OnGitHubLink } from "../../on-github";
import { ReactComponent as ArticleFooterSVG } from "../../../assets/article-footer/article-footer.svg";
import "./index.scss";
import { useGleanClick } from "../../../telemetry/glean-context";
import { ARTICLE_FOOTER, THUMBS } from "../../../telemetry/constants";

export function LastModified({ value, locale }) {
if (!value) {
return <span>Last modified date not known</span>;
}
const date = new Date(value);
// Justification for these is to match historically
const dateStringOptions: Intl.DateTimeFormatOptions = {
year: "numeric",
month: "short",
day: "numeric",
};
return (
<>
This page was last modified on{" "}
<time dateTime={value} suppressHydrationWarning>
{date.toLocaleString(locale, dateStringOptions)}
</time>
</>
);
}

export function Authors({ url }) {
return <a href={`${url}/contributors.txt`}>MDN contributors</a>;
}

enum ArticleFooterView {
Vote,
Feedback,
Thanks,
}

type FeedbackReason = "outdated" | "incomplete" | "code_examples" | "other";

const FEEDBACK_REASONS: Required<Record<FeedbackReason, string>> = {
outdated: "Content is out of date",
incomplete: "Missing information",
code_examples: "Code examples not working as expected",
other: "Other",
};

export function ArticleFooter({ doc, locale }) {
const [view, setView] = useState<ArticleFooterView>(ArticleFooterView.Vote);
const [reason, setReason] = useState<FeedbackReason>();

const gleanClick = useGleanClick();

function handleVote(value: boolean) {
setView(value ? ArticleFooterView.Thanks : ArticleFooterView.Feedback);
// Reusing Thumbs' key to be able to reuse queries.
gleanClick(`${THUMBS}: ${ARTICLE_FOOTER} -> ${Number(value)}`);
}

function handleFeedback() {
setView(ArticleFooterView.Thanks);
gleanClick(`${ARTICLE_FOOTER}: feedback -> ${reason}`);
}

return (
<aside className="article-footer">
<div className="article-footer-inner">
<div className="svg-container">
<ArticleFooterSVG role="none" />
</div>
<h2>Help improve MDN</h2>

<fieldset className="feedback">
{view === ArticleFooterView.Vote ? (
<>
<label>Was this page helpful to you?</label>
<div className="button-container">
<Button
icon="thumbs-up"
extraClasses="yes"
onClickHandler={() => handleVote(true)}
>
Yes
</Button>
<Button
icon="thumbs-down"
extraClasses="no"
onClickHandler={() => handleVote(false)}
>
No
</Button>
</div>
</>
) : view === ArticleFooterView.Feedback ? (
<>
<label>Why was this page not helpful to you?</label>
{Object.entries(FEEDBACK_REASONS).map(([key, label]) => (
<div className="radio-container" key={key}>
<input
type="radio"
id={`reason_${key}`}
name="reason"
value={key}
checked={reason === key}
onChange={(event) =>
setReason(event.target.value as FeedbackReason)
}
/>
<label htmlFor={`reason_${key}`}>{label}</label>
</div>
))}
<div className="button-container">
<Button
type="primary"
isDisabled={!reason}
onClickHandler={() => handleFeedback()}
>
Submit
</Button>
</div>
</>
) : (
<span className="thank-you">Thank you for your feedback! ❤️</span>
)}
</fieldset>

<Contribute />
<p className="last-modified-date">
<LastModified value={doc.modified} locale={locale} /> by{" "}
<Authors url={doc.mdn_url} />.
</p>
{doc.isActive && <OnGitHubLink doc={doc} />}
</div>
</aside>
);
}

function Contribute() {
return (
<>
<a
className="contribute"
href="https://github.com/mdn/content/blob/main/CONTRIBUTING.md"
title={`This will take you to our contribution guidelines on GitHub.`}
target="_blank"
rel="noopener noreferrer"
>
Learn how to contribute
</a>
.
</>
);
}
Loading
Loading