Improve edge-docked window behavior (#2779)

* Make edge-docked windows resizable

Add draggable resize seams for left and right docked windows.

Keep the main chat area from getting too narrow and remember each window's dock width.

* Show emoji shortcodes as icons by default

Keep text-only emoji mode opt-in so model output like 😊 goes through the normal emoji renderer.

* Fix dock resize seams and left dock layout

Hide the resize seam when another floating modal is open, and keep the left-docked window from covering the chat area.

* Keep narrow modal tabs usable

* Fix split layout with both edge docks

* Fix left snap after right dock

* Enable left edge snap for all windows

* Tighten dock resize handle observers

* Use edge docking for settings window
This commit is contained in:
Enes Öz
2026-06-05 18:07:08 +03:00
committed by GitHub
parent 8ce945d338
commit 977daf0643
5 changed files with 434 additions and 43 deletions
+110 -10
View File
@@ -97,9 +97,9 @@ html, body { overflow-x: hidden; height: 100%; margin: 0; overscroll-behavior: n
body {
background-color: var(--bg);
color: var(--fg);
/* Animate the dock push BOTH ways. Keeping the transition on the base body
(not on .right/left-dock-active) means removing the class on undock also
animates padding back to 0 otherwise the chat snapped back instantly. */
/* Keep the base padding transition for older layout paths that still adjust
the body directly. Edge docks reserve workspace room on the flex panes
below so left + right docks can coexist without skewing the whole body. */
transition: padding-left 160ms cubic-bezier(0.22, 0.61, 0.36, 1),
padding-right 160ms cubic-bezier(0.22, 0.61, 0.36, 1);
font-family: var(--font-family, 'Fira Code', monospace);
@@ -1773,6 +1773,8 @@ body.bg-pattern-sparkles {
min-width:0;
margin-top:8px;
margin-bottom: 0;
transition: margin-left 160ms cubic-bezier(0.22, 0.61, 0.36, 1),
margin-right 160ms cubic-bezier(0.22, 0.61, 0.36, 1);
}
.chat-meta { font-size:12px; color:color-mix(in srgb, var(--fg) 60%, transparent); margin-bottom:6px; }
.chat-history {
@@ -4939,6 +4941,15 @@ body.bg-pattern-sparkles {
pointer-events:auto;
animation: modal-enter 0.25s ease-out both;
}
.memory-modal-content,
.tasks-modal-content,
.preset-modal-content,
#cookbook-modal .modal-content,
#theme-popup,
.doclib-modal-content,
.gallery-modal-content {
container-type: inline-size;
}
.modal-header {
display:flex; justify-content:space-between; align-items:center; margin-bottom:6px;
cursor:grab; user-select:none;
@@ -14843,7 +14854,7 @@ body:has(.doc-version-panel:not(.hidden)) .hamburger-btn {
body.email-doc-split-active.doc-view .doc-editor-pane {
position: fixed !important;
left: var(--email-doc-split-right-x, 420px) !important;
right: 0 !important;
right: var(--right-dock-w, 0px) !important;
top: 0 !important;
bottom: 0 !important;
width: auto !important;
@@ -14864,15 +14875,21 @@ body [data-act="from-sender"] {
display: none !important;
}
/* Snap-to-right docking. A modal dragged to the right edge becomes a
docked side panel (mirrors Notes/Doc panels). Body reserves space via
padding-right so the chat / notes / doc panel underneath shrinks to
fit instead of being hidden behind the panel. */
/* Edge docking. Docked panels are fixed to the viewport edge; the workspace
panes reserve room with margins so left + right docks can be active at the
same time without skewing the entire body box. */
body.right-dock-active {
padding-right: var(--right-dock-w, 0px);
padding-right: 0;
}
body.left-dock-active {
padding-left: var(--left-dock-w, 0px);
padding-left: 0;
}
body.left-dock-active:not(.email-doc-split-active) .chat-container {
margin-left: var(--left-dock-w, 0px);
}
body.right-dock-active .chat-container,
body.right-dock-active:not(.email-doc-split-active) .doc-editor-pane {
margin-right: var(--right-dock-w, 0px);
}
.modal.modal-right-docked {
align-items: stretch;
@@ -23192,6 +23209,89 @@ input.settings-select::placeholder { color: color-mix(in srgb, var(--fg) 35%, tr
opacity: 1;
border-bottom-color: var(--red);
}
/* Narrow modal tab strips should stay on one row. Resized docked windows can
be much narrower than the viewport, so this cannot live only in mobile media
queries. */
.cookbook-tabs,
.memory-tabs,
.admin-tabs,
.lib-tabs,
.gallery-tabs,
.preset-tabs {
flex-wrap: nowrap !important;
overflow-x: auto !important;
overflow-y: hidden;
-webkit-overflow-scrolling: touch;
overscroll-behavior-x: contain;
scrollbar-width: none;
}
.cookbook-tabs::-webkit-scrollbar,
.memory-tabs::-webkit-scrollbar,
.admin-tabs::-webkit-scrollbar,
.lib-tabs::-webkit-scrollbar,
.gallery-tabs::-webkit-scrollbar,
.preset-tabs::-webkit-scrollbar {
display: none;
}
.cookbook-tabs > *,
.memory-tabs > *,
.admin-tabs > *,
.lib-tabs > *,
.gallery-tabs > *,
.preset-tabs > * {
flex: 0 0 auto;
}
.cookbook-tab,
.memory-tab,
.admin-tab,
.lib-tab,
.gallery-tab,
.preset-tab {
display: inline-flex;
align-items: center;
justify-content: center;
white-space: nowrap;
line-height: 1;
}
.gallery-tab {
gap: 6px;
}
@container (max-width: 360px) {
.cookbook-tab:has(svg),
.memory-tab:has(svg),
.admin-tab:has(svg),
.lib-tab:has(svg),
.gallery-tab:has(svg),
.preset-tab:has(svg) {
width: 34px;
min-width: 34px;
padding-left: 0;
padding-right: 0;
font-size: 0;
}
.cookbook-tab:has(svg) svg,
.memory-tab:has(svg) svg,
.admin-tab:has(svg) svg,
.lib-tab:has(svg) svg,
.gallery-tab:has(svg) svg,
.preset-tab:has(svg) svg {
width: 14px;
height: 14px;
margin-right: 0 !important;
vertical-align: middle !important;
}
.memory-tab:has(svg) .memory-count,
.gallery-tab:has(svg) .gallery-tab-label,
.gallery-tab:has(svg) .gallery-tab-close,
.cookbook-tab:has(svg) .cookbook-tab-count,
.preset-tab:has(svg) .preset-count {
display: none !important;
}
}
/* Icon + label layout inside each tab. */
.gallery-tab {
display: inline-flex;