feat(react/ribbon): port base structure

This commit is contained in:
Elian Doran
2025-08-21 18:29:13 +03:00
parent d76d50f30e
commit 45fbcec805
5 changed files with 136 additions and 145 deletions

View File

@@ -73,6 +73,7 @@ import ToggleReadOnlyButton from "../widgets/floating_buttons/toggle_read_only_b
import PngExportButton from "../widgets/floating_buttons/png_export_button.js";
import RefreshButton from "../widgets/floating_buttons/refresh_button.js";
import { applyModals } from "./layout_commons.js";
import Ribbon from "../widgets/ribbon/Ribbon.jsx";
export default class DesktopLayout {
@@ -159,29 +160,7 @@ export default class DesktopLayout {
.child(new ClosePaneButton())
.child(new CreatePaneButton())
)
.child(
new RibbonContainer()
// the order of the widgets matter. Some of these want to "activate" themselves
// when visible. When this happens to multiple of them, the first one "wins".
// promoted attributes should always win.
.ribbon(new ClassicEditorToolbar())
.ribbon(new ScriptExecutorWidget())
.ribbon(new SearchDefinitionWidget())
.ribbon(new EditedNotesWidget())
.ribbon(new BookPropertiesWidget())
.ribbon(new NotePropertiesWidget())
.ribbon(new FilePropertiesWidget())
.ribbon(new ImagePropertiesWidget())
.ribbon(new BasicPropertiesWidget())
.ribbon(new OwnedAttributeListWidget())
.ribbon(new InheritedAttributesWidget())
.ribbon(new NotePathsWidget())
.ribbon(new NoteMapRibbonWidget())
.ribbon(new SimilarNotesWidget())
.ribbon(new NoteInfoWidget())
.button(new RevisionsButton())
.button(new NoteActionsWidget())
)
.child(<Ribbon />)
.child(new SharedInfoWidget())
.child(new WatchedFileUpdateStatusWidget())
.child(

View File

@@ -7,116 +7,6 @@ import type { NoteType } from "../../entities/fnote.js";
import type { EventData, EventNames } from "../../components/app_context.js";
import type NoteActionsWidget from "../buttons/note_actions.js";
const TPL = /*html*/`
<div class="ribbon-container">
<style>
.ribbon-container {
margin-bottom: 5px;
}
.ribbon-top-row {
display: flex;
}
.ribbon-tab-container {
display: flex;
flex-direction: row;
justify-content: center;
margin-left: 10px;
flex-grow: 1;
flex-flow: row wrap;
}
.ribbon-tab-title {
color: var(--muted-text-color);
border-bottom: 1px solid var(--main-border-color);
min-width: 24px;
flex-basis: 24px;
max-width: max-content;
flex-grow: 10;
}
.ribbon-tab-title .bx {
font-size: 150%;
position: relative;
top: 3px;
}
.ribbon-tab-title.active {
color: var(--main-text-color);
border-bottom: 3px solid var(--main-text-color);
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.ribbon-tab-title:hover {
cursor: pointer;
}
.ribbon-tab-title:hover {
color: var(--main-text-color);
}
.ribbon-tab-title:first-of-type {
padding-left: 10px;
}
.ribbon-tab-spacer {
flex-basis: 0;
min-width: 0;
max-width: 35px;
flex-grow: 1;
border-bottom: 1px solid var(--main-border-color);
}
.ribbon-tab-spacer:last-of-type {
flex-grow: 1;
flex-basis: 0;
min-width: 0;
max-width: 10000px;
}
.ribbon-button-container {
display: flex;
border-bottom: 1px solid var(--main-border-color);
margin-right: 5px;
}
.ribbon-button-container > * {
position: relative;
top: -3px;
margin-left: 10px;
}
.ribbon-body {
display: none;
border-bottom: 1px solid var(--main-border-color);
margin-left: 10px;
margin-right: 5px; /* needs to have this value so that the bottom border is the same width as the top one */
}
.ribbon-body.active {
display: block;
}
.ribbon-tab-title-label {
display: none;
}
.ribbon-tab-title.active .ribbon-tab-title-label {
display: inline;
}
</style>
<div class="ribbon-top-row">
<div class="ribbon-tab-container"></div>
<div class="ribbon-button-container"></div>
</div>
<div class="ribbon-body-container"></div>
</div>`;
type ButtonWidget = (CommandButtonWidget | NoteActionsWidget);
export default class RibbonContainer extends NoteContextAwareWidget {
@@ -160,8 +50,6 @@ export default class RibbonContainer extends NoteContextAwareWidget {
}
doRender() {
this.$widget = $(TPL);
this.$tabContainer = this.$widget.find(".ribbon-tab-container");
this.$buttonContainer = this.$widget.find(".ribbon-button-container");
this.$bodyContainer = this.$widget.find(".ribbon-body-container");
@@ -241,16 +129,11 @@ export default class RibbonContainer extends NoteContextAwareWidget {
.attr("data-ribbon-component-id", ribbonWidget.componentId)
.attr("data-ribbon-component-name", (ribbonWidget as any).name as string) // TODO: base class for ribbon widgets
.append(
$('<span class="ribbon-tab-title-icon">')
.addClass(ret.icon)
.attr("title", ret.title)
$('<span class="">')
.attr("data-toggle-command", (ribbonWidget as any).toggleCommand)
) // TODO: base class
.append(" ")
.append($('<span class="ribbon-tab-title-label">').text(ret.title));
)
this.$tabContainer.append($ribbonTitle);
this.$tabContainer.append('<div class="ribbon-tab-spacer">');
this.$tabContainer.append('');
if (ret.activate && !this.lastActiveComponentId && !$ribbonTabToActivate && !noExplicitActivation) {
$ribbonTabToActivate = $ribbonTitle;

View File

@@ -0,0 +1,37 @@
import { t } from "../../services/i18n";
import "./style.css";
export default function Ribbon() {
return (
<div class="ribbon-container" style={{ contain: "none" }}>
<div className="ribbon-top-row">
<div className="ribbon-tab-container">
<RibbonTab
title={t("basic_properties.basic_properties")}
icon="bx bx-slider"
/>
</div>
<div className="ribbon-button-container"></div>
</div>
<div className="ribbon-body-container"></div>
</div>
)
}
function RibbonTab({ icon, title }: { icon: string; title: string }) {
return (
<>
<div className="ribbon-tab-title">
<span
className={`ribbon-tab-title-icon ${icon}`}
title={title}
/>
&nbsp;
<span class="ribbon-tab-title-label">{title}</span>
</div>
<div class="ribbon-tab-spacer" />
</>
)
}

View File

@@ -0,0 +1,94 @@
.ribbon-container {
margin-bottom: 5px;
}
.ribbon-top-row {
display: flex;
min-height: 36px;
}
.ribbon-tab-container {
display: flex;
flex-direction: row;
justify-content: center;
margin-left: 10px;
flex-grow: 1;
flex-flow: row wrap;
}
.ribbon-tab-title {
color: var(--muted-text-color);
border-bottom: 1px solid var(--main-border-color);
min-width: 24px;
flex-basis: 24px;
max-width: max-content;
flex-grow: 10;
}
.ribbon-tab-title .bx {
font-size: 150%;
position: relative;
top: 3px;
}
.ribbon-tab-title.active {
color: var(--main-text-color);
border-bottom: 3px solid var(--main-text-color);
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.ribbon-tab-title:hover {
cursor: pointer;
}
.ribbon-tab-title:hover {
color: var(--main-text-color);
}
.ribbon-tab-title:first-of-type {
padding-left: 10px;
}
.ribbon-tab-spacer {
flex-basis: 0;
min-width: 0;
max-width: 35px;
flex-grow: 1;
border-bottom: 1px solid var(--main-border-color);
}
.ribbon-tab-spacer:last-of-type {
flex-grow: 1;
flex-basis: 0;
min-width: 0;
max-width: 10000px;
}
.ribbon-button-container {
display: flex;
border-bottom: 1px solid var(--main-border-color);
margin-right: 5px;
}
.ribbon-button-container > * {
position: relative;
top: -3px;
margin-left: 10px;
}
.ribbon-body {
display: none;
border-bottom: 1px solid var(--main-border-color);
margin-left: 10px;
margin-right: 5px; /* needs to have this value so that the bottom border is the same width as the top one */
}
.ribbon-body.active {
display: block;
}
.ribbon-tab-title.active .ribbon-tab-title-label {
display: inline;
}

View File

@@ -99,8 +99,6 @@ export default class BasicPropertiesWidget extends NoteContextAwareWidget {
getTitle() {
return {
show: !this.note?.isLaunchBarConfig(),
title: t("basic_properties.basic_properties"),
icon: "bx bx-slider"
};
}