UX: update gist toggle styles (#926)
This commit is contained in:
parent
530a795d43
commit
a9afa04329
|
@ -4,35 +4,43 @@ import { action } from "@ember/object";
|
||||||
import { service } from "@ember/service";
|
import { service } from "@ember/service";
|
||||||
import DButton from "discourse/components/d-button";
|
import DButton from "discourse/components/d-button";
|
||||||
import DropdownMenu from "discourse/components/dropdown-menu";
|
import DropdownMenu from "discourse/components/dropdown-menu";
|
||||||
|
import bodyClass from "discourse/helpers/body-class";
|
||||||
import icon from "discourse-common/helpers/d-icon";
|
import icon from "discourse-common/helpers/d-icon";
|
||||||
import i18n from "discourse-common/helpers/i18n";
|
import i18n from "discourse-common/helpers/i18n";
|
||||||
import DMenu from "float-kit/components/d-menu";
|
import DMenu from "float-kit/components/d-menu";
|
||||||
|
import eq from "truth-helpers/helpers/eq";
|
||||||
|
|
||||||
export default class AiGistToggle extends Component {
|
export default class AiGistToggle extends Component {
|
||||||
@service router;
|
@service gists;
|
||||||
@service gistPreference;
|
|
||||||
|
|
||||||
get shouldShow() {
|
|
||||||
return this.router.currentRoute.attributes?.list?.topics?.some(
|
|
||||||
(topic) => topic.ai_topic_gist
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
get buttons() {
|
get buttons() {
|
||||||
return [
|
return [
|
||||||
{
|
{
|
||||||
id: "gists_enabled",
|
id: "table",
|
||||||
label: "discourse_ai.summarization.gists_enabled_long",
|
label: "discourse_ai.summarization.topic_list_layout.button.compact",
|
||||||
icon: "discourse-sparkles",
|
icon: "discourse-table",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: "gists_disabled",
|
id: "table-ai",
|
||||||
label: "discourse_ai.summarization.gists_disabled",
|
label: "discourse_ai.summarization.topic_list_layout.button.expanded",
|
||||||
icon: "far-eye-slash",
|
icon: "discourse-table-sparkles",
|
||||||
|
description:
|
||||||
|
"discourse_ai.summarization.topic_list_layout.button.expanded_description",
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
get selectedOptionId() {
|
||||||
|
return this.gists.get("preference");
|
||||||
|
}
|
||||||
|
|
||||||
|
get currentButton() {
|
||||||
|
const buttonPreference = this.buttons.find(
|
||||||
|
(button) => button.id === this.selectedOptionId
|
||||||
|
);
|
||||||
|
return buttonPreference || this.buttons[0];
|
||||||
|
}
|
||||||
|
|
||||||
@action
|
@action
|
||||||
onRegisterApi(api) {
|
onRegisterApi(api) {
|
||||||
this.dMenu = api;
|
this.dMenu = api;
|
||||||
|
@ -40,29 +48,22 @@ export default class AiGistToggle extends Component {
|
||||||
|
|
||||||
@action
|
@action
|
||||||
onSelect(optionId) {
|
onSelect(optionId) {
|
||||||
this.gistPreference.setPreference(optionId);
|
this.gists.setPreference(optionId);
|
||||||
this.dMenu.close();
|
this.dMenu.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
{{#if this.shouldShow}}
|
{{#if this.gists.shouldShow}}
|
||||||
|
{{bodyClass (concat "topic-list-layout-" this.gists.preference)}}
|
||||||
<DMenu
|
<DMenu
|
||||||
@modalForMobile={{true}}
|
@modalForMobile={{true}}
|
||||||
@autofocus={{true}}
|
@autofocus={{true}}
|
||||||
@identifier="ai-gists-dropdown"
|
@identifier="topic-list-layout"
|
||||||
@onRegisterApi={{this.onRegisterApi}}
|
@onRegisterApi={{this.onRegisterApi}}
|
||||||
@triggerClass="btn-transparent"
|
@triggerClass="btn-default btn-icon"
|
||||||
>
|
>
|
||||||
<:trigger>
|
<:trigger>
|
||||||
<span class="d-button-label">
|
{{icon this.currentButton.icon}}
|
||||||
{{i18n
|
|
||||||
(concat
|
|
||||||
"discourse_ai.summarization." this.gistPreference.preference
|
|
||||||
)
|
|
||||||
}}
|
|
||||||
</span>
|
|
||||||
{{icon "angle-down"}}
|
|
||||||
</:trigger>
|
</:trigger>
|
||||||
<:content>
|
<:content>
|
||||||
<DropdownMenu as |dropdown|>
|
<DropdownMenu as |dropdown|>
|
||||||
|
@ -71,9 +72,17 @@ export default class AiGistToggle extends Component {
|
||||||
<DButton
|
<DButton
|
||||||
@label={{button.label}}
|
@label={{button.label}}
|
||||||
@icon={{button.icon}}
|
@icon={{button.icon}}
|
||||||
class="btn-transparent"
|
class="btn-transparent
|
||||||
|
{{if button.description '--with-description'}}
|
||||||
|
{{if (eq this.currentButton.id button.id) '--active'}}"
|
||||||
@action={{fn this.onSelect button.id}}
|
@action={{fn this.onSelect button.id}}
|
||||||
/>
|
>
|
||||||
|
{{#if button.description}}
|
||||||
|
<div class="btn__description">
|
||||||
|
{{i18n button.description}}
|
||||||
|
</div>
|
||||||
|
{{/if}}
|
||||||
|
</DButton>
|
||||||
</dropdown.item>
|
</dropdown.item>
|
||||||
{{/each}}
|
{{/each}}
|
||||||
</DropdownMenu>
|
</DropdownMenu>
|
||||||
|
|
|
@ -1,31 +1,30 @@
|
||||||
import Component from "@glimmer/component";
|
import Component from "@glimmer/component";
|
||||||
import { service } from "@ember/service";
|
import { service } from "@ember/service";
|
||||||
import bodyClass from "discourse/helpers/body-class";
|
import { htmlSafe } from "@ember/template";
|
||||||
|
import { emojiUnescape, sanitize } from "discourse/lib/text";
|
||||||
|
|
||||||
export default class AiTopicGist extends Component {
|
export default class AiTopicGist extends Component {
|
||||||
@service router;
|
@service gists;
|
||||||
@service gistPreference;
|
|
||||||
|
|
||||||
get prefersGist() {
|
get shouldShow() {
|
||||||
return this.gistPreference.preference === "gists_enabled";
|
return this.gists.preference === "table-ai" && this.gists.shouldShow;
|
||||||
}
|
}
|
||||||
|
|
||||||
get showGist() {
|
get gistOrExcerpt() {
|
||||||
return (
|
const topic = this.args.topic;
|
||||||
this.args.topic?.ai_topic_gist &&
|
const gist = topic.get("ai_topic_gist");
|
||||||
this.prefersGist &&
|
const excerpt = emojiUnescape(sanitize(topic.get("excerpt")));
|
||||||
!this.args.topic?.excerpt
|
|
||||||
);
|
return gist || excerpt;
|
||||||
}
|
}
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
{{#if this.showGist}}
|
{{#if this.shouldShow}}
|
||||||
{{bodyClass "--topic-list-with-gist"}}
|
{{#if this.gistOrExcerpt}}
|
||||||
<div class="ai-topic-gist">
|
<div class="excerpt">
|
||||||
<div class="ai-topic-gist__text">
|
<div>{{htmlSafe this.gistOrExcerpt}}</div>
|
||||||
{{@topic.ai_topic_gist}}
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
{{/if}}
|
||||||
{{/if}}
|
{{/if}}
|
||||||
</template>
|
</template>
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,15 @@
|
||||||
|
import Component from "@glimmer/component";
|
||||||
|
import { service } from "@ember/service";
|
||||||
|
import AiGistToggle from "../../components/ai-gist-toggle";
|
||||||
|
|
||||||
|
export default class AiTopicGist extends Component {
|
||||||
|
@service topicThumbnails; // avoid Topic Thumbnails theme component
|
||||||
|
|
||||||
|
get shouldShow() {
|
||||||
|
return !this.topicThumbnails?.enabledForRoute;
|
||||||
|
}
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<AiGistToggle />
|
||||||
|
</template>
|
||||||
|
}
|
|
@ -1,13 +0,0 @@
|
||||||
import Component from "@glimmer/component";
|
|
||||||
import AiGistToggle from "../../components/ai-gist-toggle";
|
|
||||||
|
|
||||||
export default class AiTopicGistToggle extends Component {
|
|
||||||
static shouldRender(outletArgs, helper) {
|
|
||||||
const isMobileView = helper.site.mobileView;
|
|
||||||
return isMobileView;
|
|
||||||
}
|
|
||||||
|
|
||||||
<template>
|
|
||||||
<AiGistToggle />
|
|
||||||
</template>
|
|
||||||
}
|
|
|
@ -1,16 +0,0 @@
|
||||||
import Component from "@glimmer/component";
|
|
||||||
import AiGistToggle from "../../components/ai-gist-toggle";
|
|
||||||
|
|
||||||
export default class AiTopicGist extends Component {
|
|
||||||
static shouldRender(outletArgs) {
|
|
||||||
return (
|
|
||||||
// "default" can be removed after the glimmer topic list is rolled out
|
|
||||||
(outletArgs?.name === "default" || outletArgs?.name === "topic.title") &&
|
|
||||||
!outletArgs.bulkSelectEnabled
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
<template>
|
|
||||||
<AiGistToggle />
|
|
||||||
</template>
|
|
||||||
}
|
|
|
@ -1,12 +0,0 @@
|
||||||
import { tracked } from "@glimmer/tracking";
|
|
||||||
import Service from "@ember/service";
|
|
||||||
|
|
||||||
export default class GistPreference extends Service {
|
|
||||||
@tracked
|
|
||||||
preference = localStorage.getItem("aiGistPreference") || "gists_disabled";
|
|
||||||
|
|
||||||
setPreference(value) {
|
|
||||||
this.preference = value;
|
|
||||||
localStorage.setItem("aiGistPreference", value);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,29 @@
|
||||||
|
import { tracked } from "@glimmer/tracking";
|
||||||
|
import Service, { service } from "@ember/service";
|
||||||
|
|
||||||
|
export default class Gists extends Service {
|
||||||
|
@service router;
|
||||||
|
|
||||||
|
@tracked preference = localStorage.getItem("topicListLayout");
|
||||||
|
|
||||||
|
get shouldShow() {
|
||||||
|
const currentRoute = this.router.currentRoute.name;
|
||||||
|
const isDiscovery = currentRoute.includes("discovery");
|
||||||
|
const isNotCategories = !currentRoute.includes("categories");
|
||||||
|
const gistsAvailable =
|
||||||
|
this.router.currentRoute.attributes?.list?.topics?.some(
|
||||||
|
(topic) => topic.ai_topic_gist
|
||||||
|
);
|
||||||
|
|
||||||
|
return isDiscovery && isNotCategories && gistsAvailable;
|
||||||
|
}
|
||||||
|
|
||||||
|
setPreference(value) {
|
||||||
|
this.preference = value;
|
||||||
|
localStorage.setItem("topicListLayout", value);
|
||||||
|
|
||||||
|
if (this.preference === "table-ai") {
|
||||||
|
localStorage.setItem("aiPreferred", true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,65 @@
|
||||||
|
.topic-list-layout-content {
|
||||||
|
.btn.--with-description {
|
||||||
|
display: grid;
|
||||||
|
grid-template-areas: "icon title" "icon description";
|
||||||
|
grid-template-columns: auto 1fr;
|
||||||
|
text-align: left;
|
||||||
|
.btn__description {
|
||||||
|
grid-area: description;
|
||||||
|
width: 100%;
|
||||||
|
font-size: var(--font-down-1);
|
||||||
|
color: var(--primary-high);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn:focus {
|
||||||
|
background: transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn:focus-visible {
|
||||||
|
outline: 2px solid var(--tertiary);
|
||||||
|
background: transparent;
|
||||||
|
outline-offset: -2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn.--active {
|
||||||
|
background: var(--d-selected);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.topic-list-layout-table-ai {
|
||||||
|
.topic-list-item {
|
||||||
|
.link-bottom-line {
|
||||||
|
font-size: var(--font-down-1);
|
||||||
|
margin-top: 0.25em;
|
||||||
|
line-height: var(--line-height-medium);
|
||||||
|
}
|
||||||
|
.excerpt {
|
||||||
|
width: 100%;
|
||||||
|
line-height: var(--line-height-large);
|
||||||
|
margin-top: 0.15em;
|
||||||
|
margin-bottom: 0.15em;
|
||||||
|
max-width: 70ch;
|
||||||
|
}
|
||||||
|
&:not(.visited) {
|
||||||
|
.excerpt {
|
||||||
|
color: var(--primary-high);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.topic-excerpt {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mobile-view & {
|
||||||
|
.topic-list-item .excerpt {
|
||||||
|
margin-top: -0.25em;
|
||||||
|
margin-bottom: 0.25em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.topic-item-stats .num.activity {
|
||||||
|
align-self: end;
|
||||||
|
margin-bottom: -0.15em; // vertical alignment
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -215,77 +215,3 @@
|
||||||
opacity: 1;
|
opacity: 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.ai-topic-gist {
|
|
||||||
width: 100%;
|
|
||||||
.mobile-view & {
|
|
||||||
position: relative;
|
|
||||||
top: -0.33em;
|
|
||||||
line-height: 1.4;
|
|
||||||
width: 90%;
|
|
||||||
}
|
|
||||||
|
|
||||||
&__text {
|
|
||||||
color: var(--primary-high);
|
|
||||||
text-wrap: pretty;
|
|
||||||
word-wrap: break-word;
|
|
||||||
font-size: var(--font-down-1);
|
|
||||||
max-width: 65ch;
|
|
||||||
.visited & {
|
|
||||||
color: var(--primary-medium);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.--topic-list-with-gist {
|
|
||||||
.topic-list-item {
|
|
||||||
.main-link {
|
|
||||||
line-height: var(--line-height-medium);
|
|
||||||
}
|
|
||||||
.link-bottom-line {
|
|
||||||
font-size: var(--font-down-1);
|
|
||||||
margin-top: 0.25em;
|
|
||||||
}
|
|
||||||
.ai-topic-gist {
|
|
||||||
font-size: var(--font-up-1);
|
|
||||||
line-height: var(--line-height-large);
|
|
||||||
margin-top: 0.25em;
|
|
||||||
margin-bottom: 0.15em;
|
|
||||||
}
|
|
||||||
.topic-post-badges {
|
|
||||||
font-size: var(--font-down-1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.mobile-view & {
|
|
||||||
.topic-list {
|
|
||||||
.topic-list-item > .topic-list-data {
|
|
||||||
padding: 1em 0;
|
|
||||||
}
|
|
||||||
.topic-item-stats .num.activity {
|
|
||||||
align-self: end;
|
|
||||||
margin-bottom: -0.15em; // vertical alignment
|
|
||||||
}
|
|
||||||
.pull-left {
|
|
||||||
padding-top: 0.25em;
|
|
||||||
}
|
|
||||||
.right {
|
|
||||||
margin-left: 3.75em;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.ai-gists-dropdown-trigger {
|
|
||||||
font-size: var(--font-down-1);
|
|
||||||
color: var(--primary-medium);
|
|
||||||
padding-left: 0.25em;
|
|
||||||
.mobile-view & {
|
|
||||||
padding-left: 0;
|
|
||||||
color: var(--primary-high);
|
|
||||||
}
|
|
||||||
.d-icon {
|
|
||||||
color: var(--primary-low-mid);
|
|
||||||
margin-left: 0.15em;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -481,9 +481,11 @@ en:
|
||||||
topic:
|
topic:
|
||||||
title: "Topic summary"
|
title: "Topic summary"
|
||||||
close: "Close summary panel"
|
close: "Close summary panel"
|
||||||
gists_enabled: "with summary"
|
topic_list_layout:
|
||||||
gists_enabled_long: "with AI-generated summary"
|
button:
|
||||||
gists_disabled: "without summary"
|
compact: "Compact"
|
||||||
|
expanded: "Expanded"
|
||||||
|
expanded_description: "with AI summaries"
|
||||||
review:
|
review:
|
||||||
types:
|
types:
|
||||||
reviewable_ai_post:
|
reviewable_ai_post:
|
||||||
|
|
|
@ -24,6 +24,8 @@ register_asset "stylesheets/modules/summarization/mobile/ai-summary.scss", :mobi
|
||||||
register_asset "stylesheets/modules/summarization/common/ai-summary.scss"
|
register_asset "stylesheets/modules/summarization/common/ai-summary.scss"
|
||||||
register_asset "stylesheets/modules/summarization/desktop/ai-summary.scss", :desktop
|
register_asset "stylesheets/modules/summarization/desktop/ai-summary.scss", :desktop
|
||||||
|
|
||||||
|
register_asset "stylesheets/modules/summarization/common/ai-gists.scss"
|
||||||
|
|
||||||
register_asset "stylesheets/modules/ai-bot/common/bot-replies.scss"
|
register_asset "stylesheets/modules/ai-bot/common/bot-replies.scss"
|
||||||
register_asset "stylesheets/modules/ai-bot/common/ai-persona.scss"
|
register_asset "stylesheets/modules/ai-bot/common/ai-persona.scss"
|
||||||
register_asset "stylesheets/modules/ai-bot/mobile/ai-persona.scss", :mobile
|
register_asset "stylesheets/modules/ai-bot/mobile/ai-persona.scss", :mobile
|
||||||
|
|
|
@ -0,0 +1,16 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" style="display: none;">
|
||||||
|
<!-- "Discourse Table" is a Discourse derivative of https://fontawesome.com/v6/icons/table-list?f=classic&s=solid -->
|
||||||
|
<symbol id="discourse-table" viewBox="0 0 512 512">
|
||||||
|
<g>
|
||||||
|
<g id="Layer_1">
|
||||||
|
<path d="M0,96C0,60.7,28.7,32,64,32h384c35.3,0,64,28.7,64,64v320c0,35.3-28.7,64-64,64H64c-35.3,0-64-28.7-64-64V96ZM448,96H64v64h384v-64ZM448,224H64v64h384v-64ZM448,352H64v64h384v-64Z"/>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</symbol>
|
||||||
|
|
||||||
|
<!-- "Discourse Table Sparkles" is a Discourse derivative of https://fontawesome.com/v6/icons/table-list?f=classic&s=solid -->
|
||||||
|
<symbol id="discourse-table-sparkles" viewBox="0 0 512 512">
|
||||||
|
<path d="M448 309.64V413H64V290h190c12.23 0 18.46-14.71 9.94-23.48-7.56-7.78-14.48-16.2-20.66-25.16-5.36-7.77-14.24-12.36-23.69-12.36H64V93h130c10.65 0 20.14-6.92 23.18-17.12a193.4 193.4 0 0 1 9.74-25.76c4.56-9.86-2.77-21.12-13.63-21.12H64C28.65 29 0 57.65 0 93v320c0 35.35 28.65 64 64 64h384c35.35 0 64-28.65 64-64V263.8c0-9.16-10.7-14.14-17.7-8.25a194.056 194.056 0 0 1-25.76 18.32c-12.66 7.53-20.53 21.05-20.53 35.77Z"/><path d="M247.46 122.15c-6.45 2.44-10.75 8.6-10.75 15.49s4.3 13.05 10.75 15.49l81.01 30.4 30.4 81.01c2.44 6.45 8.6 10.75 15.49 10.75s13.05-4.3 15.49-10.75l30.4-81.01 81.01-30.4c6.45-2.44 10.75-8.6 10.75-15.49s-4.3-13.05-10.75-15.49l-81.01-30.4-30.4-81.01c-2.44-6.45-8.6-10.75-15.49-10.75s-13.05 4.3-15.49 10.75l-30.4 81.01-81.01 30.4Z"/>
|
||||||
|
</symbol>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 1.5 KiB |
Loading…
Reference in New Issue