mirror of
https://github.com/zulip/zulip.git
synced 2025-10-23 04:52:12 +00:00
banners: Add new redesigned banner component.
This commit adds the redesigned banner component to the codebase along with a storybook-style page in /devtools/banners to view and test the redesigned banner component. Any banner using the new redesigned styles, requires two classes, - First, the base `banner` class which defines the structure and behavior of the banner. - Second, a modifier class like `banner-info` which defines the styles for the particular banner type. The navbar alert banners also have a custom class `navbar-alert-banner` which is used to define the specific style and structure for these banner types. This commit also makes the `banner`, `action-button` and `icon-button` components into handlebar templates to maintain consistency in their usage in the codebase.
This commit is contained in:
211
templates/zerver/development/design_testing/banners.html
Normal file
211
templates/zerver/development/design_testing/banners.html
Normal file
@@ -0,0 +1,211 @@
|
||||
{% extends "zerver/base.html" %}
|
||||
{% set entrypoint = "dev-testing" %}
|
||||
|
||||
{% block title %}
|
||||
<title>{{ doc_root_title }} | Zulip Dev</title>
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="portico-container" data-platform="{{ platform }}">
|
||||
<div class="portico-wrap">
|
||||
{% include 'zerver/portico-header.html' %}
|
||||
<div class="app portico-page">
|
||||
<div class="banner-wrapper" id="dev_navbar_alerts_wrapper"></div>
|
||||
<div class="app-main portico-page-container">
|
||||
<div class="design-testing-wrapper">
|
||||
<div class="banner-wrapper" id="dev_normal_banner_wrapper"></div>
|
||||
<section class="design-controls-section">
|
||||
<div class="design-testing-controls-label">Theme Settings</div>
|
||||
<div class="design-testing-controls">
|
||||
<div class="design-testing-control">
|
||||
<span class="control-label">Dark Theme</span>
|
||||
<div role="group" class="tab-picker control-setting">
|
||||
<input type="radio" data-theme="dark" id="dev_enable_dark_theme_banners" class="tab-option" name="dark-theme-select"/>
|
||||
<label role="menuitemradio" class="tab-option-content design-testing-control-element" for="dev_enable_dark_theme_banners" tabindex="0">
|
||||
<span>Enable</span>
|
||||
</label>
|
||||
<input type="radio" data-theme="light" id="dev_disable_dark_theme_banners" class="tab-option" name="dark-theme-select" checked/>
|
||||
<label role="menuitemradio" class="tab-option-content design-testing-control-element" for="dev_disable_dark_theme_banners" tabindex="0">
|
||||
<span>Disable</span>
|
||||
</label>
|
||||
<span class="slider"></span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="design-testing-control">
|
||||
<span class="control-label">Select Background</span>
|
||||
<select class="design-testing-control-element control-setting select_background">
|
||||
{% for background in background_colors %}
|
||||
<option value="{{ background.css_var }}" {% if background.css_var == "--color-background" %}selected{% endif %}>{{ background.name }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="design-testing-controls-label">Banner Settings</div>
|
||||
<div class="design-testing-controls">
|
||||
<div class="design-testing-control">
|
||||
<span class="control-label">Alert Banner Type</span>
|
||||
<select class="design-testing-control-element control-setting" id="banner_select_type"></select>
|
||||
</div>
|
||||
<div class="design-testing-control">
|
||||
<span class="control-label">Banner Intent</span>
|
||||
<select class="design-testing-control-element control-setting" id="banner_select_intent"></select>
|
||||
</div>
|
||||
<div class="design-testing-control">
|
||||
<span class="control-label">Banner Label</span>
|
||||
<input class="design-testing-control-element control-setting" type="text" id="banner_label" />
|
||||
</div>
|
||||
<div class="design-testing-control">
|
||||
<span class="control-label">Banner Close Button</span>
|
||||
<div role="group" class="tab-picker control-setting">
|
||||
<input type="radio" id="enable_banner_close_button" class="tab-option" name="banner-close-button-select"/>
|
||||
<label role="menuitemradio" class="tab-option-content design-testing-control-element" for="enable_banner_close_button" tabindex="0">
|
||||
<span>Enable</span>
|
||||
</label>
|
||||
<input type="radio" id="disable_banner_close_button" class="tab-option" name="banner-close-button-select" checked/>
|
||||
<label role="menuitemradio" class="tab-option-content design-testing-control-element" for="disable_banner_close_button" tabindex="0">
|
||||
<span>Disable</span>
|
||||
</label>
|
||||
<span class="slider"></span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="design-testing-controls-label">Primary Button Settings</div>
|
||||
<div class="design-testing-controls">
|
||||
<div class="design-testing-control">
|
||||
<span class="control-label">Button</span>
|
||||
<div role="group" class="tab-picker control-setting">
|
||||
<input type="radio" id="enable_primary_button" class="tab-option" name="primary-button-select"/>
|
||||
<label role="menuitemradio" class="tab-option-content design-testing-control-element" for="enable_primary_button" tabindex="0">
|
||||
<span>Enable</span>
|
||||
</label>
|
||||
<input type="radio" id="disable_primary_button" class="tab-option" name="primary-button-select" checked/>
|
||||
<label role="menuitemradio" class="tab-option-content design-testing-control-element" for="disable_primary_button" tabindex="0">
|
||||
<span>Disable</span>
|
||||
</label>
|
||||
<span class="slider"></span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="design-testing-control">
|
||||
<span class="control-label">Button Icon</span>
|
||||
<div role="group" class="tab-picker control-setting">
|
||||
<input type="radio" id="enable_primary_button_icon" class="tab-option" name="primary-button-icon-select"/>
|
||||
<label role="menuitemradio" class="tab-option-content design-testing-control-element" for="enable_primary_button_icon" tabindex="0">
|
||||
<span>Enable</span>
|
||||
</label>
|
||||
<input type="radio" id="disable_primary_button_icon" class="tab-option" name="primary-button-icon-select" checked/>
|
||||
<label role="menuitemradio" class="tab-option-content design-testing-control-element" for="disable_primary_button_icon" tabindex="0">
|
||||
<span>Disable</span>
|
||||
</label>
|
||||
<span class="slider"></span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="design-testing-control">
|
||||
<span class="control-label">Select Icon</span>
|
||||
<select class="design-testing-control-element control-setting" id="primary_button_select_icon">
|
||||
{% for icon in icons %}
|
||||
<option value="{{ icon }}" {% if icon == "move-alt" %}selected{% endif %}>{{ icon }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</div>
|
||||
<div class="design-testing-control">
|
||||
<span class="control-label">Button Text</span>
|
||||
<input class="design-testing-control-element control-setting" type="text" id="primary_button_text" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="design-testing-controls-label">Quiet Button Settings</div>
|
||||
<div class="design-testing-controls">
|
||||
<div class="design-testing-control">
|
||||
<span class="control-label">Button</span>
|
||||
<div role="group" class="tab-picker control-setting">
|
||||
<input type="radio" id="enable_quiet_button" class="tab-option" name="quiet-button-select"/>
|
||||
<label role="menuitemradio" class="tab-option-content design-testing-control-element" for="enable_quiet_button" tabindex="0">
|
||||
<span>Enable</span>
|
||||
</label>
|
||||
<input type="radio" id="disable_quiet_button" class="tab-option" name="quiet-button-select" checked/>
|
||||
<label role="menuitemradio" class="tab-option-content design-testing-control-element" for="disable_quiet_button" tabindex="0">
|
||||
<span>Disable</span>
|
||||
</label>
|
||||
<span class="slider"></span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="design-testing-control">
|
||||
<span class="control-label">Button Icon</span>
|
||||
<div role="group" class="tab-picker control-setting">
|
||||
<input type="radio" id="enable_quiet_button_icon" class="tab-option" name="quiet-button-icon-select"/>
|
||||
<label role="menuitemradio" class="tab-option-content design-testing-control-element" for="enable_quiet_button_icon" tabindex="0">
|
||||
<span>Enable</span>
|
||||
</label>
|
||||
<input type="radio" id="disable_quiet_button_icon" class="tab-option" name="quiet-button-icon-select" checked/>
|
||||
<label role="menuitemradio" class="tab-option-content design-testing-control-element" for="disable_quiet_button_icon" tabindex="0">
|
||||
<span>Disable</span>
|
||||
</label>
|
||||
<span class="slider"></span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="design-testing-control">
|
||||
<span class="control-label">Select Icon</span>
|
||||
<select class="design-testing-control-element control-setting" id="quiet_button_select_icon">
|
||||
{% for icon in icons %}
|
||||
<option value="{{ icon }}" {% if icon == "move-alt" %}selected{% endif %}>{{ icon }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</div>
|
||||
<div class="design-testing-control">
|
||||
<span class="control-label">Button Text</span>
|
||||
<input class="design-testing-control-element control-setting" type="text" id="quiet_button_text" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="design-testing-controls-label">Borderless Button Settings</div>
|
||||
<div class="design-testing-controls">
|
||||
<div class="design-testing-control">
|
||||
<span class="control-label">Button</span>
|
||||
<div role="group" class="tab-picker control-setting">
|
||||
<input type="radio" id="enable_borderless_button" class="tab-option" name="borderless-button-select"/>
|
||||
<label role="menuitemradio" class="tab-option-content design-testing-control-element" for="enable_borderless_button" tabindex="0">
|
||||
<span>Enable</span>
|
||||
</label>
|
||||
<input type="radio" id="disable_borderless_button" class="tab-option" name="borderless-button-select" checked/>
|
||||
<label role="menuitemradio" class="tab-option-content design-testing-control-element" for="disable_borderless_button" tabindex="0">
|
||||
<span>Disable</span>
|
||||
</label>
|
||||
<span class="slider"></span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="design-testing-control">
|
||||
<span class="control-label">Button Icon</span>
|
||||
<div role="group" class="tab-picker control-setting">
|
||||
<input type="radio" id="enable_borderless_button_icon" class="tab-option" name="borderless-button-icon-select"/>
|
||||
<label role="menuitemradio" class="tab-option-content design-testing-control-element" for="enable_borderless_button_icon" tabindex="0">
|
||||
<span>Enable</span>
|
||||
</label>
|
||||
<input type="radio" id="disable_borderless_button_icon" class="tab-option" name="borderless-button-icon-select" checked/>
|
||||
<label role="menuitemradio" class="tab-option-content design-testing-control-element" for="disable_borderless_button_icon" tabindex="0">
|
||||
<span>Disable</span>
|
||||
</label>
|
||||
<span class="slider"></span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="design-testing-control">
|
||||
<span class="control-label">Select Icon</span>
|
||||
<select class="design-testing-control-element control-setting" id="borderless_button_select_icon">
|
||||
{% for icon in icons %}
|
||||
<option value="{{ icon }}" {% if icon == "move-alt" %}selected{% endif %}>{{ icon }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</div>
|
||||
<div class="design-testing-control">
|
||||
<span class="control-label">Button Text</span>
|
||||
<input class="design-testing-control-element control-setting" type="text" id="borderless_button_text" />
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
@@ -1,8 +1,8 @@
|
||||
{% extends "zerver/base.html" %}
|
||||
{% set entrypoint = "dev-buttons" %}
|
||||
{% set entrypoint = "dev-testing" %}
|
||||
|
||||
{% block title %}
|
||||
<title>Button styles browser | Zulip Dev</title>
|
||||
<title>{{ doc_root_title }} | Zulip Dev</title>
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
@@ -11,7 +11,6 @@
|
||||
{% include 'zerver/portico-header.html' %}
|
||||
<div class="app portico-page">
|
||||
<div class="app-main portico-page-container">
|
||||
<div class="design-testing-title">Button styles browser</div>
|
||||
<div class="design-testing-wrapper">
|
||||
<div class="dev-buttons-grid">
|
||||
<div class="dev-buttons-variant-group">
|
||||
@@ -169,18 +168,18 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<section class="action-button-section">
|
||||
<div class="section-heading">Controls</div>
|
||||
<section class="design-controls-section">
|
||||
<div class="design-testing-controls-label">Controls</div>
|
||||
<div class="design-testing-controls">
|
||||
<div class="design-testing-control">
|
||||
<span class="control-label">Dark Theme</span>
|
||||
<div role="group" class="tab-picker">
|
||||
<input type="radio" id="enable_dark_theme" class="tab-option" name="dark-theme-select"/>
|
||||
<label role="menuitemradio" class="tab-option-content design-testing-control-element" for="enable_dark_theme" tabindex="0">
|
||||
<input type="radio" data-theme="dark" id="dev_enable_dark_theme_buttons" class="tab-option" name="dark-theme-select"/>
|
||||
<label role="menuitemradio" class="tab-option-content design-testing-control-element" for="dev_enable_dark_theme_buttons" tabindex="0">
|
||||
<span>Enable</span>
|
||||
</label>
|
||||
<input type="radio" id="disable_dark_theme" class="tab-option" name="dark-theme-select" checked/>
|
||||
<label role="menuitemradio" class="tab-option-content design-testing-control-element" for="disable_dark_theme" tabindex="0">
|
||||
<input type="radio" data-theme="light" id="dev_disable_dark_theme_buttons" class="tab-option" name="dark-theme-select" checked/>
|
||||
<label role="menuitemradio" class="tab-option-content design-testing-control-element" for="dev_disable_dark_theme_buttons" tabindex="0">
|
||||
<span>Disable</span>
|
||||
</label>
|
||||
<span class="slider"></span>
|
||||
@@ -188,7 +187,7 @@
|
||||
</div>
|
||||
<div class="design-testing-control">
|
||||
<span class="control-label">Select Background</span>
|
||||
<select class="design-testing-control-element" id="button_select_background">
|
||||
<select class="design-testing-control-element select_background">
|
||||
{% for background in background_colors %}
|
||||
<option value="{{ background.css_var }}" {% if background.css_var == "--color-background" %}selected{% endif %}>{{ background.name }}</option>
|
||||
{% endfor %}
|
||||
|
@@ -84,6 +84,11 @@
|
||||
<td>None needed</td>
|
||||
<td>Test button styles</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a href="/devtools/banners">/devtools/banners</a></td>
|
||||
<td>None needed</td>
|
||||
<td>Test banner styles</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<h2>Useful management commands</h2>
|
||||
|
@@ -23,6 +23,9 @@
|
||||
{% if page_is_policy_center %}
|
||||
<span class="light portico-header-text"> | <a href="{{ root_domain_url }}/policies/">{{ doc_root_title }}</a></span>
|
||||
{% endif %}
|
||||
{% if page_is_design_testing %}
|
||||
<span class="light portico-header-text"> | <a href="{{ root_domain_url }}/devtools/{{ design_component }}">{{ doc_root_title }}</a></span>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
11
web/src/bundles/design-testing.ts
Normal file
11
web/src/bundles/design-testing.ts
Normal file
@@ -0,0 +1,11 @@
|
||||
import "./common.ts";
|
||||
import "../portico/header.ts";
|
||||
import "../portico/design-testing.ts";
|
||||
|
||||
// Import styles in the required order
|
||||
import "../../styles/portico/portico_styles.css";
|
||||
import "../../styles/portico/dev-testing.css";
|
||||
import "../../styles/app_variables.css";
|
||||
import "../../styles/buttons.css";
|
||||
import "../../styles/banners.css";
|
||||
import "../../styles/app_components.css";
|
@@ -1,10 +1,299 @@
|
||||
import Handlebars from "handlebars/runtime.js";
|
||||
import $ from "jquery";
|
||||
|
||||
import {$t} from "../i18n.ts";
|
||||
import render_banner from "../../templates/components/banner.hbs";
|
||||
import {$t, $t_html} from "../i18n.ts";
|
||||
|
||||
type ComponentIntent = "neutral" | "brand" | "info" | "success" | "warning" | "danger";
|
||||
|
||||
type ActionButton = {
|
||||
type: "primary" | "quiet" | "borderless";
|
||||
intent: ComponentIntent;
|
||||
label: string;
|
||||
icon?: string | undefined;
|
||||
};
|
||||
|
||||
type Banner = {
|
||||
intent: ComponentIntent;
|
||||
label: string | Handlebars.SafeString;
|
||||
buttons: ActionButton[];
|
||||
close_button: boolean;
|
||||
custom_classes?: string;
|
||||
};
|
||||
|
||||
type AlertBanner = Banner & {
|
||||
process: string;
|
||||
};
|
||||
|
||||
const component_intents: ComponentIntent[] = [
|
||||
"neutral",
|
||||
"brand",
|
||||
"info",
|
||||
"success",
|
||||
"warning",
|
||||
"danger",
|
||||
];
|
||||
|
||||
const banner_html = (banner: Banner | AlertBanner): string => render_banner(banner);
|
||||
|
||||
const custom_normal_banner: Banner = {
|
||||
intent: "neutral",
|
||||
label: "This is a normal banner. Use the controls below to modify this banner.",
|
||||
buttons: [
|
||||
{
|
||||
type: "quiet",
|
||||
intent: "neutral",
|
||||
label: "Quiet Button",
|
||||
},
|
||||
],
|
||||
close_button: true,
|
||||
};
|
||||
|
||||
const alert_banners: Record<string, AlertBanner> = {
|
||||
"custom-banner": {
|
||||
process: "custom-banner",
|
||||
intent: "neutral",
|
||||
label: "This is a navbar alerts banner. Use the controls below to modify this banner.",
|
||||
buttons: [
|
||||
{
|
||||
type: "quiet",
|
||||
intent: "neutral",
|
||||
label: "Quiet Button",
|
||||
},
|
||||
],
|
||||
close_button: true,
|
||||
custom_classes: "navbar-alert-banner",
|
||||
},
|
||||
bankruptcy: {
|
||||
process: "bankruptcy",
|
||||
intent: "info",
|
||||
label: "Welcome back! You have 12 unread messages. Do you want to mark them all as read?",
|
||||
buttons: [
|
||||
{
|
||||
type: "quiet",
|
||||
intent: "info",
|
||||
label: "Yes, please!",
|
||||
},
|
||||
{
|
||||
type: "borderless",
|
||||
intent: "info",
|
||||
label: "No, I'll catch up.",
|
||||
},
|
||||
],
|
||||
close_button: true,
|
||||
custom_classes: "navbar-alert-banner",
|
||||
},
|
||||
"email-server": {
|
||||
process: "email-server",
|
||||
intent: "warning",
|
||||
label: "Zulip needs to send email to confirm users' addresses and send notifications.",
|
||||
buttons: [
|
||||
{
|
||||
type: "quiet",
|
||||
intent: "warning",
|
||||
label: "Configuration instructions",
|
||||
},
|
||||
],
|
||||
close_button: true,
|
||||
custom_classes: "navbar-alert-banner",
|
||||
},
|
||||
"demo-organization-deadline": {
|
||||
process: "demo-organization-deadline",
|
||||
intent: "info",
|
||||
label: new Handlebars.SafeString(
|
||||
$t_html(
|
||||
{
|
||||
defaultMessage:
|
||||
"This <demo_link>demo organization</demo_link> will be automatically deleted in 30 days, unless it's <convert_link>converted into a permanent organization</convert_link>.",
|
||||
},
|
||||
{
|
||||
demo_link: (content_html) =>
|
||||
`<a class="banner__link" href="https://zulip.com/help/demo-organizations" target="_blank" rel="noopener noreferrer">${content_html.join("")}</a>`,
|
||||
convert_link: (content_html) =>
|
||||
`<a class="banner__link" href="https://zulip.com/help/demo-organizations#convert-a-demo-organization-to-a-permanent-organization" target="_blank" rel="noopener noreferrer">${content_html.join("")}</a>`,
|
||||
},
|
||||
),
|
||||
),
|
||||
buttons: [],
|
||||
close_button: true,
|
||||
custom_classes: "navbar-alert-banner",
|
||||
},
|
||||
notifications: {
|
||||
process: "notifications",
|
||||
intent: "brand",
|
||||
label: new Handlebars.SafeString(
|
||||
$t_html(
|
||||
{
|
||||
defaultMessage:
|
||||
"Zulip needs your permission to enable desktop notifications for messages you receive. You can <z-link>customize</z-link> what kinds of messages trigger notifications.",
|
||||
},
|
||||
{
|
||||
"z-link": (content_html) =>
|
||||
`<a class="banner__link" href="https://zulip.com/help/desktop-notifications#desktop-notifications" target="_blank" rel="noopener noreferrer">${content_html.join("")}</a>`,
|
||||
},
|
||||
),
|
||||
),
|
||||
buttons: [
|
||||
{
|
||||
type: "primary",
|
||||
intent: "brand",
|
||||
label: "Enable notifications",
|
||||
},
|
||||
{
|
||||
type: "quiet",
|
||||
intent: "brand",
|
||||
label: "Ask me later",
|
||||
},
|
||||
{
|
||||
type: "borderless",
|
||||
intent: "brand",
|
||||
label: "Never ask on this computer",
|
||||
},
|
||||
],
|
||||
close_button: true,
|
||||
custom_classes: "navbar-alert-banner",
|
||||
},
|
||||
"profile-missing-required": {
|
||||
process: "profile-missing-required",
|
||||
intent: "warning",
|
||||
label: "Your profile is missing required fields.",
|
||||
buttons: [
|
||||
{
|
||||
type: "quiet",
|
||||
intent: "warning",
|
||||
label: "Edit your profile",
|
||||
},
|
||||
],
|
||||
close_button: true,
|
||||
custom_classes: "navbar-alert-banner",
|
||||
},
|
||||
"insecure-desktop-app": {
|
||||
process: "insecure-desktop-app",
|
||||
intent: "danger",
|
||||
label: "You are using an old version of the Zulip desktop app with known security bugs.",
|
||||
buttons: [
|
||||
{
|
||||
type: "quiet",
|
||||
intent: "danger",
|
||||
label: "Download the latest version",
|
||||
},
|
||||
],
|
||||
close_button: true,
|
||||
custom_classes: "navbar-alert-banner",
|
||||
},
|
||||
"profile-incomplete": {
|
||||
process: "profile-incomplete",
|
||||
intent: "info",
|
||||
label: "Complete your organization profile, which is displayed on your organization's registration and login pages.",
|
||||
buttons: [
|
||||
{
|
||||
type: "quiet",
|
||||
intent: "info",
|
||||
label: "Edit profile",
|
||||
},
|
||||
],
|
||||
close_button: true,
|
||||
custom_classes: "navbar-alert-banner",
|
||||
},
|
||||
"server-needs-upgrade": {
|
||||
process: "server-needs-upgrade",
|
||||
intent: "danger",
|
||||
label: "This Zulip server is running an old version and should be upgraded.",
|
||||
buttons: [
|
||||
{
|
||||
type: "quiet",
|
||||
intent: "danger",
|
||||
label: "Learn more",
|
||||
},
|
||||
{
|
||||
type: "borderless",
|
||||
intent: "danger",
|
||||
label: "Dismiss for a week",
|
||||
},
|
||||
],
|
||||
close_button: true,
|
||||
custom_classes: "navbar-alert-banner",
|
||||
},
|
||||
};
|
||||
|
||||
const sortButtons = (buttons: ActionButton[]): void => {
|
||||
const sortOrder: Record<ActionButton["type"], number> = {
|
||||
primary: 1,
|
||||
quiet: 2,
|
||||
borderless: 3,
|
||||
};
|
||||
|
||||
buttons.sort((a, b) => sortOrder[a.type] - sortOrder[b.type]);
|
||||
};
|
||||
|
||||
const update_buttons = (buttons: ActionButton[]): void => {
|
||||
const primary_button = buttons.find((button) => button.type === "primary");
|
||||
if (primary_button) {
|
||||
$("#enable_primary_button").prop("checked", true);
|
||||
$("#primary_button_text").val(primary_button.label);
|
||||
if (primary_button.icon) {
|
||||
$("#primary_button_select_icon").val(primary_button.icon);
|
||||
$("#enable_primary_button_icon").prop("checked", true);
|
||||
} else {
|
||||
$("#disable_primary_button_icon").prop("checked", true);
|
||||
}
|
||||
} else {
|
||||
$("#disable_primary_button").prop("checked", true);
|
||||
$("#primary_button_text").val("");
|
||||
$("#disable_primary_button_icon").prop("checked", true);
|
||||
}
|
||||
const quiet_button = buttons.find((button) => button.type === "quiet");
|
||||
if (quiet_button) {
|
||||
$("#enable_quiet_button").prop("checked", true);
|
||||
$("#quiet_button_text").val(quiet_button.label);
|
||||
if (quiet_button.icon) {
|
||||
$("#quiet_button_select_icon").val(quiet_button.icon);
|
||||
$("#enable_quiet_button_icon").prop("checked", true);
|
||||
} else {
|
||||
$("#disable_quiet_button_icon").prop("checked", true);
|
||||
}
|
||||
} else {
|
||||
$("#disable_quiet_button").prop("checked", true);
|
||||
$("#quiet_button_text").val("");
|
||||
$("#disable_quiet_button_icon").prop("checked", true);
|
||||
}
|
||||
const borderless_button = buttons.find((button) => button.type === "borderless");
|
||||
if (borderless_button) {
|
||||
$("#enable_borderless_button").prop("checked", true);
|
||||
$("#borderless_button_text").val(borderless_button.label);
|
||||
if (borderless_button.icon) {
|
||||
$("#borderless_button_select_icon").val(borderless_button.icon);
|
||||
$("#enable_borderless_button_icon").prop("checked", true);
|
||||
} else {
|
||||
$("#disable_borderless_button_icon").prop("checked", true);
|
||||
}
|
||||
} else {
|
||||
$("#disable_borderless_button").prop("checked", true);
|
||||
$("#borderless_button_text").val("");
|
||||
$("#disable_borderless_button_icon").prop("checked", true);
|
||||
}
|
||||
};
|
||||
|
||||
function update_banner(): void {
|
||||
$("#dev_navbar_alerts_wrapper").html(banner_html(current_banner));
|
||||
$("#dev_normal_banner_wrapper").html(banner_html(custom_normal_banner));
|
||||
|
||||
$("#banner_select_intent").val(current_banner.intent);
|
||||
$("#banner_label").val(current_banner.label.toString());
|
||||
update_buttons(current_banner.buttons);
|
||||
if (current_banner.close_button) {
|
||||
$("#enable_banner_close_button").prop("checked", true);
|
||||
} else {
|
||||
$("#disable_banner_close_button").prop("checked", true);
|
||||
}
|
||||
}
|
||||
|
||||
let current_banner = alert_banners["custom-banner"]!;
|
||||
|
||||
$(window).on("load", () => {
|
||||
// Code for /devtools/buttons design testing page.
|
||||
$("input[name='dark-theme-select']").on("change", (e) => {
|
||||
if ($(e.target).attr("id") === "enable_dark_theme") {
|
||||
if ($(e.target).data("theme") === "dark") {
|
||||
$(":root").addClass("dark-theme");
|
||||
} else {
|
||||
$(":root").removeClass("dark-theme");
|
||||
@@ -38,8 +327,314 @@ $(window).on("load", () => {
|
||||
);
|
||||
});
|
||||
|
||||
$("#button_select_background").on("change", function (this: HTMLElement) {
|
||||
$(".select_background").on("change", function (this: HTMLElement) {
|
||||
const background_var = $(this).val()?.toString() ?? "";
|
||||
$("body").css("background-color", `var(${background_var})`);
|
||||
});
|
||||
|
||||
// Code for /devtools/banners design testing page.
|
||||
update_banner();
|
||||
|
||||
// Populate banner type select options
|
||||
const $banner_select = $("#banner_select_type");
|
||||
for (const key of Object.keys(alert_banners)) {
|
||||
$banner_select.append($("<option>").val(key).text(key));
|
||||
}
|
||||
|
||||
const $banner_intent_select = $("#banner_select_intent");
|
||||
for (const intent of component_intents) {
|
||||
$banner_intent_select.append($("<option>").val(intent).text(intent));
|
||||
}
|
||||
|
||||
$("#banner_select_intent").on("change", function (this: HTMLElement) {
|
||||
const selected_intent = $(this).val()?.toString();
|
||||
if (selected_intent === undefined) {
|
||||
return;
|
||||
}
|
||||
current_banner.intent =
|
||||
component_intents.find((intent) => intent === selected_intent) ?? "neutral";
|
||||
for (const button of current_banner.buttons) {
|
||||
button.intent = current_banner.intent;
|
||||
}
|
||||
if (current_banner.process === "custom-banner") {
|
||||
custom_normal_banner.intent = current_banner.intent;
|
||||
for (const button of custom_normal_banner.buttons) {
|
||||
button.intent = custom_normal_banner.intent;
|
||||
}
|
||||
$("#dev_normal_banner_wrapper").html(banner_html(custom_normal_banner));
|
||||
}
|
||||
$("#dev_navbar_alerts_wrapper").html(banner_html(current_banner));
|
||||
});
|
||||
|
||||
$banner_select.on("change", function (this: HTMLElement) {
|
||||
const banner_type = $(this).val()?.toString();
|
||||
if (banner_type === undefined) {
|
||||
return;
|
||||
}
|
||||
current_banner = alert_banners[banner_type]!;
|
||||
update_banner();
|
||||
});
|
||||
|
||||
$("input[name='banner-close-button-select']").on("change", (e) => {
|
||||
if ($(e.target).attr("id") === "enable_banner_close_button") {
|
||||
current_banner.close_button = true;
|
||||
} else {
|
||||
current_banner.close_button = false;
|
||||
}
|
||||
$("#dev_navbar_alerts_wrapper").html(banner_html(current_banner));
|
||||
if (current_banner.process === "custom-banner") {
|
||||
custom_normal_banner.close_button = current_banner.close_button;
|
||||
$("#dev_normal_banner_wrapper").html(banner_html(custom_normal_banner));
|
||||
}
|
||||
});
|
||||
|
||||
$("#banner_label").on("input", function (this: HTMLElement) {
|
||||
const banner_label = $(this).val()?.toString() ?? "";
|
||||
current_banner.label = banner_label;
|
||||
$("#dev_navbar_alerts_wrapper").html(banner_html(current_banner));
|
||||
if (current_banner.process === "custom-banner") {
|
||||
custom_normal_banner.label = banner_label;
|
||||
$("#dev_normal_banner_wrapper").html(banner_html(custom_normal_banner));
|
||||
}
|
||||
});
|
||||
|
||||
$("input[name='primary-button-select']").on("change", (e) => {
|
||||
if ($(e.target).attr("id") === "enable_primary_button") {
|
||||
if (current_banner.buttons.some((button) => button.type === "primary")) {
|
||||
return;
|
||||
}
|
||||
let label = $("#primary_button_text").val()?.toString();
|
||||
if (!label) {
|
||||
label = "Primary Button";
|
||||
}
|
||||
const is_icon_enabled = $("#enable_primary_button_icon").prop("checked") === true;
|
||||
current_banner.buttons.push({
|
||||
type: "primary",
|
||||
intent: current_banner.intent,
|
||||
label,
|
||||
icon: is_icon_enabled
|
||||
? $("#primary_button_select_icon").val()?.toString()
|
||||
: undefined,
|
||||
});
|
||||
$("#primary_button_text").val(label);
|
||||
} else {
|
||||
current_banner.buttons = current_banner.buttons.filter(
|
||||
(button) => button.type !== "primary",
|
||||
);
|
||||
}
|
||||
sortButtons(current_banner.buttons);
|
||||
$("#dev_navbar_alerts_wrapper").html(banner_html(current_banner));
|
||||
if (current_banner.process === "custom-banner") {
|
||||
custom_normal_banner.buttons = current_banner.buttons;
|
||||
$("#dev_normal_banner_wrapper").html(banner_html(custom_normal_banner));
|
||||
}
|
||||
});
|
||||
|
||||
$("input[name='primary-button-icon-select']").on("change", (e) => {
|
||||
const primary_button = current_banner.buttons.find((button) => button.type === "primary");
|
||||
if (primary_button === undefined) {
|
||||
return;
|
||||
}
|
||||
if ($(e.target).attr("id") === "enable_primary_button_icon") {
|
||||
primary_button.icon = $("#primary_button_select_icon").val()?.toString() ?? "";
|
||||
} else {
|
||||
delete primary_button.icon;
|
||||
}
|
||||
$("#dev_navbar_alerts_wrapper").html(banner_html(current_banner));
|
||||
if (current_banner.process === "custom-banner") {
|
||||
custom_normal_banner.buttons = current_banner.buttons;
|
||||
$("#dev_normal_banner_wrapper").html(banner_html(custom_normal_banner));
|
||||
}
|
||||
});
|
||||
|
||||
$("#primary_button_select_icon").on("change", function (this: HTMLElement) {
|
||||
const primary_button = current_banner.buttons.find((button) => button.type === "primary");
|
||||
if (primary_button === undefined) {
|
||||
return;
|
||||
}
|
||||
if (!primary_button.icon) {
|
||||
return;
|
||||
}
|
||||
primary_button.icon = $(this).val()?.toString() ?? "";
|
||||
$("#dev_navbar_alerts_wrapper").html(banner_html(current_banner));
|
||||
if (current_banner.process === "custom-banner") {
|
||||
custom_normal_banner.buttons = current_banner.buttons;
|
||||
$("#dev_normal_banner_wrapper").html(banner_html(custom_normal_banner));
|
||||
}
|
||||
});
|
||||
|
||||
$("#primary_button_text").on("input", function (this: HTMLElement) {
|
||||
const primary_button = current_banner.buttons.find((button) => button.type === "primary");
|
||||
if (primary_button === undefined) {
|
||||
return;
|
||||
}
|
||||
primary_button.label = $(this).val()?.toString() ?? "";
|
||||
$("#dev_navbar_alerts_wrapper").html(banner_html(current_banner));
|
||||
if (current_banner.process === "custom-banner") {
|
||||
custom_normal_banner.buttons = current_banner.buttons;
|
||||
$("#dev_normal_banner_wrapper").html(banner_html(custom_normal_banner));
|
||||
}
|
||||
});
|
||||
|
||||
$("input[name='quiet-button-select']").on("change", (e) => {
|
||||
if ($(e.target).attr("id") === "enable_quiet_button") {
|
||||
if (current_banner.buttons.some((button) => button.type === "quiet")) {
|
||||
return;
|
||||
}
|
||||
let label = $("#quiet_button_text").val()?.toString();
|
||||
if (!label) {
|
||||
label = "Quiet Button";
|
||||
}
|
||||
const is_icon_enabled = $("#enable_quiet_button_icon").prop("checked") === true;
|
||||
current_banner.buttons.push({
|
||||
type: "quiet",
|
||||
intent: current_banner.intent,
|
||||
label,
|
||||
icon: is_icon_enabled
|
||||
? $("#quiet_button_select_icon").val()?.toString()
|
||||
: undefined,
|
||||
});
|
||||
$("#quiet_button_text").val(label);
|
||||
sortButtons(current_banner.buttons);
|
||||
} else {
|
||||
current_banner.buttons = current_banner.buttons.filter(
|
||||
(button) => button.type !== "quiet",
|
||||
);
|
||||
}
|
||||
$("#dev_navbar_alerts_wrapper").html(banner_html(current_banner));
|
||||
if (current_banner.process === "custom-banner") {
|
||||
custom_normal_banner.buttons = current_banner.buttons;
|
||||
$("#dev_normal_banner_wrapper").html(banner_html(custom_normal_banner));
|
||||
}
|
||||
});
|
||||
|
||||
$("input[name='quiet-button-icon-select']").on("change", (e) => {
|
||||
const quiet_button = current_banner.buttons.find((button) => button.type === "quiet");
|
||||
if (quiet_button === undefined) {
|
||||
return;
|
||||
}
|
||||
if ($(e.target).attr("id") === "enable_quiet_button_icon") {
|
||||
quiet_button.icon = $("#quiet_button_select_icon").val()?.toString() ?? "";
|
||||
} else {
|
||||
delete quiet_button.icon;
|
||||
}
|
||||
$("#dev_navbar_alerts_wrapper").html(banner_html(current_banner));
|
||||
if (current_banner.process === "custom-banner") {
|
||||
custom_normal_banner.buttons = current_banner.buttons;
|
||||
$("#dev_normal_banner_wrapper").html(banner_html(custom_normal_banner));
|
||||
}
|
||||
});
|
||||
|
||||
$("#quiet_button_select_icon").on("change", function (this: HTMLElement) {
|
||||
const quiet_button = current_banner.buttons.find((button) => button.type === "quiet");
|
||||
if (quiet_button === undefined) {
|
||||
return;
|
||||
}
|
||||
if (!quiet_button.icon) {
|
||||
return;
|
||||
}
|
||||
quiet_button.icon = $(this).val()?.toString() ?? "";
|
||||
$("#dev_navbar_alerts_wrapper").html(banner_html(current_banner));
|
||||
if (current_banner.process === "custom-banner") {
|
||||
custom_normal_banner.buttons = current_banner.buttons;
|
||||
$("#dev_normal_banner_wrapper").html(banner_html(custom_normal_banner));
|
||||
}
|
||||
});
|
||||
|
||||
$("#quiet_button_text").on("input", function (this: HTMLElement) {
|
||||
const quiet_button = current_banner.buttons.find((button) => button.type === "quiet");
|
||||
if (quiet_button === undefined) {
|
||||
return;
|
||||
}
|
||||
quiet_button.label = $(this).val()?.toString() ?? "";
|
||||
$("#dev_navbar_alerts_wrapper").html(banner_html(current_banner));
|
||||
if (current_banner.process === "custom-banner") {
|
||||
custom_normal_banner.buttons = current_banner.buttons;
|
||||
$("#dev_normal_banner_wrapper").html(banner_html(custom_normal_banner));
|
||||
}
|
||||
});
|
||||
|
||||
$("input[name='borderless-button-select']").on("change", function (this: HTMLElement) {
|
||||
if ($(this).attr("id") === "enable_borderless_button") {
|
||||
if (current_banner.buttons.some((button) => button.type === "borderless")) {
|
||||
return;
|
||||
}
|
||||
let label = $("#borderless_button_text").val()?.toString();
|
||||
if (!label) {
|
||||
label = "Borderless Button";
|
||||
}
|
||||
const is_icon_enabled = $("#enable_borderless_button_icon").prop("checked") === true;
|
||||
current_banner.buttons.push({
|
||||
type: "borderless",
|
||||
intent: current_banner.intent,
|
||||
label,
|
||||
icon: is_icon_enabled
|
||||
? $("#borderless_button_select_icon").val()?.toString()
|
||||
: undefined,
|
||||
});
|
||||
$("#borderless_button_text").val(label);
|
||||
sortButtons(current_banner.buttons);
|
||||
} else {
|
||||
current_banner.buttons = current_banner.buttons.filter(
|
||||
(button) => button.type !== "borderless",
|
||||
);
|
||||
}
|
||||
$("#dev_navbar_alerts_wrapper").html(banner_html(current_banner));
|
||||
if (current_banner.process === "custom-banner") {
|
||||
custom_normal_banner.buttons = current_banner.buttons;
|
||||
$("#dev_normal_banner_wrapper").html(banner_html(custom_normal_banner));
|
||||
}
|
||||
});
|
||||
|
||||
$("input[name='borderless-button-icon-select']").on("change", function (this: HTMLElement) {
|
||||
const borderless_button = current_banner.buttons.find(
|
||||
(button) => button.type === "borderless",
|
||||
);
|
||||
if (borderless_button === undefined) {
|
||||
return;
|
||||
}
|
||||
if ($(this).attr("id") === "enable_borderless_button_icon") {
|
||||
borderless_button.icon = $("#borderless_button_select_icon").val()?.toString() ?? "";
|
||||
} else {
|
||||
delete borderless_button.icon;
|
||||
}
|
||||
$("#dev_navbar_alerts_wrapper").html(banner_html(current_banner));
|
||||
if (current_banner.process === "custom-banner") {
|
||||
custom_normal_banner.buttons = current_banner.buttons;
|
||||
$("#dev_normal_banner_wrapper").html(banner_html(custom_normal_banner));
|
||||
}
|
||||
});
|
||||
|
||||
$("#borderless_button_select_icon").on("change", function (this: HTMLElement) {
|
||||
const borderless_button = current_banner.buttons.find(
|
||||
(button) => button.type === "borderless",
|
||||
);
|
||||
if (borderless_button === undefined) {
|
||||
return;
|
||||
}
|
||||
if (!borderless_button.icon) {
|
||||
return;
|
||||
}
|
||||
borderless_button.icon = $(this).val()?.toString() ?? "";
|
||||
$("#dev_navbar_alerts_wrapper").html(banner_html(current_banner));
|
||||
if (current_banner.process === "custom-banner") {
|
||||
custom_normal_banner.buttons = current_banner.buttons;
|
||||
$("#dev_normal_banner_wrapper").html(banner_html(custom_normal_banner));
|
||||
}
|
||||
});
|
||||
|
||||
$("#borderless_button_text").on("input", function (this: HTMLElement) {
|
||||
const borderless_button = current_banner.buttons.find(
|
||||
(button) => button.type === "borderless",
|
||||
);
|
||||
if (borderless_button === undefined) {
|
||||
return;
|
||||
}
|
||||
borderless_button.label = $(this).val()?.toString() ?? "";
|
||||
$("#dev_navbar_alerts_wrapper").html(banner_html(current_banner));
|
||||
if (current_banner.process === "custom-banner") {
|
||||
custom_normal_banner.buttons = current_banner.buttons;
|
||||
$("#dev_normal_banner_wrapper").html(banner_html(custom_normal_banner));
|
||||
}
|
||||
});
|
||||
});
|
||||
|
@@ -591,6 +591,25 @@
|
||||
oklch(70% 0.3 0deg) 100%
|
||||
);
|
||||
|
||||
/* Banner grid layout variables */
|
||||
--banner-horizontal-padding: 13px;
|
||||
--banner-vertical-padding: 5px;
|
||||
--banner-grid-template-areas-lg: ". . . . . . banner-close-btn banner-close-btn"
|
||||
". . banner-label . banner-btns . banner-close-btn banner-close-btn"
|
||||
". . . . . . banner-close-btn banner-close-btn";
|
||||
--banner-grid-template-columns-lg: var(--banner-horizontal-padding) 0 auto
|
||||
minmax(0, 1fr) auto 0 minmax(0, auto) var(--banner-horizontal-padding);
|
||||
--banner-grid-template-rows-lg: 5px auto 5px;
|
||||
--banner-grid-template-areas-md: ". . . . banner-close-btn banner-close-btn"
|
||||
". . banner-label banner-label banner-close-btn banner-close-btn"
|
||||
". banner-btns banner-btns banner-btns . .";
|
||||
--banner-grid-template-columns-md: var(--banner-horizontal-padding) 0
|
||||
minmax(auto, 1fr) 0 minmax(0, auto) var(--banner-horizontal-padding);
|
||||
--banner-grid-template-rows-md: 5px auto auto 5px;
|
||||
--banner-grid-template-areas-sm: ". . . . banner-close-btn banner-close-btn"
|
||||
". . banner-label banner-label banner-close-btn banner-close-btn"
|
||||
". banner-btns banner-btns banner-btns banner-btns .";
|
||||
|
||||
/* Colors used across the app */
|
||||
--color-date: hsl(0deg 0% 15% / 75%);
|
||||
--color-background-private-message-header: hsl(46deg 35% 93%);
|
||||
@@ -1492,6 +1511,57 @@
|
||||
hsl(359deg 93% 39%) 13%,
|
||||
transparent
|
||||
);
|
||||
|
||||
/* Banners */
|
||||
--color-text-link-banner: hsl(210deg 94% 42%);
|
||||
/* Banners - Neutral Variant */
|
||||
--color-text-neutral-banner: hsl(229deg 12% 25%);
|
||||
--color-border-neutral-banner: color-mix(
|
||||
in oklch,
|
||||
hsl(240deg 2% 30%) 40%,
|
||||
transparent
|
||||
);
|
||||
--color-background-neutral-banner: hsl(240deg 7% 93%);
|
||||
/* Banners - Brand Variant */
|
||||
--color-text-brand-banner: hsl(264deg 95% 34%);
|
||||
--color-border-brand-banner: color-mix(
|
||||
in oklch,
|
||||
hsl(254deg 60% 50%) 40%,
|
||||
transparent
|
||||
);
|
||||
--color-background-brand-banner: hsl(254deg 42% 94%);
|
||||
/* Banners - Info Variant */
|
||||
--color-text-info-banner: hsl(241deg 95% 25%);
|
||||
--color-border-info-banner: color-mix(
|
||||
in oklch,
|
||||
hsl(204deg 49% 29%) 40%,
|
||||
transparent
|
||||
);
|
||||
--color-background-info-banner: hsl(204deg 58% 92%);
|
||||
/* Banners - Success Variant */
|
||||
--color-text-success-banner: hsl(144deg 88% 16%);
|
||||
--color-border-success-banner: color-mix(
|
||||
in oklch,
|
||||
hsl(147deg 57% 25%) 40%,
|
||||
transparent
|
||||
);
|
||||
--color-background-success-banner: hsl(147deg 43% 92%);
|
||||
/* Banners - Warning Variant */
|
||||
--color-text-warning-banner: hsl(34deg 89% 25%);
|
||||
--color-border-warning-banner: color-mix(
|
||||
in oklch,
|
||||
hsl(38deg 44% 27%) 40%,
|
||||
transparent
|
||||
);
|
||||
--color-background-warning-banner: hsl(50deg 75% 92%);
|
||||
/* Banners - Danger Variant */
|
||||
--color-text-danger-banner: hsl(359deg 94% 35%);
|
||||
--color-border-danger-banner: color-mix(
|
||||
in oklch,
|
||||
hsl(3deg 57% 33%) 40%,
|
||||
transparent
|
||||
);
|
||||
--color-background-danger-banner: hsl(0deg 35% 92%);
|
||||
}
|
||||
|
||||
%dark-theme {
|
||||
@@ -2414,6 +2484,56 @@
|
||||
hsl(5deg 88% 60%) 17%,
|
||||
transparent
|
||||
);
|
||||
|
||||
/* Banners */
|
||||
/* Banners - Neutral Variant */
|
||||
--color-text-neutral-banner: hsl(231deg 11% 76%);
|
||||
--color-border-neutral-banner: color-mix(
|
||||
in oklch,
|
||||
hsl(240deg 7% 66%) 40%,
|
||||
transparent
|
||||
);
|
||||
--color-background-neutral-banner: hsl(240deg 7% 17%);
|
||||
/* Banners - Brand Variant */
|
||||
--color-text-brand-banner: hsl(244deg 96% 82%);
|
||||
--color-border-brand-banner: color-mix(
|
||||
in oklch,
|
||||
hsl(253deg 70% 89%) 40%,
|
||||
transparent
|
||||
);
|
||||
--color-background-brand-banner: hsl(254deg 49% 16%);
|
||||
/* Banners - Info Variant */
|
||||
--color-text-info-banner: hsl(221deg 93% 89%);
|
||||
--color-border-info-banner: color-mix(
|
||||
in oklch,
|
||||
hsl(205deg 58% 69%) 40%,
|
||||
transparent
|
||||
);
|
||||
--color-background-info-banner: hsl(204deg 100% 12%);
|
||||
/* Banners - Success Variant */
|
||||
--color-text-success-banner: hsl(135deg 56% 63%);
|
||||
--color-border-success-banner: color-mix(
|
||||
in oklch,
|
||||
hsl(149deg 48% 52%) 40%,
|
||||
transparent
|
||||
);
|
||||
--color-background-success-banner: hsl(146deg 90% 7%);
|
||||
/* Banners - Warning Variant */
|
||||
--color-text-warning-banner: hsl(40deg 94% 56%);
|
||||
--color-border-warning-banner: color-mix(
|
||||
in oklch,
|
||||
hsl(44deg 44% 66%) 40%,
|
||||
transparent
|
||||
);
|
||||
--color-background-warning-banner: hsl(50deg 100% 10%);
|
||||
/* Banners - Danger Variant */
|
||||
--color-text-danger-banner: hsl(7deg 100% 74%);
|
||||
--color-border-danger-banner: color-mix(
|
||||
in oklch,
|
||||
hsl(3deg 73% 74%) 40%,
|
||||
transparent
|
||||
);
|
||||
--color-background-danger-banner: hsl(0deg 52% 18%);
|
||||
}
|
||||
|
||||
@media screen {
|
||||
|
131
web/styles/banners.css
Normal file
131
web/styles/banners.css
Normal file
@@ -0,0 +1,131 @@
|
||||
.banner-wrapper {
|
||||
container: banner / inline-size;
|
||||
}
|
||||
|
||||
.banner {
|
||||
box-sizing: border-box;
|
||||
display: grid;
|
||||
grid-template: var(--banner-grid-template-rows-lg) / var(
|
||||
--banner-grid-template-columns-lg
|
||||
);
|
||||
grid-template-areas: var(--banner-grid-template-areas-lg);
|
||||
place-items: start;
|
||||
font-size: 0.9375em;
|
||||
border: 1px solid;
|
||||
border-radius: 6px;
|
||||
}
|
||||
|
||||
.banner__link {
|
||||
color: var(--color-text-link-banner);
|
||||
}
|
||||
|
||||
.banner-label {
|
||||
grid-area: banner-label;
|
||||
padding: 0.3333em 0 0.2667em;
|
||||
line-height: 1.2667;
|
||||
}
|
||||
|
||||
.banner-action-buttons {
|
||||
grid-area: banner-btns;
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
margin-left: 6px;
|
||||
}
|
||||
|
||||
.banner-close-button {
|
||||
display: flex;
|
||||
grid-area: banner-close-btn;
|
||||
padding: 0.6875em;
|
||||
margin-left: 5px;
|
||||
}
|
||||
|
||||
.navbar-alert-banner {
|
||||
grid-template-columns:
|
||||
var(--banner-horizontal-padding) minmax(0, 1fr)
|
||||
auto 0 auto minmax(0, 1fr) minmax(0, auto) var(
|
||||
--banner-horizontal-padding
|
||||
);
|
||||
border: unset;
|
||||
border-bottom: 1px solid;
|
||||
border-radius: 0;
|
||||
place-items: start center;
|
||||
}
|
||||
|
||||
.navbar-alert-banner .banner-action-buttons {
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
@container (width >= 44em) and (width < 63em) {
|
||||
.navbar-alert-banner[data-process="notifications"] {
|
||||
grid-template: var(--banner-grid-template-rows-md) / var(
|
||||
--banner-grid-template-columns-md
|
||||
);
|
||||
grid-template-areas: var(--banner-grid-template-areas-md);
|
||||
text-align: center;
|
||||
}
|
||||
}
|
||||
|
||||
@container (width < 44em) {
|
||||
.banner {
|
||||
grid-template: var(--banner-grid-template-rows-md) / var(
|
||||
--banner-grid-template-columns-md
|
||||
);
|
||||
grid-template-areas: var(--banner-grid-template-areas-md);
|
||||
}
|
||||
|
||||
.banner-action-buttons {
|
||||
flex-wrap: wrap;
|
||||
margin-left: 0;
|
||||
}
|
||||
|
||||
.navbar-alert-banner {
|
||||
text-align: center;
|
||||
}
|
||||
}
|
||||
|
||||
@container (width < 25em) {
|
||||
.banner {
|
||||
grid-template-areas: var(--banner-grid-template-areas-sm);
|
||||
}
|
||||
|
||||
.banner-action-buttons {
|
||||
flex-direction: column;
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.banner-neutral {
|
||||
background-color: var(--color-background-neutral-banner);
|
||||
color: var(--color-text-neutral-banner);
|
||||
border-color: var(--color-border-neutral-banner);
|
||||
}
|
||||
|
||||
.banner-brand {
|
||||
background-color: var(--color-background-brand-banner);
|
||||
color: var(--color-text-brand-banner);
|
||||
border-color: var(--color-border-brand-banner);
|
||||
}
|
||||
|
||||
.banner-info {
|
||||
background-color: var(--color-background-info-banner);
|
||||
color: var(--color-text-info-banner);
|
||||
border-color: var(--color-border-info-banner);
|
||||
}
|
||||
|
||||
.banner-success {
|
||||
background-color: var(--color-background-success-banner);
|
||||
color: var(--color-text-success-banner);
|
||||
border-color: var(--color-border-success-banner);
|
||||
}
|
||||
|
||||
.banner-warning {
|
||||
background-color: var(--color-background-warning-banner);
|
||||
color: var(--color-text-warning-banner);
|
||||
border-color: var(--color-border-warning-banner);
|
||||
}
|
||||
|
||||
.banner-danger {
|
||||
background-color: var(--color-background-danger-banner);
|
||||
color: var(--color-text-danger-banner);
|
||||
border-color: var(--color-border-danger-banner);
|
||||
}
|
@@ -21,30 +21,27 @@ body {
|
||||
display: flex;
|
||||
flex-flow: column;
|
||||
gap: 20px;
|
||||
padding-bottom: 20px;
|
||||
padding: 40px 20px;
|
||||
}
|
||||
|
||||
.design-testing-title {
|
||||
font-size: 2em;
|
||||
text-align: center;
|
||||
padding: 20px 0;
|
||||
}
|
||||
|
||||
.action-button-section {
|
||||
display: flex;
|
||||
flex-flow: column;
|
||||
gap: 5px;
|
||||
.design-controls-section {
|
||||
display: grid;
|
||||
grid-template-columns: [control-name-start] max-content [control-name-end control-input-start] 1fr [control-input-end];
|
||||
gap: 10px;
|
||||
margin-top: 50px;
|
||||
width: min(100%, 500px);
|
||||
}
|
||||
|
||||
.design-testing-controls {
|
||||
display: grid;
|
||||
grid-template-columns: [control-name-start] max-content [control-name-end control-input-start] min-content [control-input-end];
|
||||
grid-template-columns: subgrid;
|
||||
grid-column: control-name-start / control-input-end;
|
||||
grid-auto-rows: 1fr;
|
||||
gap: 10px;
|
||||
background-color: var(--color-background);
|
||||
border: solid 1px;
|
||||
padding: 10px;
|
||||
width: fit-content;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.design-testing-control {
|
||||
@@ -79,7 +76,9 @@ body {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
.section-heading {
|
||||
.design-testing-controls-label {
|
||||
grid-column: control-name-start / control-input-end;
|
||||
margin-top: 10px;
|
||||
font-size: 1.4em;
|
||||
font-weight: 600;
|
||||
}
|
||||
@@ -125,3 +124,12 @@ body {
|
||||
font-size: 1.1em;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
#banner_select_intent {
|
||||
text-transform: capitalize;
|
||||
}
|
||||
|
||||
#dev_normal_banner_wrapper {
|
||||
width: min(100%, 800px);
|
||||
margin: 0 auto;
|
||||
}
|
6
web/templates/components/action-button.hbs
Normal file
6
web/templates/components/action-button.hbs
Normal file
@@ -0,0 +1,6 @@
|
||||
<button class="{{#if custom_classes}}{{custom_classes}} {{/if}}action-button action-button-{{type}}-{{intent}}" tabindex="0">
|
||||
{{#if icon}}
|
||||
<i class="zulip-icon zulip-icon-{{icon}}"></i>
|
||||
{{/if}}
|
||||
<span class="action-button-label">{{label}}</span>
|
||||
</button>
|
13
web/templates/components/banner.hbs
Normal file
13
web/templates/components/banner.hbs
Normal file
@@ -0,0 +1,13 @@
|
||||
<div {{#if process}}data-process="{{process}}"{{/if}} class="{{#if custom_classes}}{{custom_classes}} {{/if}}banner banner-{{intent}}">
|
||||
<span class="banner-label">
|
||||
{{label}}
|
||||
</span>
|
||||
<span class="banner-action-buttons">
|
||||
{{#each buttons}}
|
||||
{{> action-button .}}
|
||||
{{/each}}
|
||||
</span>
|
||||
{{#if close_button}}
|
||||
{{> icon-button custom_classes="banner-close-button" icon="close" intent=intent}}
|
||||
{{/if}}
|
||||
</div>
|
3
web/templates/components/icon-button.hbs
Normal file
3
web/templates/components/icon-button.hbs
Normal file
@@ -0,0 +1,3 @@
|
||||
<button class="{{#if custom_classes}}{{custom_classes}} {{/if}}icon-button icon-button-{{intent}}" tabindex="0">
|
||||
<i class="zulip-icon zulip-icon-{{icon}}"></i>
|
||||
</button>
|
@@ -15,12 +15,5 @@
|
||||
"./src/reload_state.ts",
|
||||
"./src/channel.ts"
|
||||
],
|
||||
"dev-buttons": [
|
||||
"./src/bundles/portico.ts",
|
||||
"./src/portico/design-testing.ts",
|
||||
"./styles/app_variables.css",
|
||||
"./styles/portico/dev-buttons.css",
|
||||
"./styles/buttons.css",
|
||||
"./styles/app_components.css"
|
||||
]
|
||||
"dev-testing": ["./src/bundles/design-testing.ts"]
|
||||
}
|
||||
|
@@ -59,6 +59,7 @@ class PublicURLTest(ZulipTestCase):
|
||||
def test_design_testing_pages(self) -> None:
|
||||
urls = {
|
||||
"/devtools/buttons/": "Button styles browser",
|
||||
"/devtools/banners/": "Banner styles browser",
|
||||
}
|
||||
|
||||
for url, expected_content in urls.items():
|
||||
|
@@ -28,7 +28,23 @@ def dev_buttons_design_testing(request: HttpRequest) -> HttpResponse:
|
||||
context = {
|
||||
"background_colors": background_colors,
|
||||
"icons": get_svg_filenames(),
|
||||
"page_is_design_testing": True,
|
||||
"design_component": "buttons",
|
||||
"doc_root_title": "Button styles browser",
|
||||
# We set isolated_page to avoid clutter from footer/header.
|
||||
"isolated_page": True,
|
||||
}
|
||||
return render(request, "zerver/development/design_testing/buttons.html", context)
|
||||
|
||||
|
||||
def dev_banners_design_testing(request: HttpRequest) -> HttpResponse:
|
||||
context = {
|
||||
"background_colors": background_colors,
|
||||
"icons": get_svg_filenames(),
|
||||
"page_is_design_testing": True,
|
||||
"design_component": "banners",
|
||||
"doc_root_title": "Banner styles browser",
|
||||
# We set isolated_page to avoid clutter from footer/header.
|
||||
"isolated_page": True,
|
||||
}
|
||||
return render(request, "zerver/development/design_testing/banners.html", context)
|
||||
|
@@ -13,7 +13,10 @@ from django.views.static import serve
|
||||
from zerver.views.auth import login_page
|
||||
from zerver.views.development.cache import remove_caches
|
||||
from zerver.views.development.camo import handle_camo_url
|
||||
from zerver.views.development.design_testing import dev_buttons_design_testing
|
||||
from zerver.views.development.design_testing import (
|
||||
dev_banners_design_testing,
|
||||
dev_buttons_design_testing,
|
||||
)
|
||||
from zerver.views.development.dev_login import (
|
||||
api_dev_fetch_api_key,
|
||||
api_dev_list_users,
|
||||
@@ -100,6 +103,7 @@ urls = [
|
||||
path("external_content/<digest>/<received_url>", handle_camo_url),
|
||||
# Endpoints for design testing.
|
||||
path("devtools/buttons/", dev_buttons_design_testing),
|
||||
path("devtools/banners/", dev_banners_design_testing),
|
||||
]
|
||||
|
||||
v1_api_mobile_patterns = [
|
||||
|
Reference in New Issue
Block a user