mirror of
https://github.com/discourse/discourse.git
synced 2024-12-21 22:24:11 +08:00
0623ac684a
Second iteration of https://github.com/discourse/discourse/pull/23312 with a fix for embroider not resolving an export file using .gjs extension. --- This PR introduces three new concepts to Discourse codebase through an addon called "FloatKit": - menu - tooltip - toast ## Tooltips ### Component Simple cases can be express with an API similar to DButton: ```hbs <DTooltip @label={{i18n "foo.bar"}} @icon="check" @content="Something" /> ``` More complex cases can use blocks: ```hbs <DTooltip> <:trigger> {{d-icon "check"}} <span>{{i18n "foo.bar"}}</span> </:trigger> <:content> Something </:content> </DTooltip> ``` ### Service You can manually show a tooltip using the `tooltip` service: ```javascript const tooltipInstance = await this.tooltip.show( document.querySelector(".my-span"), options ) // and later manual close or destroy it tooltipInstance.close(); tooltipInstance.destroy(); // you can also just close any open tooltip through the service this.tooltip.close(); ``` The service also allows you to register event listeners on a trigger, it removes the need for you to manage open/close of a tooltip started through the service: ```javascript const tooltipInstance = this.tooltip.register( document.querySelector(".my-span"), options ) // when done you can destroy the instance to remove the listeners tooltipInstance.destroy(); ``` Note that the service also allows you to use a custom component as content which will receive `@data` and `@close` as args: ```javascript const tooltipInstance = await this.tooltip.show( document.querySelector(".my-span"), { component: MyComponent, data: { foo: 1 } } ) ``` ## Menus Menus are very similar to tooltips and provide the same kind of APIs: ### Component ```hbs <DMenu @icon="plus" @label={{i18n "foo.bar"}}> <ul> <li>Foo</li> <li>Bat</li> <li>Baz</li> </ul> </DMenu> ``` They also support blocks: ```hbs <DMenu> <:trigger> {{d-icon "plus"}} <span>{{i18n "foo.bar"}}</span> </:trigger> <:content> <ul> <li>Foo</li> <li>Bat</li> <li>Baz</li> </ul> </:content> </DMenu> ``` ### Service You can manually show a menu using the `menu` service: ```javascript const menuInstance = await this.menu.show( document.querySelector(".my-span"), options ) // and later manual close or destroy it menuInstance.close(); menuInstance.destroy(); // you can also just close any open tooltip through the service this.menu.close(); ``` The service also allows you to register event listeners on a trigger, it removes the need for you to manage open/close of a tooltip started through the service: ```javascript const menuInstance = this.menu.register( document.querySelector(".my-span"), options ) // when done you can destroy the instance to remove the listeners menuInstance.destroy(); ``` Note that the service also allows you to use a custom component as content which will receive `@data` and `@close` as args: ```javascript const menuInstance = await this.menu.show( document.querySelector(".my-span"), { component: MyComponent, data: { foo: 1 } } ) ``` ## Toasts Interacting with toasts is made only through the `toasts` service. A default component is provided (DDefaultToast) and can be used through dedicated service methods: - this.toasts.success({ ... }); - this.toasts.warning({ ... }); - this.toasts.info({ ... }); - this.toasts.error({ ... }); - this.toasts.default({ ... }); ```javascript this.toasts.success({ data: { title: "Foo", message: "Bar", actions: [ { label: "Ok", class: "btn-primary", action: (componentArgs) => { // eslint-disable-next-line no-alert alert("Closing toast:" + componentArgs.data.title); componentArgs.close(); }, } ] }, }); ``` You can also provide your own component: ```javascript this.toasts.show(MyComponent, { autoClose: false, class: "foo", data: { baz: 1 }, }) ``` Co-authored-by: Martin Brennan <mjrbrennan@gmail.com> Co-authored-by: Isaac Janzen <50783505+janzenisaac@users.noreply.github.com> Co-authored-by: David Taylor <david@taylorhq.com> Co-authored-by: Jarek Radosz <jradosz@gmail.com>
285 lines
5.0 KiB
SCSS
285 lines
5.0 KiB
SCSS
.discourse-local-date {
|
|
> * {
|
|
pointer-events: none;
|
|
}
|
|
|
|
&.cooked-date {
|
|
color: var(--primary);
|
|
cursor: pointer;
|
|
border-bottom: 1px dashed var(--primary-medium);
|
|
white-space: nowrap;
|
|
|
|
.d-icon {
|
|
color: var(--primary);
|
|
}
|
|
|
|
&.past {
|
|
border-bottom-color: var(--primary-low-mid);
|
|
}
|
|
|
|
&.past[data-countdown] {
|
|
color: var(--primary-medium);
|
|
}
|
|
}
|
|
}
|
|
|
|
.locale-dates-previews {
|
|
max-width: 250px;
|
|
|
|
.preview {
|
|
display: flex;
|
|
flex-direction: column;
|
|
padding: 5px;
|
|
margin: 0;
|
|
|
|
.timezone {
|
|
font-weight: 700;
|
|
}
|
|
|
|
&.current {
|
|
background: var(--tertiary-low);
|
|
}
|
|
}
|
|
}
|
|
|
|
.download-calendar {
|
|
text-align: right;
|
|
cursor: pointer;
|
|
margin-top: 0.5em;
|
|
}
|
|
|
|
.discourse-local-dates-create-modal-footer {
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: flex-start;
|
|
|
|
&:before,
|
|
&:after {
|
|
content: none;
|
|
}
|
|
|
|
.advanced-mode-btn {
|
|
margin-left: auto;
|
|
}
|
|
}
|
|
|
|
.discourse-local-dates-create-modal {
|
|
box-sizing: border-box;
|
|
min-height: 320px;
|
|
display: flex;
|
|
flex-direction: row;
|
|
padding: 0.5em;
|
|
|
|
.form {
|
|
flex: 1 0 0px;
|
|
|
|
label {
|
|
font-weight: 700;
|
|
}
|
|
|
|
.date-time-configuration {
|
|
display: flex;
|
|
|
|
.fake-input {
|
|
display: none;
|
|
}
|
|
|
|
.timezone-input {
|
|
width: 100%;
|
|
|
|
&.is-expanded {
|
|
.select-kit-header {
|
|
border: 1px solid var(--primary-medium);
|
|
}
|
|
}
|
|
|
|
.select-kit-header {
|
|
padding: 0.5em 0.5em;
|
|
border: 1px solid var(--primary-low);
|
|
|
|
.d-icon {
|
|
margin-right: 1em;
|
|
}
|
|
|
|
.caret-icon {
|
|
margin-right: 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
.date-time-control {
|
|
position: relative;
|
|
display: flex;
|
|
border: 1px solid var(--primary-low);
|
|
|
|
&.is-filled,
|
|
&.is-selected {
|
|
.date-time {
|
|
color: var(--primary);
|
|
background: var(--secondary);
|
|
}
|
|
|
|
.d-icon {
|
|
color: var(--primary-high);
|
|
}
|
|
}
|
|
|
|
&.from {
|
|
border-radius: 5px 5px 0 0;
|
|
|
|
.date-time {
|
|
border-radius: 5px 5px 0 0;
|
|
}
|
|
|
|
&.is-selected {
|
|
border-color: var(--tertiary);
|
|
}
|
|
}
|
|
|
|
&.to {
|
|
border-radius: 0 0 5px 5px;
|
|
margin-bottom: 1em;
|
|
|
|
.date-time {
|
|
border-radius: 0 0 5px 5px;
|
|
padding-right: 3em;
|
|
}
|
|
|
|
&.is-selected {
|
|
border-color: var(--tertiary);
|
|
}
|
|
}
|
|
|
|
.date-time {
|
|
color: var(--primary-medium);
|
|
background: var(--primary-very-low);
|
|
padding: 1em 0.5em 1em 2em;
|
|
border: 0;
|
|
outline: none;
|
|
flex: 1;
|
|
@include ellipsis;
|
|
width: 100%;
|
|
justify-content: flex-start;
|
|
&:focus {
|
|
background-color: var(--tertiary-50);
|
|
}
|
|
}
|
|
|
|
.d-icon {
|
|
position: absolute;
|
|
margin-top: auto;
|
|
margin-bottom: auto;
|
|
left: 0.5em;
|
|
top: 0;
|
|
bottom: 0;
|
|
color: var(--primary-medium);
|
|
}
|
|
|
|
.delete-to-date {
|
|
position: absolute;
|
|
margin-top: auto;
|
|
margin-bottom: auto;
|
|
right: 0;
|
|
width: 30px;
|
|
top: 0;
|
|
bottom: 0;
|
|
color: var(--primary-high);
|
|
border-radius: 0 0 5px 0;
|
|
}
|
|
}
|
|
|
|
.inputs-panel {
|
|
flex: 1;
|
|
}
|
|
}
|
|
|
|
.preview {
|
|
text-align: center;
|
|
margin-top: 0;
|
|
margin-bottom: 0.5em;
|
|
display: flex;
|
|
align-items: center;
|
|
padding: 0.5em;
|
|
flex-wrap: wrap;
|
|
|
|
b {
|
|
margin-right: 0.5em;
|
|
margin-left: 0.5em;
|
|
}
|
|
|
|
b + p {
|
|
margin: 0;
|
|
display: inline-block;
|
|
}
|
|
}
|
|
|
|
.recurrence {
|
|
.recurrence-input {
|
|
width: 350px;
|
|
}
|
|
}
|
|
}
|
|
|
|
.validation-error {
|
|
margin-bottom: 0.5em;
|
|
}
|
|
|
|
.format {
|
|
.format-input {
|
|
width: 280px;
|
|
}
|
|
}
|
|
|
|
.formats {
|
|
list-style: none;
|
|
padding: 0;
|
|
margin: 0;
|
|
.format {
|
|
.previewed-format {
|
|
color: var(--primary-medium);
|
|
}
|
|
}
|
|
}
|
|
|
|
.control-group.recurrence,
|
|
.control-group.format,
|
|
.control-group.timezones {
|
|
margin-top: 1em;
|
|
}
|
|
|
|
.timezones-input {
|
|
width: 350px;
|
|
}
|
|
}
|
|
|
|
html:not(.mobile-view) {
|
|
.fixed-modal .discourse-local-dates-create-modal.modal-body {
|
|
width: 40em; // using ems to scale with user font size
|
|
max-width: 100vw; // avoids overflow if someone has extreme font-sizes impacting width
|
|
max-height: 400px !important;
|
|
}
|
|
}
|
|
|
|
html.mobile-view {
|
|
.fixed-modal .discourse-local-dates-create-modal.modal-body {
|
|
max-height: 400px !important;
|
|
|
|
.date-time-configuration {
|
|
flex-direction: column;
|
|
}
|
|
|
|
.calendar-date-time-input {
|
|
width: 100%;
|
|
margin: 0 0 1em 0;
|
|
|
|
.pika-single {
|
|
justify-content: center;
|
|
}
|
|
|
|
.time-picker {
|
|
padding-top: 6px;
|
|
}
|
|
}
|
|
}
|
|
}
|