mirror of
https://github.com/discourse/discourse.git
synced 2025-03-05 18:59:22 +00:00
UX: Simplify and redesign summary skeleton (#22965)
This commit is contained in:
parent
001320c9f1
commit
bd19f0c9f1
@ -1,6 +1,10 @@
|
||||
import I18n from "I18n";
|
||||
import { registerUnbound } from "discourse-common/lib/helpers";
|
||||
|
||||
export default function i18n(key, params) {
|
||||
return I18n.t(key, params);
|
||||
}
|
||||
|
||||
registerUnbound("i18n", (key, params) => I18n.t(key, params));
|
||||
registerUnbound("i18n-yes-no", (value, params) =>
|
||||
I18n.t(value ? "yes_value" : "no_value", params)
|
||||
|
@ -0,0 +1,35 @@
|
||||
import i18n from "discourse-common/helpers/i18n";
|
||||
|
||||
<template>
|
||||
<ul class="ai-summary__list">
|
||||
<li class="ai-summary__list-item"></li>
|
||||
<li class="ai-summary__list-item"></li>
|
||||
<li class="ai-summary__list-item"></li>
|
||||
<li class="ai-summary__list-item"></li>
|
||||
<li class="ai-summary__shimmer"></li>
|
||||
</ul>
|
||||
|
||||
<div class="ai-summary__status">
|
||||
<div class="ai-summary__generating-text">
|
||||
{{i18n "summary.in_progress"}}
|
||||
</div>
|
||||
<div class="ai-summary__sparkles">
|
||||
<svg
|
||||
fill="currentColor"
|
||||
viewBox="0 0 512 512"
|
||||
id="icons"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
d="M208,512a24.84,24.84,0,0,1-23.34-16l-39.84-103.6a16.06,16.06,0,0,0-9.19-9.19L32,343.34a25,25,0,0,1,0-46.68l103.6-39.84a16.06,16.06,0,0,0,9.19-9.19L184.66,144a25,25,0,0,1,46.68,0l39.84,103.6a16.06,16.06,0,0,0,9.19,9.19l103,39.63A25.49,25.49,0,0,1,400,320.52a24.82,24.82,0,0,1-16,22.82l-103.6,39.84a16.06,16.06,0,0,0-9.19,9.19L231.34,496A24.84,24.84,0,0,1,208,512Zm66.85-254.84h0Z"
|
||||
/>
|
||||
<path
|
||||
d="M88,176a14.67,14.67,0,0,1-13.69-9.4L57.45,122.76a7.28,7.28,0,0,0-4.21-4.21L9.4,101.69a14.67,14.67,0,0,1,0-27.38L53.24,57.45a7.31,7.31,0,0,0,4.21-4.21L74.16,9.79A15,15,0,0,1,86.23.11,14.67,14.67,0,0,1,101.69,9.4l16.86,43.84a7.31,7.31,0,0,0,4.21,4.21L166.6,74.31a14.67,14.67,0,0,1,0,27.38l-43.84,16.86a7.28,7.28,0,0,0-4.21,4.21L101.69,166.6A14.67,14.67,0,0,1,88,176Z"
|
||||
/>
|
||||
<path
|
||||
d="M400,256a16,16,0,0,1-14.93-10.26l-22.84-59.37a8,8,0,0,0-4.6-4.6l-59.37-22.84a16,16,0,0,1,0-29.86l59.37-22.84a8,8,0,0,0,4.6-4.6L384.9,42.68a16.45,16.45,0,0,1,13.17-10.57,16,16,0,0,1,16.86,10.15l22.84,59.37a8,8,0,0,0,4.6,4.6l59.37,22.84a16,16,0,0,1,0,29.86l-59.37,22.84a8,8,0,0,0-4.6,4.6l-22.84,59.37A16,16,0,0,1,400,256Z"
|
||||
/>
|
||||
</svg>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
@ -1,26 +0,0 @@
|
||||
<ul class="ai-summary__list" {{did-insert this.setupAnimation}}>
|
||||
{{#each this.blocks as |block|}}
|
||||
<li
|
||||
class={{concat-class
|
||||
"ai-summary__list-item"
|
||||
(if block.show "show")
|
||||
(if block.shown "is-shown")
|
||||
(if block.blinking "blink")
|
||||
}}
|
||||
{{did-update (fn this.onBlinking block) block.blinking}}
|
||||
{{did-update (fn this.onShowing block) block.show}}
|
||||
{{will-destroy this.teardownAnimation}}
|
||||
></li>
|
||||
{{/each}}
|
||||
</ul>
|
||||
|
||||
<span>
|
||||
<div class="ai-summary__generating-text">
|
||||
{{i18n "summary.in_progress"}}
|
||||
</div>
|
||||
<span class="ai-summary__indicator-wave">
|
||||
<span class="ai-summary__indicator-dot">.</span>
|
||||
<span class="ai-summary__indicator-dot">.</span>
|
||||
<span class="ai-summary__indicator-dot">.</span>
|
||||
</span>
|
||||
</span>
|
@ -1,92 +0,0 @@
|
||||
import Component from "@glimmer/component";
|
||||
import { action } from "@ember/object";
|
||||
import { tracked } from "@glimmer/tracking";
|
||||
import discourseLater from "discourse-common/lib/later";
|
||||
import { cancel } from "@ember/runloop";
|
||||
|
||||
class Block {
|
||||
@tracked show = false;
|
||||
@tracked shown = false;
|
||||
@tracked blinking = false;
|
||||
|
||||
constructor(args = {}) {
|
||||
this.show = args.show ?? false;
|
||||
this.shown = args.shown ?? false;
|
||||
}
|
||||
}
|
||||
|
||||
const BLOCKS_SIZE = 20; // changing this requires to change css accordingly
|
||||
|
||||
export default class AiSummarySkeleton extends Component {
|
||||
blocks = [...Array.from({ length: BLOCKS_SIZE }, () => new Block())];
|
||||
|
||||
#nextBlockBlinkingTimer;
|
||||
#blockBlinkingTimer;
|
||||
#blockShownTimer;
|
||||
|
||||
@action
|
||||
setupAnimation() {
|
||||
this.blocks.firstObject.show = true;
|
||||
this.blocks.firstObject.shown = true;
|
||||
}
|
||||
|
||||
@action
|
||||
onBlinking(block) {
|
||||
if (!block.blinking) {
|
||||
return;
|
||||
}
|
||||
|
||||
block.show = false;
|
||||
|
||||
this.#nextBlockBlinkingTimer = discourseLater(
|
||||
this,
|
||||
() => {
|
||||
this.#nextBlock(block).blinking = true;
|
||||
},
|
||||
250
|
||||
);
|
||||
|
||||
this.#blockBlinkingTimer = discourseLater(
|
||||
this,
|
||||
() => {
|
||||
block.blinking = false;
|
||||
},
|
||||
500
|
||||
);
|
||||
}
|
||||
|
||||
@action
|
||||
onShowing(block) {
|
||||
if (!block.show) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.#blockShownTimer = discourseLater(
|
||||
this,
|
||||
() => {
|
||||
this.#nextBlock(block).show = true;
|
||||
this.#nextBlock(block).shown = true;
|
||||
|
||||
if (this.blocks.lastObject === block) {
|
||||
this.blocks.firstObject.blinking = true;
|
||||
}
|
||||
},
|
||||
250
|
||||
);
|
||||
}
|
||||
|
||||
@action
|
||||
teardownAnimation() {
|
||||
cancel(this.#blockShownTimer);
|
||||
cancel(this.#nextBlockBlinkingTimer);
|
||||
cancel(this.#blockBlinkingTimer);
|
||||
}
|
||||
|
||||
#nextBlock(currentBlock) {
|
||||
if (currentBlock === this.blocks.lastObject) {
|
||||
return this.blocks.firstObject;
|
||||
} else {
|
||||
return this.blocks.objectAt(this.blocks.indexOf(currentBlock) + 1);
|
||||
}
|
||||
}
|
||||
}
|
@ -54,7 +54,7 @@ export default createWidget("summary-box", {
|
||||
return new RenderGlimmer(
|
||||
this,
|
||||
"div.ai-summary__container",
|
||||
hbs`{{ai-summary-skeleton}}`
|
||||
hbs`<AiSummarySkeleton />`
|
||||
);
|
||||
},
|
||||
|
||||
|
@ -10,120 +10,87 @@
|
||||
flex-wrap: wrap;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
&__list-item {
|
||||
background: var(--primary-300);
|
||||
border-radius: var(--d-border-radius);
|
||||
margin-right: 8px;
|
||||
margin-bottom: 8px;
|
||||
height: 18px;
|
||||
opacity: 0;
|
||||
display: block;
|
||||
animation: motion-up 1.5s infinite linear;
|
||||
|
||||
&:nth-child(1) {
|
||||
width: 10%;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
&:nth-child(2) {
|
||||
width: 12%;
|
||||
width: 85%;
|
||||
}
|
||||
|
||||
&:nth-child(3) {
|
||||
width: 18%;
|
||||
width: 90%;
|
||||
}
|
||||
|
||||
&:nth-child(4) {
|
||||
width: 14%;
|
||||
}
|
||||
|
||||
&:nth-child(5) {
|
||||
width: 18%;
|
||||
}
|
||||
|
||||
&:nth-child(6) {
|
||||
width: 14%;
|
||||
}
|
||||
|
||||
&:nth-child(7) {
|
||||
width: 22%;
|
||||
}
|
||||
|
||||
&:nth-child(8) {
|
||||
width: 05%;
|
||||
}
|
||||
|
||||
&:nth-child(9) {
|
||||
width: 25%;
|
||||
}
|
||||
|
||||
&:nth-child(10) {
|
||||
width: 14%;
|
||||
}
|
||||
|
||||
&:nth-child(11) {
|
||||
width: 18%;
|
||||
}
|
||||
|
||||
&:nth-child(12) {
|
||||
width: 12%;
|
||||
}
|
||||
|
||||
&:nth-child(13) {
|
||||
width: 22%;
|
||||
}
|
||||
|
||||
&:nth-child(14) {
|
||||
width: 18%;
|
||||
}
|
||||
|
||||
&:nth-child(15) {
|
||||
width: 13%;
|
||||
}
|
||||
|
||||
&:nth-child(16) {
|
||||
width: 22%;
|
||||
}
|
||||
|
||||
&:nth-child(17) {
|
||||
width: 19%;
|
||||
}
|
||||
|
||||
&:nth-child(18) {
|
||||
width: 13%;
|
||||
}
|
||||
|
||||
&:nth-child(19) {
|
||||
width: 22%;
|
||||
}
|
||||
|
||||
&:nth-child(20) {
|
||||
width: 25%;
|
||||
}
|
||||
&.is-shown {
|
||||
opacity: 1;
|
||||
}
|
||||
&.show {
|
||||
animation: appear 0.5s cubic-bezier(0.445, 0.05, 0.55, 0.95) 0s forwards;
|
||||
}
|
||||
&.blink {
|
||||
animation: blink 0.5s cubic-bezier(0.55, 0.085, 0.68, 0.53) both;
|
||||
width: 95%;
|
||||
}
|
||||
}
|
||||
&__generating-text {
|
||||
display: inline-block;
|
||||
margin-left: 3px;
|
||||
|
||||
&__shimmer {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 50%;
|
||||
height: 100%;
|
||||
background: linear-gradient(
|
||||
100deg,
|
||||
rgba(255, 255, 255, 0) 20%,
|
||||
rgba(255, 255, 255, 0.5) 50%,
|
||||
rgba(255, 255, 255, 0) 80%
|
||||
);
|
||||
|
||||
animation: ai-shimmer 1.5s infinite linear;
|
||||
}
|
||||
&__indicator-wave {
|
||||
flex: 0 0 auto;
|
||||
display: inline-flex;
|
||||
|
||||
&__status {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.5rem;
|
||||
}
|
||||
&__indicator-dot {
|
||||
display: inline-block;
|
||||
animation: ai-summary__indicator-wave 1.8s linear infinite;
|
||||
&:nth-child(2) {
|
||||
animation-delay: -1.6s;
|
||||
}
|
||||
&:nth-child(3) {
|
||||
animation-delay: -1.4s;
|
||||
|
||||
&__sparkles {
|
||||
position: relative;
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
|
||||
svg {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
position: absolute;
|
||||
|
||||
path {
|
||||
position: absolute;
|
||||
transform-origin: center;
|
||||
scale: 0.9;
|
||||
opacity: 0.5;
|
||||
fill: var(--tertiary);
|
||||
&:nth-child(1) {
|
||||
animation: sparkle 2.25s infinite
|
||||
cubic-bezier(0.175, 0.885, 0.32, 1.275);
|
||||
}
|
||||
&:nth-child(2) {
|
||||
animation: sparkle 3.25s infinite
|
||||
cubic-bezier(0.175, 0.885, 0.32, 1.275);
|
||||
}
|
||||
&:nth-child(3) {
|
||||
animation: sparkle 4.25s infinite
|
||||
cubic-bezier(0.175, 0.885, 0.32, 1.275);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -152,34 +119,24 @@
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes ai-summary__indicator-wave {
|
||||
0%,
|
||||
60%,
|
||||
100% {
|
||||
transform: initial;
|
||||
@keyframes ai-shimmer {
|
||||
0% {
|
||||
transform: translateX(-200%);
|
||||
}
|
||||
30% {
|
||||
transform: translateY(-0.2em);
|
||||
100% {
|
||||
transform: translateX(200%);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes appear {
|
||||
0% {
|
||||
opacity: 0;
|
||||
}
|
||||
100% {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes blink {
|
||||
0% {
|
||||
opacity: 1;
|
||||
}
|
||||
50% {
|
||||
@keyframes sparkle {
|
||||
75% {
|
||||
transform: scale(0.9);
|
||||
opacity: 0.5;
|
||||
fill: var(--tertiary-medium);
|
||||
}
|
||||
100% {
|
||||
transform: scale(1);
|
||||
opacity: 1;
|
||||
fill: var(--tertiary);
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user