Merge pull request #17442 from desktop/fancy-dialog-headers-take-one-thousand

Clickable close button in release notes dialog and fall(ing confetti) cleanup
This commit is contained in:
Markus Olsson 2023-09-27 10:30:50 +02:00 committed by GitHub
commit a101ccd1b8
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
12 changed files with 97 additions and 211 deletions

View file

@ -48,6 +48,7 @@
"quick-lru": "^3.0.0",
"re2js": "^0.3.0",
"react": "^16.8.4",
"react-confetti": "^6.1.0",
"react-css-transition-replace": "^3.0.3",
"react-dom": "^16.8.4",
"react-transition-group": "^4.4.1",

View file

@ -566,6 +566,10 @@ export function buildDefaultMenu({
label: 'Release notes',
click: emit('show-release-notes-popup'),
},
{
label: 'Thank you',
click: emit('show-thank-you-popup'),
},
{
label: 'Pull Request Check Run Failed',
click: emit('pull-request-check-run-failed'),

View file

@ -47,3 +47,4 @@ export type MenuEvent =
| 'show-app-error'
| 'decrease-active-resizable-width'
| 'increase-active-resizable-width'
| 'show-thank-you-popup'

View file

@ -458,6 +458,8 @@ export class App extends React.Component<IAppProps, IAppState> {
return this.selectAll()
case 'show-release-notes-popup':
return this.showFakeReleaseNotesPopup()
case 'show-thank-you-popup':
return this.showFakeThankYouPopup()
case 'show-stashed-changes':
return this.showStashedChanges()
case 'hide-stashed-changes':
@ -497,6 +499,22 @@ export class App extends React.Component<IAppProps, IAppState> {
}
}
private showFakeThankYouPopup() {
if (__DEV__) {
this.props.dispatcher.showPopup({
type: PopupType.ThankYou,
userContributions: [
{
kind: 'new',
message: '[New] Added fake thank you dialog',
},
],
friendlyName: 'kind contributor',
latestVersion: '3.0.0',
})
}
}
private testShowNotification() {
if (
__RELEASE_CHANNEL__ !== 'development' &&

View file

@ -134,6 +134,8 @@ interface IDialogProps {
/** Whether or not to override focus of first element with close button */
readonly focusCloseButtonOnOpen?: boolean
readonly onDialogRef?: (ref: HTMLDialogElement | null) => void
}
/**
@ -677,6 +679,7 @@ export class Dialog extends React.Component<DialogProps, IDialogState> {
}
this.dialogElement = e
this.props.onDialogRef?.(e)
}
private onKeyDown = (event: React.KeyboardEvent) => {

View file

@ -72,10 +72,6 @@ export class DialogHeader extends React.Component<IDialogHeaderProps, {}> {
)
}
private renderTitle() {
return <h1 id={this.props.titleId}>{this.props.title}</h1>
}
public render() {
const spinner = this.props.loading ? (
<Octicon className="icon spin" symbol={syncClockwise} />
@ -83,7 +79,7 @@ export class DialogHeader extends React.Component<IDialogHeaderProps, {}> {
return (
<div className="dialog-header">
{this.renderTitle()}
<h1 id={this.props.titleId}>{this.props.title}</h1>
{spinner}
{this.renderCloseButton()}
{this.props.children}

View file

@ -8,10 +8,6 @@ import { shell } from '../../lib/app-shell'
import { ReleaseNotesUri } from '../lib/releases'
import { OkCancelButtonGroup } from '../dialog/ok-cancel-button-group'
import { DesktopFakeRepository } from '../../lib/desktop-fake-repository'
import {
ReleaseNoteHeaderLeftUri,
ReleaseNoteHeaderRightUri,
} from '../../lib/release-notes'
import { SandboxedMarkdown } from '../lib/sandboxed-markdown'
import { Button } from '../lib/button'
@ -168,22 +164,10 @@ export class ReleaseNotes extends React.Component<IReleaseNotesProps, {}> {
: this.drawSingleColumnLayout(release)
const dialogHeader = (
<div className="release-notes-header">
<img
className="release-note-graphic-left"
src={ReleaseNoteHeaderLeftUri}
alt=""
/>
<div className="title">
<p className="version">Version {latestVersion}</p>
<p className="date">{datePublished}</p>
</div>
<img
className="release-note-graphic-right"
src={ReleaseNoteHeaderRightUri}
alt=""
/>
</div>
<>
<span className="version">Version {latestVersion}</span>
<span className="date">{datePublished}</span>
</>
)
return (

View file

@ -2,13 +2,10 @@
/* eslint-disable jsx-a11y/click-events-have-key-events */
import * as React from 'react'
import { DesktopFakeRepository } from '../../lib/desktop-fake-repository'
import {
ReleaseNoteHeaderLeftUri,
ReleaseNoteHeaderRightUri,
} from '../../lib/release-notes'
import { ReleaseNote } from '../../models/release-notes'
import { Dialog, DialogContent } from '../dialog'
import { RichText } from '../lib/rich-text'
import Confetti from 'react-confetti'
interface IThankYouProps {
readonly onDismissed: () => void
@ -18,7 +15,16 @@ interface IThankYouProps {
readonly latestVersion: string | null
}
export class ThankYou extends React.Component<IThankYouProps, {}> {
interface IThankYouState {
readonly confettiHost?: HTMLDialogElement
readonly confettiRect?: DOMRect
}
export class ThankYou extends React.Component<IThankYouProps, IThankYouState> {
public constructor(props: IThankYouProps) {
super(props)
this.state = {}
}
private renderList(
releaseEntries: ReadonlyArray<ReleaseNote>
): JSX.Element | null {
@ -48,46 +54,40 @@ export class ThankYou extends React.Component<IThankYouProps, {}> {
)
}
private renderConfetti(): JSX.Element | null {
const confetti = new Array<JSX.Element>()
private renderConfetti() {
const { confettiHost } = this.state
if (confettiHost) {
const { left, top } = this.state.confettiRect ?? { left: 0, top: 0 }
const howMuchConfetti = 750
for (let i = 0; i < howMuchConfetti; i++) {
confetti.push(<div key={i} className="confetti"></div>)
return (
<Confetti
recycle={false}
numberOfPieces={750}
width={window.innerWidth}
height={window.innerHeight}
style={{ left, top }}
/>
)
}
return <>{confetti}</>
return undefined
}
private updateConfettiRect = (e: Event) => {
if (e.currentTarget instanceof HTMLElement) {
const { offsetLeft: x, offsetTop: y } = e.currentTarget
const { innerWidth: w, innerHeight: h } = window
const confettiRect = new DOMRect(-Math.round(x), -Math.round(y), w, h)
this.setState({ confettiRect })
}
}
private onDialogRef = (dialog: HTMLDialogElement | null) => {
this.setState({ confettiHost: dialog ?? undefined })
dialog?.addEventListener('dialog-show', this.updateConfettiRect)
}
public render() {
const dialogHeader = (
<div className="release-notes-header">
<div className="header-graphics">
<img
className="release-note-graphic-left"
src={ReleaseNoteHeaderLeftUri}
alt=""
/>
<div className="img-space"></div>
<img
className="release-note-graphic-right"
src={ReleaseNoteHeaderRightUri}
alt=""
/>
</div>
<div className="title">
<div className="thank-you">
Thank you {this.props.friendlyName}!{' '}
<RichText
text={':tada:'}
emoji={this.props.emoji}
renderUrlsAsLinks={true}
/>
</div>
</div>
</div>
)
const version =
this.props.latestVersion !== null ? ` ${this.props.latestVersion}` : ''
const thankYouNote = (
@ -102,7 +102,8 @@ export class ThankYou extends React.Component<IThankYouProps, {}> {
<Dialog
id="thank-you-notes"
onDismissed={this.props.onDismissed}
title={dialogHeader}
title={`Thank you ${this.props.friendlyName}! 🎉`}
onDialogRef={this.onDialogRef}
>
<DialogContent>
<div className="container">
@ -111,13 +112,7 @@ export class ThankYou extends React.Component<IThankYouProps, {}> {
<div className="contributions">
{this.renderList(this.props.userContributions)}
</div>
<div
className="confetti-container"
onClick={this.props.onDismissed}
>
{this.renderConfetti()}
</div>
<div className="footer"></div>
{this.renderConfetti()}
</div>
</DialogContent>
</Dialog>

View file

@ -11,10 +11,12 @@
<path d="M111.535,13.767 C111.535,13.3436424 111.191358,13 110.767,13 C110.343549,13 110,13.343736 110,13.767 C110,14.1911704 110.343455,14.535 110.767,14.535 C111.191451,14.535 111.535,14.1912641 111.535,13.767 Z M112.535,13.767 C112.535,14.7434269 111.743858,15.535 110.767,15.535 C109.790926,15.535 109,14.7432113 109,13.767 C109,12.7915732 109.791142,12 110.767,12 C111.743642,12 112.535,12.7913576 112.535,13.767 Z" fill="#C9DEF2"></path>
<path d="M88.5,67.5 L90,67.5 L90,68.5 L88.5,68.5 L88.5,70 L87.5,70 L87.5,68.5 L86,68.5 L86,67.5 L87.5,67.5 L87.5,66 L88.5,66 L88.5,67.5 Z" fill="#C9DEF2"></path>
<path d="M142.016,72.008 C142.016,71.4517457 141.564461,71 141.008,71 C140.452142,71 140,71.4521424 140,72.008 C140,72.5644611 140.451746,73.016 141.008,73.016 C141.564858,73.016 142.016,72.5648576 142.016,72.008 Z M143.016,72.008 C143.016,73.1171424 142.117142,74.016 141.008,74.016 C139.899563,74.016 139,73.1168484 139,72.008 C139,70.8998576 139.899858,70 141.008,70 C142.116848,70 143.016,70.8995635 143.016,72.008 Z" fill="#C9DEF2"></path>
<path d="M139.005775,42.9942247 L138,41.1551784 L136.994225,42.9942247 L135.155178,44 L136.994225,45.0057753 L138,46.8448216 L139.005775,45.0057753 L140.844822,44 L139.005775,42.9942247 Z M143,44 L139.76773,45.76773 L138,49 L136.23227,45.76773 L133,44 L136.23227,42.23227 L138,39 L139.76773,42.23227 L143,44 Z M139.840401,42.3651471 L139.634853,42.1595994 L139.76773,42.23227 L139.840401,42.3651471 Z" fill="#C9DEF2"></path>
<g transform="translate(0 -30)">
<path d="M139.005775,42.9942247 L138,41.1551784 L136.994225,42.9942247 L135.155178,44 L136.994225,45.0057753 L138,46.8448216 L139.005775,45.0057753 L140.844822,44 L139.005775,42.9942247 Z M143,44 L139.76773,45.76773 L138,49 L136.23227,45.76773 L133,44 L136.23227,42.23227 L138,39 L139.76773,42.23227 L143,44 Z M139.840401,42.3651471 L139.634853,42.1595994 L139.76773,42.23227 L139.840401,42.3651471 Z" fill="#C9DEF2"></path>
</g>
<path d="M121.720444,54.279556 L120,51.133748 L118.279556,54.279556 L115.133748,56 L118.279556,57.7204439 L120,60.866252 L121.720444,57.7204439 L124.866252,56 L121.720444,54.279556 Z M127,56 L122.474822,58.474822 L120,63 L117.525178,58.474822 L113,56 L117.525178,53.5251779 L120,49 L122.474822,53.5251779 L127,56 Z" fill="#C9DEF2"></path>
<path d="M54.9691035,34.7254742 L54.8077827,34.7497316 C54.2456747,34.7497316 53.8735538,34.2535704 54.1248747,33.7582603 L56.1367154,28.3271151 L50.7837495,30.3069791 C50.2969392,30.6317304 49.7118643,30.127811 49.7118643,29.6538132 L49.7361217,29.4924924 L49.8405926,29.152962 C47.8413546,29.9129289 45.548494,31.1836039 43.9956645,32.7364334 C41.5883951,35.1437028 41.4347631,38.326082 43.7430329,40.6343592 C46.0517046,42.9430308 49.3162163,42.7865132 51.6409513,40.3817283 C53.1615432,38.8611307 54.4115747,36.6309139 55.1764325,34.6616807 L54.9691035,34.7254742 Z M50.4436278,28.9291509 C50.4705976,28.928755 50.495846,28.9230435 50.5180916,28.9110555 C50.5057008,28.9151858 50.4932927,28.9193385 50.4808677,28.9235135 L50.4436278,28.9291509 Z M56.4224079,27.5558626 C56.4119997,27.5766789 56.4038929,27.5987544 56.3980374,27.6216529 L56.4224079,27.5558626 Z M56.4984208,33.6400731 C56.5974897,33.8382109 56.5969824,34.0808135 56.4821979,34.2804753 C55.7137168,36.5523565 54.2728382,39.301367 52.4232365,41.1508654 C49.6917865,43.9765033 45.7238851,44.1667451 42.9672654,41.4101254 C40.2129321,38.6557832 40.4000121,34.7805521 43.2198976,31.9606666 C45.0962125,30.0843517 47.8851661,28.6322524 50.0993058,27.9000172 C50.6496453,27.6248475 51.1458064,27.9969683 51.1458064,28.5590763 L51.121549,28.7203971 L51.0201976,29.0497894 L56.4701246,27.034063 L56.6604143,27 C57.200592,27 57.7194078,27.4150527 57.427533,27.9914713 L55.4083398,33.4424651 L55.6604354,33.3648972 C55.9713065,33.1901292 56.3452757,33.3337827 56.4984208,33.6400731 Z M47.3564312,41.1883573 C45.0071345,41.1883573 43.1026533,39.2838761 43.1026533,36.9345795 C43.1026533,34.5852828 45.0071345,32.6808016 47.3564312,32.6808016 C49.7057278,32.6808016 51.6102091,34.5852828 51.6102091,36.9345795 C51.6102091,39.2838761 49.7057278,41.1883573 47.3564312,41.1883573 Z M47.3564312,40.0912573 C49.0998162,40.0912573 50.513109,38.6779645 50.513109,36.9345795 C50.513109,35.1911944 49.0998162,33.7779016 47.3564312,33.7779016 C45.6130461,33.7779016 44.1997533,35.1911944 44.1997533,36.9345795 C44.1997533,38.6779645 45.6130461,40.0912573 47.3564312,40.0912573 Z" fill="#CFE5FF"></path>
<path d="M6.40799454,19.7606609 C6.86785286,19.4156863 7.49864298,18.8494598 8.13008712,18.2178675 C8.76153125,17.5862752 9.32762496,16.9553371 9.67251869,16.4953709 C9.83679914,16.276279 9.83679914,15.6852229 9.67251869,15.466131 C9.32762496,15.0061648 8.76153125,14.3752266 8.13008712,13.7436344 C7.49864298,13.1120421 6.86785286,12.5458156 6.40799454,12.200841 C6.18895395,12.036522 5.59803654,12.036522 5.37899595,12.200841 C4.91913763,12.5458156 4.2883475,13.1120421 3.65690337,13.7436344 C3.02545923,14.3752266 2.45936553,15.0061648 2.11447179,15.466131 C1.95019135,15.6852229 1.95019135,16.276279 2.11447179,16.4953709 C2.45936553,16.9553371 3.02545923,17.5862752 3.65690337,18.2178675 C4.2883475,18.8494598 4.91913763,19.4156863 5.37899595,19.7606609 C5.59803654,19.9249799 6.18895395,19.9249799 6.40799454,19.7606609 Z M8.51392882,19.3775916 C7.98411623,19.8862015 7.47355503,20.3326781 7.06610016,20.638341 C6.76821656,20.8618061 6.52370095,21.0132084 6.31740747,21.0892291 C6.17536459,21.1415729 6.02860201,21.1600653 5.89349524,21.1433211 C5.75838848,21.1600653 5.61162589,21.1415729 5.46958301,21.0892291 C5.26328954,21.0132084 5.01877392,20.8618061 4.72089032,20.638341 C4.21358423,20.2577721 3.54644515,19.6589171 2.88131845,18.9936344 C2.21619176,18.3283516 1.6174772,17.6610561 1.23699763,17.153631 C1.01358493,16.8556775 0.862218119,16.6111045 0.786215259,16.4047626 C0.733883672,16.2626864 0.715395676,16.1158894 0.732135954,15.9807509 C0.715395676,15.8456125 0.733883672,15.6988155 0.786215259,15.5567393 C0.862218119,15.3503974 1.01358493,15.1058244 1.23699763,14.8078709 C1.54332479,14.3993389 1.99111164,13.887179 2.50112636,13.3558733 L0,10.7615419 L0.78955043,10 L3.27699268,12.5801374 C3.8053993,12.0730926 4.31444326,11.6280677 4.72089032,11.3231609 C5.01877392,11.0996958 5.26328954,10.9482935 5.46958301,10.8722728 C5.61162589,10.819929 5.75838848,10.8014366 5.89349524,10.8181808 C6.02860201,10.8014366 6.17536459,10.819929 6.31740747,10.8722728 C6.52370095,10.9482935 6.76821656,11.0996958 7.06610016,11.3231609 C7.57340626,11.7037298 8.24054534,12.3025848 8.90567203,12.9678675 C9.57079873,13.6331502 10.1695133,14.3004458 10.5499929,14.8078709 C10.7734056,15.1058244 10.9247724,15.3503974 11.0007752,15.5567393 C11.0531068,15.6988155 11.0715948,15.8456125 11.0548545,15.9807509 C11.0715948,16.1158894 11.0531068,16.2626864 11.0007752,16.4047626 C10.9247724,16.6111045 10.7734056,16.8556775 10.5499929,17.153631 C10.2443967,17.5611881 9.79801518,18.0718791 9.28951426,18.6018253 L11.8800001,21.1928634 L11.1044235,21.9686385 L8.51392882,19.3775916 Z" fill="#CFE5FF"></path>
</g>
</g>
</svg>
</svg>

Before

Width:  |  Height:  |  Size: 8.5 KiB

After

Width:  |  Height:  |  Size: 8.5 KiB

View file

@ -14,41 +14,18 @@
.dialog-header {
height: 100px;
position: relative;
.release-notes-header {
display: flex;
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
padding: 0 var(--spacing-double);
}
background: url('../static/common/release-note-header-left.svg') no-repeat left var(--spacing-double) top var(--spacing-half) / auto 90px,
url('../static/common/release-note-header-right.svg') no-repeat right var(--spacing-double) top var(--spacing-half) / auto 90px;
.release-note-graphic-left {
margin-right: 20px;
}
.release-note-graphic-right {
margin-left: 20px;
}
.title {
h1 {
display: flex;
flex-direction: column;
flex-grow: 1;
justify-content: center;
text-align: center;
p {
margin: 0;
}
.version {
font-size: 14px;
font-weight: var(--font-weight-semibold);
margin-bottom: 0;
}
.date {

View file

@ -13,54 +13,10 @@
.dialog-header {
height: 88px;
position: relative;
text-align: center;
.release-notes-header {
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
padding: 0 var(--spacing-double);
}
.header-graphics {
display: flex;
.img-space {
flex-grow: 2;
display: flex;
}
}
.release-note-graphic-left {
margin-right: 20px;
}
.release-note-graphic-right {
margin-left: 20px;
}
.title {
text-align: center;
position: absolute;
width: 100%;
top: 0;
left: 0;
padding-top: 6%;
.thank-you-note {
font-size: var(--font-size-md);
font-weight: normal;
}
.thank-you {
font-size: var(--font-size-md);
font-weight: var(--font-weight-semibold);
div {
display: inline;
}
}
}
background: url('../static/common/release-note-header-left.svg') no-repeat left var(--spacing-double) top var(--spacing-half) / auto 78px,
url('../static/common/release-note-header-right.svg') no-repeat right var(--spacing-double) top var(--spacing-half) / auto 78px;
}
ul {
@ -80,22 +36,10 @@
.container {
width: 600px;
padding-left: 72px;
padding-right: 72px;
padding-top: var(--spacing-triple);
padding-bottom: var(--spacing-triple);
padding: var(--spacing-triple) 72px;
overflow-x: hidden;
overflow-y: auto;
.footer {
position: fixed;
height: var(--spacing-triple);
width: 95%;
bottom: 0;
left: 0;
background-color: var(--background-color);
}
.section {
padding-bottom: var(--spacing-triple);
}
@ -116,55 +60,4 @@
padding-bottom: var(--spacing-triple);
}
}
.confetti-container {
position: absolute;
width: 110vw;
height: 110vh;
top: -50vh;
left: -33vw;
animation: remove-confetti-container 0s ease-in 4s forwards;
animation-iteration-count: 1;
animation-fill-mode: forwards;
}
@keyframes remove-confetti-container {
to {
width: 0;
height: 0;
overflow: hidden;
}
}
.confetti {
position: absolute;
}
$colors: (#e7001b, #ffe600, #0ebd25, #0f2679, #e21bd2);
@for $i from 0 through 750 {
$w: random(8);
$l: random(100);
.confetti:nth-child(#{$i}) {
width: #{$w}px;
height: #{$w * 0.4}px;
background-color: nth($colors, random(5));
top: -10%;
left: unquote($l + '%');
opacity: random() + 0.5;
transform: rotate(#{random() * 360}deg);
animation-name: falling-#{$i};
animation-duration: unquote(5 + random() + 's');
animation-delay: unquote('-' + random() + 's');
animation-iteration-count: 1;
}
@keyframes falling-#{$i} {
100% {
top: 110%;
left: unquote($l + random(15) + '%');
}
}
}
}

View file

@ -1108,6 +1108,13 @@ re2js@^0.3.0:
resolved "https://registry.yarnpkg.com/re2js/-/re2js-0.3.0.tgz#4d69d9bee8cb9eaf5ac35f9db36b23640e533ace"
integrity sha512-FKfaeBtpUIbtqSBy5KnlRG3jVRCCPul5EUPzhaTfJ8peGZOVHl90c3jslCv6sW6/vmwMJ3eBXe8zLpoAdDDN8w==
react-confetti@^6.1.0:
version "6.1.0"
resolved "https://registry.yarnpkg.com/react-confetti/-/react-confetti-6.1.0.tgz#03dc4340d955acd10b174dbf301f374a06e29ce6"
integrity sha512-7Ypx4vz0+g8ECVxr88W9zhcQpbeujJAVqL14ZnXJ3I23mOI9/oBVTQ3dkJhUmB0D6XOtCZEM6N0Gm9PMngkORw==
dependencies:
tween-functions "^1.2.0"
react-css-transition-replace@^3.0.3:
version "3.0.3"
resolved "https://registry.yarnpkg.com/react-css-transition-replace/-/react-css-transition-replace-3.0.3.tgz#23d3ed17f54e41435c0485300adb75d2e6e24aad"
@ -1476,6 +1483,11 @@ tunnel-agent@^0.6.0:
dependencies:
safe-buffer "^5.0.1"
tween-functions@^1.2.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/tween-functions/-/tween-functions-1.2.0.tgz#1ae3a50e7c60bb3def774eac707acbca73bbc3ff"
integrity sha512-PZBtLYcCLtEcjL14Fzb1gSxPBeL7nWvGhO5ZFPGqziCcr8uvHp0NDmdjBchp6KHL+tExcg0m3NISmKxhU394dA==
untildify@^3.0.2:
version "3.0.2"
resolved "https://registry.yarnpkg.com/untildify/-/untildify-3.0.2.tgz#7f1f302055b3fea0f3e81dc78eb36766cb65e3f1"