diff --git a/assets/brand/moonbot-logo.svg b/assets/brand/moonbot-logo.svg deleted file mode 100644 index 151dc60b..00000000 --- a/assets/brand/moonbot-logo.svg +++ /dev/null @@ -1,19 +0,0 @@ - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/assets/brand/moonterminal-logo-blue-dark.svg b/assets/brand/moonterminal-logo-blue-dark.svg new file mode 100644 index 00000000..d375f93c --- /dev/null +++ b/assets/brand/moonterminal-logo-blue-dark.svg @@ -0,0 +1,9 @@ + + MoonTerminal + + + + + + + diff --git a/assets/brand/moonterminal-logo-blue-light.svg b/assets/brand/moonterminal-logo-blue-light.svg new file mode 100644 index 00000000..190ecff1 --- /dev/null +++ b/assets/brand/moonterminal-logo-blue-light.svg @@ -0,0 +1,9 @@ + + MoonTerminal + + + + + + + diff --git a/crates/moon-ui-gpui/src/chart_tabs/add_stack.rs b/crates/moon-ui-gpui/src/chart_tabs/add_stack.rs index a37ca888..3bbf8040 100644 --- a/crates/moon-ui-gpui/src/chart_tabs/add_stack.rs +++ b/crates/moon-ui-gpui/src/chart_tabs/add_stack.rs @@ -1130,7 +1130,10 @@ impl Render for AddChartStack { .flex() .items_center() .justify_center() - .child(crate::design::logo_glow_sized(cx, 220.0)) + .child(crate::design::logo_glow_sized( + cx, + crate::design::EMPTY_STACK_LOGO_W, + )) .into_any_element(); // Measured here too: a window resized while the tab holds no charts would otherwise // leave a stale size behind, and the first frame WITH charts would divide by it. diff --git a/crates/moon-ui-gpui/src/chart_tabs/main_stack.rs b/crates/moon-ui-gpui/src/chart_tabs/main_stack.rs index fcd88f31..2645db64 100644 --- a/crates/moon-ui-gpui/src/chart_tabs/main_stack.rs +++ b/crates/moon-ui-gpui/src/chart_tabs/main_stack.rs @@ -1621,7 +1621,10 @@ impl Render for MainChartStack { .flex() .items_center() .justify_center() - .child(crate::design::logo_glow_sized(cx, 220.0)) + .child(crate::design::logo_glow_sized( + cx, + crate::design::EMPTY_STACK_LOGO_W, + )) .into_any_element(); // Measured here too, for the reason the fullscreen branch keeps its probe: a resize // taken while the stack is empty must not leave a size the first divided frame uses. diff --git a/crates/moon-ui-gpui/src/chrome/terminal_chrome.rs b/crates/moon-ui-gpui/src/chrome/terminal_chrome.rs index 2c41b416..8515898d 100644 --- a/crates/moon-ui-gpui/src/chrome/terminal_chrome.rs +++ b/crates/moon-ui-gpui/src/chrome/terminal_chrome.rs @@ -9,7 +9,7 @@ use gpui::*; use moon_ui::{ MoonButton, MoonButtonIconSlot, MoonButtonSize, MoonButtonVariant, MoonDropdown, MoonMenuItem, MoonMenuSize, MoonPalette, MoonPopover, MoonPopoverPlacement, MoonPopupMenu, MoonRect, - MoonSelectorPill, MoonSelectorSegment, MoonTag, MoonWindowFrame, MoonWindowFrameBrand, h_flex, + MoonSelectorPill, MoonSelectorSegment, MoonTag, MoonWindowFrame, h_flex, }; use rust_i18n::t; @@ -136,19 +136,29 @@ pub fn header( // internally, so the seams line up. .gap(design::ui_px(cx, design::CHROME_GAP)) .bg(rgb(p.shell_high)) - // Brand draws its OWN trailing separator (MoonWindowFrame::brand_cluster), so the - // groups below add only the seams after them. It is also the FIRST thing this row gives - // up on a narrow window (`design::header_brand_visible`): dropping the mark to `None` - // keeps the drag region and takes the rule with it, so the space goes to the readouts - // that carry information instead. + // The brand carries its OWN trailing separator, so the groups below add only the seams + // after them. It is also the FIRST thing this row gives up on a narrow window + // (`design::header_brand_visible`): dropping the mark keeps the drag region and takes the + // rule with it, so the space goes to the readouts that carry information instead. + // + // The cluster is assembled here rather than through `MoonWindowFrame::brand_cluster`, + // which draws MoonUI's own Moonbot lockup: the terminal ships the MoonTerminal one from + // `assets/brand`. Only the drag handle comes from the frame — that region is what makes + // the titlebar grabbable, and `brand_cluster` is nothing more than that handle plus the + // two children added below, at the same `CHROME_GAP` and the same rule height. The rule + // itself is `chrome_divider`, not MoonUI's fainter `border` copy of it: owning the cluster + // means this seam answers to the same contrast rule as every other seam in the row. .child( MoonWindowFrame::main("terminal-header-brand-drag", 0.0) - .brand(if design::header_brand_visible(cx, chrome_width) { - MoonWindowFrameBrand::Default - } else { - MoonWindowFrameBrand::None + .drag_handle() + .flex() + .items_center() + .gap(design::ui_px(cx, design::CHROME_GAP)) + .when(design::header_brand_visible(cx, chrome_width), |cluster| { + cluster + .child(design::header_logo(cx)) + .child(design::chrome_divider(cx, p)) }) - .brand_cluster(cx) .flex_none() .h_full(), ) diff --git a/crates/moon-ui-gpui/src/design.rs b/crates/moon-ui-gpui/src/design.rs index f2cdadd9..99b092fa 100644 --- a/crates/moon-ui-gpui/src/design.rs +++ b/crates/moon-ui-gpui/src/design.rs @@ -7,7 +7,7 @@ use gpui::*; use moon_core::util::fmt::DeltaSign; use moon_ui::{MoonMetrics, MoonPalette, MoonTheme, MoonTone, rgba_from}; use std::collections::HashMap; -use std::sync::Arc; +use std::sync::{Arc, LazyLock}; const M: MoonMetrics = MoonMetrics::TERMINAL; @@ -191,6 +191,11 @@ pub const HEADER_LABEL_MAX_W: f32 = 260.0; /// readouts would disappear at the same width and the priority above would be a comment rather /// than a behaviour. Usable only because [`HEADER_LABEL_MAX_W`] bounds the clusters that would /// otherwise grow without limit. +/// +/// These are TUNED window widths, not values derived from what the row holds, so the brand's own +/// width does not enter them: the MoonTerminal lockup is 36px wider than the Moonbot one these +/// were set against, and the `flex_1` drag spacer absorbs the difference. Re-tune them by looking +/// at the row, not by arithmetic on the mark. const HEADER_BRAND_MIN_W: f32 = 1400.0; const TICKER_DELTAS_MIN_W: f32 = 1200.0; const TICKER_MIN_W: f32 = 1000.0; @@ -252,11 +257,52 @@ pub fn platform_window_decorations() -> Option { } } -const LOGO_GLOW_SVG_RAW: &str = include_str!("../../../assets/brand/moonbot-logo.svg"); -const LOGO_SRC_W: f32 = 199.0; +/// The MoonTerminal lockup, one cut per colour scheme. +/// +/// Each file already carries its own wordmark colour — `#E7E7E7` in the dark cut, `#17202A` in the +/// light one, with the blue "Terminal" shared — so the terminal PICKS a file instead of patching a +/// fill the way the old single-cut Moonbot asset needed. A custom palette therefore no longer +/// recolours the brand, which is the point of a brand asset. +const LOGO_SVG_DARK: &str = include_str!("../../../assets/brand/moonterminal-logo-blue-dark.svg"); +const LOGO_SVG_LIGHT: &str = include_str!("../../../assets/brand/moonterminal-logo-blue-light.svg"); +const LOGO_SRC_W: f32 = 283.23; const LOGO_SRC_H: f32 = 43.0; -const LOGO_GLOW_VIEW_W: f32 = LOGO_SRC_W * 1.2; -const LOGO_GLOW_VIEW_H: f32 = LOGO_SRC_W * 1.2; +/// Factor carrying every lockup size across the brand swap, from the 199px-wide Moonbot mark the +/// sizes below were tuned against to the 283.23px-wide MoonTerminal one. +/// +/// The port keeps the ICON's drawn size rather than the box it sat in: only the wordmark got +/// longer, and holding a width tuned for the shorter mark would shrink the whole lockup by a third +/// and read as a different, smaller logo. Spelling the factor ONCE is the load-bearing part — +/// these five sizes live in two files, and hand-multiplying each one is how four of them stay +/// right while the fifth quietly does not. +const LOGO_PORT_SCALE: f32 = LOGO_SRC_W / 199.0; + +/// Width of the placeholder lockup a chart stack draws while it holds no charts. +pub const EMPTY_STACK_LOGO_W: f32 = 220.0 * LOGO_PORT_SCALE; + +/// Share of a chart slot's width the same placeholder covers, bounded by [`CHART_LOGO_MIN_W`] and +/// [`CHART_LOGO_MAX_W`] — a floor so it stays legible in a small pane, a ceiling so it stays a +/// watermark in a large one. +/// +/// The floor is ported like everything else: leaving it where it was would have kept exactly the +/// small panes — the ones that need it — drawing an icon a third smaller than before. It buys that +/// at the far end: a pane narrower than the floor itself now clips the LOCKUP, where the shorter +/// mark still fitted. That pane is under 256 logical px wide — narrower than the placeholder it +/// would be showing — and between there and 643 px, where the share takes over, the floor is what +/// keeps the icon at its designed size. The glow frame is [`LOGO_GLOW_SCALE`] times these widths +/// and overhangs sooner, which costs nothing visible: its aura reaches zero opacity at that edge. +pub const CHART_LOGO_SLOT_SHARE: f32 = 0.28 * LOGO_PORT_SCALE; +pub const CHART_LOGO_MIN_W: f32 = 180.0 * LOGO_PORT_SCALE; +pub const CHART_LOGO_MAX_W: f32 = 280.0 * LOGO_PORT_SCALE; + +/// Header lockup width: the header strip is height-constrained, so the longer wordmark has to buy +/// its room in width, or the mark shrinks inside a row whose height cannot follow it. +const HEADER_LOGO_W: f32 = 86.0 * LOGO_PORT_SCALE; + +/// How much wider than the lockup the glow canvas is; the aura fills the difference. +const LOGO_GLOW_SCALE: f32 = 1.2; +/// The glow canvas is SQUARE, so the aura reads as a disc rather than a flat ellipse. +const LOGO_GLOW_VIEW: f32 = LOGO_SRC_W * LOGO_GLOW_SCALE; pub fn solid(hex: u32) -> Rgba { rgb(hex) @@ -1056,32 +1102,72 @@ pub fn r_container(cx: &App) -> Pixels { ui_px(cx, R_CONTAINER_BASE) } -/// Brand-book navy for the Moonbot wordmark in the light theme. +/// Return the lockup cut that belongs to a colour scheme. /// -/// Navy lacks contrast in the dark theme, where the wordmark uses `p.text` instead. -const LOGO_WORDMARK_NAVY: u32 = 0x0C2C4A; +/// Each file carries its own wordmark colour, so the scheme picks a FILE; nothing recolours the +/// brand at runtime, and a custom palette therefore cannot repaint it. +fn logo_svg(light: bool) -> &'static str { + if light { LOGO_SVG_LIGHT } else { LOGO_SVG_DARK } +} -pub fn logo_glow_sized(cx: &App, width: f32) -> impl IntoElement { - let p = MoonPalette::active(cx); - let text = if p.is_light() { - LOGO_WORDMARK_NAVY - } else { - p.text - }; - let text_fill = format!("#{text:06X}"); - let logo = - LOGO_GLOW_SVG_RAW.replace(r##"fill="#E7E7E7""##, &format!(r##"fill="{text_fill}""##)); - let paths = logo - .split_once(r#""#) - .and_then(|(_, rest)| rest.split_once("")) - .map(|(paths, _)| paths) - .unwrap_or(""); - let cx = LOGO_GLOW_VIEW_W * 0.5; - let cy = LOGO_GLOW_VIEW_H * 0.5; - let r = LOGO_GLOW_VIEW_W * 0.5; - let logo_x = (LOGO_GLOW_VIEW_W - LOGO_SRC_W) * 0.5; - let logo_y = (LOGO_GLOW_VIEW_H - LOGO_SRC_H) * 0.5; - let (aura_0_color, aura_1_color, aura_2_color, aura_0, aura_1, aura_2) = if p.is_light() { +/// Return everything the lockup's root `` wraps, for embedding in a composed document. +/// +/// The cut is the root tag itself, not the first ``: an export is free to wrap its paths in +/// a `` or to declare a ``/`` ahead of them, and starting at the first path +/// would drop those opening tags while keeping their closing ones — unbalanced markup usvg rejects +/// outright, which paints NOTHING and looks exactly like a decode failure. Whatever the file +/// carries travels as-is; a `` among it is inert inside a rasterized document. +/// +/// Returns an empty string if the file has no root tag to cut at, which the asset test catches. +fn logo_paths(svg: &str) -> &str { + svg.split_once("')) + .and_then(|(_, inner)| inner.rsplit_once("")) + .map_or("", |(inner, _)| inner) +} + +/// Wrap SVG source in the GPUI image every element builder here takes. +fn svg_image(svg: impl Into>) -> Arc { + Arc::new(Image::from_bytes(ImageFormat::Svg, svg.into())) +} + +/// The brand cuts as decoded images, indexed by `is_light()`. +/// +/// Built once because there are only ever two of them. GPUI keys its raster cache on a hash of the +/// bytes, so consecutive frames already shared one texture; what repeated per frame was the 6.9KB +/// copy and the hash upstream of that cache, inside the header's own render. +static LOGO_IMAGES: LazyLock<[Arc; 2]> = + LazyLock::new(|| [svg_image(logo_svg(false)), svg_image(logo_svg(true))]); + +/// The composed glow documents, indexed by `is_light()`. +/// +/// Two, for the reason [`LOGO_IMAGES`] gives: the colour scheme is the document's ONLY input. The +/// caller's `width` never enters it — that sizes the element afterwards — so re-composing this +/// ~7.5KB string per empty pane per frame produced the same two documents forever. +static GLOW_IMAGES: LazyLock<[Arc; 2]> = + LazyLock::new(|| [svg_image(glow_svg(false)), svg_image(glow_svg(true))]); + +/// The header lockup: the brand at the left end of the main window's titlebar. +/// +/// Sized off [`HEADER_LOGO_W`] through `ui()` — the UI-scale track MoonUI's own brand used — so the +/// mark follows the interface scale but NOT the font slider, matching the separator beside it. +/// +/// The asset is decoded whole, unlike in [`glow_svg`], which has to splice it into a document of +/// its own: here the file IS the document, so there is nothing to rewrite. +pub fn header_logo(cx: &App) -> impl IntoElement { + let width = ui_value(cx, HEADER_LOGO_W); + img(LOGO_IMAGES[usize::from(MoonPalette::active(cx).is_light())].clone()) + .w(px(width)) + .h(px(width * (LOGO_SRC_H / LOGO_SRC_W))) +} + +/// Compose the glow document for one colour scheme: the aura disc with the lockup centred on it. +fn glow_svg(light: bool) -> String { + let paths = logo_paths(logo_svg(light)); + let centre = LOGO_GLOW_VIEW * 0.5; + let logo_x = (LOGO_GLOW_VIEW - LOGO_SRC_W) * 0.5; + let logo_y = (LOGO_GLOW_VIEW - LOGO_SRC_H) * 0.5; + let (aura_0_color, aura_1_color, aura_2_color, aura_0, aura_1, aura_2) = if light { ( "#BFF5C9", "#AEEFC1", @@ -1093,41 +1179,33 @@ pub fn logo_glow_sized(cx: &App, width: f32) -> impl IntoElement { } else { ("#00BCFF", "#1A76FF", "#0A5CFF", 0.30, 0.19, 0.07) }; - let svg = format!( - r##" + format!( + r##" - + - + {paths} "##, - view_w = LOGO_GLOW_VIEW_W, - view_h = LOGO_GLOW_VIEW_H, - cx = cx, - cy = cy, - r = r, - logo_x = logo_x, - logo_y = logo_y, - aura_0_color = aura_0_color, - aura_1_color = aura_1_color, - aura_2_color = aura_2_color, - aura_0 = aura_0, - aura_1 = aura_1, - aura_2 = aura_2, - paths = paths, - ); - let frame_w = width * (LOGO_GLOW_VIEW_W / 199.0); - img(Arc::new(Image::from_bytes( - ImageFormat::Svg, - svg.into_bytes(), - ))) - .w(px(frame_w)) - .h(px(frame_w * (LOGO_GLOW_VIEW_H / LOGO_GLOW_VIEW_W))) + view = LOGO_GLOW_VIEW, + ) +} + +/// The glowing placeholder an empty chart surface draws; `width` is the lockup's own width. +/// +/// The element is the square glow canvas around it, hence the [`LOGO_GLOW_SCALE`] factor: taking +/// the LOCKUP width keeps every caller's number comparable to the artwork rather than to a frame +/// whose size the aura decides. +pub fn logo_glow_sized(cx: &App, width: f32) -> impl IntoElement { + let frame_w = width * LOGO_GLOW_SCALE; + img(GLOW_IMAGES[usize::from(MoonPalette::active(cx).is_light())].clone()) + .w(px(frame_w)) + .h(px(frame_w)) } /// Vertical 1px group separator. diff --git a/crates/moon-ui-gpui/src/design/tests.rs b/crates/moon-ui-gpui/src/design/tests.rs index 404e4c1c..d9a80325 100644 --- a/crates/moon-ui-gpui/src/design/tests.rs +++ b/crates/moon-ui-gpui/src/design/tests.rs @@ -1,4 +1,4 @@ -//! Regression coverage for exact batched text measurement. +//! Regression coverage for exact batched text measurement and for the brand assets. use super::{FontId, FontWeight, MonoGlyphWidthCache, wrap_text}; use std::collections::HashMap; @@ -105,3 +105,53 @@ fn an_unbreakable_word_is_cut_rather_than_looped() { // And zero lines is a legitimate ask: it prints nothing rather than looping. assert!(wrap_text("anything", 10.0, 0, measure).is_empty()); } + +/// The brand cuts: scheme name, asset source, and the wordmark colour that cut must carry. +const BRAND_CUTS: [(&str, &str, &str); 2] = [ + ("dark", super::LOGO_SVG_DARK, "#E7E7E7"), + ("light", super::LOGO_SVG_LIGHT, "#17202A"), +]; + +/// Both cuts must survive [`super::logo_paths`], which splices them into the glow document. +/// +/// The extraction is string surgery on an asset nobody rebuilds when they re-export it, and its +/// failure is SILENT at runtime: an empty result draws an aura with no mark, indistinguishable +/// from a decode failure. So the check belongs here rather than in a bug report. +#[test] +fn brand_cuts_survive_the_glow_extraction() { + for (name, svg, _) in BRAND_CUTS { + let inner = super::logo_paths(svg); + assert!(inner.contains(" small mark; - `Popup` -> no logo. +Единственное исключение — full logo главного окна: `MoonWindowFrame` рисует свой +Moonbot-lockup, зашитый в компонент, а продукт называется MoonTerminal. Поэтому +header главного окна собирает бренд-кластер сам (`chrome/terminal_chrome.rs`): +drag-зону по-прежнему даёт `MoonWindowFrame::drag_handle()`, а лого и разделитель — +`design::header_logo` над ассетами `assets/brand/`. Геометрия кластера та же, что у +`brand_cluster` (`CHROME_GAP`, линейка 16px), но линейку рисует `design::chrome_divider`: +раз кластер собирает терминал, шов подчиняется тому же контрасту, что и остальные швы +строки, а не более бледному `border` из MoonUI. Вернуть `brand_cluster` следует ровно +тогда, когда `MoonWindowFrame` научится принимать чужой lockup. Для mark-окон и popup-ов +правило ниже действует без изменений. + Для titlebar-зоны использовать: - `MoonWindowFrame::brand_cluster(cx)` - brand + separator без title; @@ -247,6 +258,10 @@ MoonTerminal использует три визуальных класса ок Если в экране хочется "просто поставить логотип" или "просто нарисовать x", это значит, что в MoonUI не хватает нужного `MoonWindowFrameKind` или helper в `MoonWindowFrame`. Исправлять надо MoonUI-контракт, а не конкретный экран. +Единственное записанное исключение — брендовый lockup главного окна выше: пока в +`MoonWindowFrame` нет варианта под чужой логотип, его рисует `design::header_logo` +из `chrome/terminal_chrome.rs`. Оно записано здесь и закреплено тестом, а не +заведено по месту, — второго такого исключения быть не должно. Прямые использования в terminal UI запрещены: @@ -256,6 +271,9 @@ MoonTerminal использует три визуальных класса ок - `start_window_move`; - `titlebar_double_click`; - `logo_sized` / `logo_mark` вне самого brand/helper слоя; +- `design::header_logo` вне `chrome/terminal_chrome.rs` и открытие файла по пути + `assets/brand/` вне `design.rs` (назвать папку в комментарии можно) — логотип + берется у `MoonWindowFrame`, а единственное исключение описано выше; - `WindowOptions { ... }` вне `windowing.rs`. Запрет закреплен тестом `terminal_windows_use_closed_window_frame_api` в diff --git a/docs/tour/index.html b/docs/tour/index.html index 71b53b33..2521e869 100644 --- a/docs/tour/index.html +++ b/docs/tour/index.html @@ -890,7 +890,7 @@

Наведите или кликните

MANUAL режим

    -
  1. Бренд и перетаскивание — Логотип Moonbot и зона захвата окна: за неё окно таскается по экрану. Правее логотипа MoonUI сам рисует разделитель — поэтому второго терминал не добавляет.
  2. +
  3. Бренд и перетаскивание — Логотип MoonTerminal и зона захвата окна: за неё окно таскается по экрану. Логотип и разделитель правее него терминал рисует сам — рамка MoonUI знает только свой Moonbot.
  4. Режим воркспейса — Переключает рабочее пространство группы. В режиме AUTO терминал сам держит на графике монету активного ядра.
  5. Активное ядро и его шестерёнка — Выбор ядра, к которому относятся баланс, торговые кнопки и график. Шестерёнка открывает настройки именно этого ядра — блэклист, плечо, режим позиции.
  6. Баланс ядра — Свободный и общий USDT активного торгового ядра, как их отдаёт сервер. Если число устарело или курс посчитать не удалось, терминал показывает это, а не выдаёт старую цифру за живую.
  7. @@ -912,7 +912,7 @@

    MANUAL режим

AUTO режим

    -
  1. Бренд и перетаскивание — Логотип Moonbot и зона захвата окна: за неё окно таскается по экрану. Правее логотипа MoonUI сам рисует разделитель — поэтому второго терминал не добавляет.
  2. +
  3. Бренд и перетаскивание — Логотип MoonTerminal и зона захвата окна: за неё окно таскается по экрану. Логотип и разделитель правее него терминал рисует сам — рамка MoonUI знает только свой Moonbot.
  4. Режим воркспейса — Рабочее пространство для автоторговли; раскладка общая для всех серверов, открепление окон выключено
  5. Индикатор ядра, закреплённый рейкой — В режиме AUTO пилюля в шапке отключена и без меню: она только показывает выбранное на левой рейке ядро или «Полную сводку». Шестерёнка по-прежнему открывает настройки этого ядра. Баланс в шапке скрыт, пока выбрана сводка, — иначе рядом с подписью «вся группа» оказалась бы цифра одного случайного сервера.
  6. Тикер курса — Курс и дельты за 1ч / 24ч. Клик — открыть график, двойной — выбрать монету и ядро
  7. @@ -1284,13 +1284,13 @@

    AUTO режим

    "n": 1, "ru": [ "Бренд и перетаскивание", - "Логотип Moonbot и зона захвата окна: за неё окно таскается по экрану. Правее логотипа MoonUI сам рисует разделитель — поэтому второго терминал не добавляет." + "Логотип MoonTerminal и зона захвата окна: за неё окно таскается по экрану. Логотип и разделитель правее него терминал рисует сам — рамка MoonUI знает только свой Moonbot." ], "en": [ "Brand and window drag", - "The Moonbot logo doubles as the window's drag handle. MoonUI draws its own separator right of it, which is why the terminal never adds a second one." + "The MoonTerminal logo doubles as the window's drag handle. The terminal draws both the mark and the separator right of it itself — the MoonUI frame only knows its own Moonbot lockup." ], - "src": "chrome/terminal_chrome.rs — brand_cluster" + "src": "chrome/terminal_chrome.rs — header brand cluster" }, "ws": { "n": 2, @@ -1549,13 +1549,13 @@

    AUTO режим

    "n": 1, "ru": [ "Бренд и перетаскивание", - "Логотип Moonbot и зона захвата окна: за неё окно таскается по экрану. Правее логотипа MoonUI сам рисует разделитель — поэтому второго терминал не добавляет." + "Логотип MoonTerminal и зона захвата окна: за неё окно таскается по экрану. Логотип и разделитель правее него терминал рисует сам — рамка MoonUI знает только свой Moonbot." ], "en": [ "Brand and window drag", - "The Moonbot logo doubles as the window's drag handle. MoonUI draws its own separator right of it, which is why the terminal never adds a second one." + "The MoonTerminal logo doubles as the window's drag handle. The terminal draws both the mark and the separator right of it itself — the MoonUI frame only knows its own Moonbot lockup." ], - "src": "chrome/terminal_chrome.rs — brand_cluster" + "src": "chrome/terminal_chrome.rs — header brand cluster" }, "ws": { "n": 2, diff --git a/tools/tour/content/zones.yml b/tools/tour/content/zones.yml index 88a433fc..70600b51 100644 --- a/tools/tour/content/zones.yml +++ b/tools/tour/content/zones.yml @@ -14,12 +14,12 @@ maps: ru: Бренд и перетаскивание en: Brand and window drag body: - ru: 'Логотип Moonbot и зона захвата окна: за неё окно таскается по экрану. Правее логотипа MoonUI - сам рисует разделитель — поэтому второго терминал не добавляет.' - en: The Moonbot logo doubles as the window's drag handle. MoonUI draws its own separator right of - it, which is why the terminal never adds a second one. + ru: 'Логотип MoonTerminal и зона захвата окна: за неё окно таскается по экрану. Логотип и + разделитель правее него терминал рисует сам — рамка MoonUI знает только свой Moonbot.' + en: The MoonTerminal logo doubles as the window's drag handle. The terminal draws both the mark + and the separator right of it itself — the MoonUI frame only knows its own Moonbot lockup. src: - code: chrome/terminal_chrome.rs — brand_cluster + code: chrome/terminal_chrome.rs — header brand cluster - id: ws n: 2 title: @@ -229,12 +229,12 @@ maps: ru: Бренд и перетаскивание en: Brand and window drag body: - ru: 'Логотип Moonbot и зона захвата окна: за неё окно таскается по экрану. Правее логотипа MoonUI - сам рисует разделитель — поэтому второго терминал не добавляет.' - en: The Moonbot logo doubles as the window's drag handle. MoonUI draws its own separator right of - it, which is why the terminal never adds a second one. + ru: 'Логотип MoonTerminal и зона захвата окна: за неё окно таскается по экрану. Логотип и + разделитель правее него терминал рисует сам — рамка MoonUI знает только свой Moonbot.' + en: The MoonTerminal logo doubles as the window's drag handle. The terminal draws both the mark + and the separator right of it itself — the MoonUI frame only knows its own Moonbot lockup. src: - code: chrome/terminal_chrome.rs — brand_cluster + code: chrome/terminal_chrome.rs — header brand cluster - id: ws n: 2 title: