diff --git a/package-lock.json b/package-lock.json index 38d9f46b7..43a50879a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,6 +10,7 @@ "license": "GPL-2.0-or-later", "dependencies": { "@codemirror/fold": "^0.19.4", + "@tabler/icons-react": "^3.46.0", "@wordpress/components": "^29.3.0", "@wordpress/date": "^5.43.0", "@wordpress/dom-ready": "^4.17.0", @@ -3030,6 +3031,32 @@ "node": ">=10" } }, + "node_modules/@tabler/icons": { + "version": "3.46.0", + "resolved": "https://registry.npmjs.org/@tabler/icons/-/icons-3.46.0.tgz", + "integrity": "sha512-f2RYFl3fzPwj5WO82x6en0dmkjefxEfOm16D1ByM6cj/McNiwOkL4VaPUoP9VVIrXAD9WnTSVFr70px703b//A==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/codecalm" + } + }, + "node_modules/@tabler/icons-react": { + "version": "3.46.0", + "resolved": "https://registry.npmjs.org/@tabler/icons-react/-/icons-react-3.46.0.tgz", + "integrity": "sha512-CCm7xJWhDT2PH4ZIFkP6AgYKtVhq0gpYkjUN+GVh1AzmIQaa77OW0bQPBPQiTE0PsXMR9oSxFqA3qBglzPyrVQ==", + "license": "MIT", + "dependencies": { + "@tabler/icons": "3.46.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/codecalm" + }, + "peerDependencies": { + "react": ">= 16" + } + }, "node_modules/@tannin/compile": { "version": "1.1.0", "license": "MIT", diff --git a/src/css/common/_kebab-menu.scss b/src/css/common/_kebab-menu.scss index 99c601000..83f225eac 100644 --- a/src/css/common/_kebab-menu.scss +++ b/src/css/common/_kebab-menu.scss @@ -45,6 +45,7 @@ background: #fff; border: 1px solid #e2e2e4; border-radius: 5px; + overflow: hidden; box-shadow: 0 3px 16px rgb(0 0 0 / 15%); &.kebab-menu-popover-top { diff --git a/src/css/common/_page-header.scss b/src/css/common/_page-header.scss index 81a8c10e0..60d07f53d 100644 --- a/src/css/common/_page-header.scss +++ b/src/css/common/_page-header.scss @@ -15,10 +15,17 @@ h2 { margin: 0; padding: 0; - font-size: 32px; + font-size: 26px; font-weight: 510; line-height: 1.25; - color: #000; + } + + h1 { + color: #1d2327; + } + + h2 { + color: theme.$control-text; } } diff --git a/src/css/common/_subnav.scss b/src/css/common/_subnav.scss index 4b5ecf5fa..d0c5033a2 100644 --- a/src/css/common/_subnav.scss +++ b/src/css/common/_subnav.scss @@ -3,45 +3,76 @@ // Snippet-type navigation: a boxed segmented control on a white band, with // each tab separated by a vertical rule and the active tab shown as a // filled tile. -.snippet-type-nav { - // The tab band scrolls sideways instead of wrapping at any width. - overflow-x: auto; - scrollbar-width: thin; - background: #fff; +.snippet-type-nav-wrapper { + position: relative; - // The toolbar band above already draws the 1px separator, so only a - // bottom border here — a top border would double the line weight. - border-block-end: 1px solid #e2e2e4; - min-block-size: 53px; - - // Bleed across the full admin content width, flush against the plugin - // toolbar above: counteract the .wrap top margin (10px) plus its 2px / - // 20px inline margins and the #wpcontent 20px inline padding. + // Bleed across the full admin content width, flush against the plugin toolbar. box-sizing: border-box; - margin-block-start: -10px; + min-block-size: 53px; + margin-block-start: -1px; margin-inline-start: -22px; inline-size: calc(100% + 42px); + overflow: hidden; + background: #fff; + + &::before, + &::after { + position: absolute; + inset-block: 0; + z-index: 1; + inline-size: 32px; + content: ''; + opacity: 0; + pointer-events: none; + transition: opacity 150ms ease; + } + + &::before { + inset-inline-start: 0; + background: linear-gradient(to right, #fff, transparent); + } + + &::after { + inset-inline-end: 0; + background: linear-gradient(to left, #fff, transparent); + } + + &.has-scroll-start::before, + &.has-scroll-end::after { + opacity: 1; + } - // Core admin switches to 10px #wpcontent padding, 0/12px .wrap margins - // below 782px; mirror them so the bar stays flush without overflowing - // the viewport. The tabs scroll horizontally on a single row rather than - // stacking, with the scrollbar chrome hidden. @media (width <= 782px) { margin-inline-start: -10px; inline-size: calc(100% + 22px); - overflow-x: auto; - scrollbar-width: none; + } +} - &::-webkit-scrollbar { - display: none; - } +.snippet-type-nav { + // The tab band scrolls sideways instead of wrapping at any width. + overflow-x: auto; + scrollbar-width: thin; + + // The row line is painted on the scrollport so it remains fixed while tabs scroll. + background: linear-gradient(to top, #e2e2e4 1px, #fff 1px); - ul { - flex-wrap: nowrap; + @media (width <= 960px) { + li { + flex: 1 1 0; } .snippet-type-link { - white-space: nowrap; + inline-size: 100%; + min-inline-size: 100px; + padding-inline: 4px; + } + } + + @media (width <= 782px) { + scrollbar-width: none; + + &::-webkit-scrollbar { + display: none; } } @@ -49,7 +80,7 @@ display: flex; align-items: stretch; flex-wrap: nowrap; - min-block-size: 52px; + min-block-size: 53px; margin: 0; padding: 0; list-style: none; @@ -57,6 +88,7 @@ li { display: flex; + flex: 0 0 auto; margin: 0; } @@ -85,6 +117,7 @@ font-size: 14px; font-weight: 600; line-height: 1.5; + white-space: nowrap; color: #646970; text-decoration: none; box-sizing: border-box; @@ -110,12 +143,7 @@ &.active-type { background: #f0f0f1; - border-color: #f0f0f1; color: theme.$accent; - - // Children paint over the parent nav's border, so this recolours - // the 1px band separator beneath the active tab to match its fill. - box-shadow: 0 1px 0 0 #f0f0f1; } // Suppress the persistent focus ring left behind after a mouse click; @@ -189,6 +217,11 @@ display: flex; justify-content: flex-end; margin: 0; + border-color: #e2e2e4; + + .show-settings { + border-color: #e2e2e4; + } } #screen-meta { @@ -196,17 +229,18 @@ } } -// Item count shown after a subnav tab's label, as muted text. +// Item count shown after a subnav tab's label, using the label colour at reduced opacity. .snippet-type-nav .subnav-count { font-size: 14px; font-weight: 600; line-height: 1.5; - color: #646970; + color: currentcolor; + opacity: 0.65; } -// The active tab's count adopts the accent alongside its label. +// Keep the active count tied to its active label rather than assigning a separate colour. .snippet-type-nav .snippet-type-link.active-type .subnav-count { - color: theme.$accent; + color: currentcolor; } // The short "All" form of the all-snippets label only replaces "All Snippets" @@ -234,9 +268,8 @@ } } -// When an admin notice pushes the page content down, restore the gap and top -// border above the subnav bar. -.notice + .wrap .snippet-type-nav { - margin-block-start: 20px; - border-block-start: 1px solid theme.$control-border; +// When an admin notice pushes the page content down, restore the top border +// above the subnav bar (no extra margin — the wrapper sits flush). +.notice + .wrap .snippet-type-nav-wrapper { + border-block-start: 1px solid #e2e2e4; } diff --git a/src/css/common/_theme.scss b/src/css/common/_theme.scss index a836dce51..f4f40c544 100644 --- a/src/css/common/_theme.scss +++ b/src/css/common/_theme.scss @@ -13,10 +13,27 @@ $cloud-update: #ff9800; // screens regardless of WordPress version (see common/_wp-admin.scss). $accent-hover: #0a4b78; $control-border: #c3c4c7; -$control-text: #2c3338; +$control-text: #2c3337; $control-height: 38px; $control-radius: 5px; +// Runtime design tokens. Sass variables keep compile-time helpers available; +// custom properties expose the approved system to every rendered component. +:root { + --cs-color-accent: #2271b1; + --cs-color-accent-hover: #0a4b78; + --cs-color-text: #2c3337; + --cs-color-text-muted: #646970; + --cs-color-surface: #fff; + --cs-color-surface-subtle: #f6f7f7; + --cs-color-border: #c3c4c7; + --cs-color-border-subtle: #dcdcde; + --cs-control-height: 38px; + --cs-control-radius: 5px; + --cs-font-size-body: 14px; + --cs-line-height-body: 1.5; +} + /* format: background-color [color] */ $badges: ( // php/html/cond darkened for WCAG AA — at least 4.5:1 against white 12px @@ -26,12 +43,12 @@ $badges: ( css: #9b59b6, js: #f7d67a #1c1f20, cond: #22826f, - core: #61c5cb, + core: #4fa1a6, pro: #f7e8e3 #df9279, - cloud: $cloud, + cloud: #009fb4, bundles: #50575e, - cloud_search: #ff9800, - private: #f7e6be #ca961b, + cloud_search: #d27c00, + private: #f7e6be #a27813, public: #dbebf7 $accent, success: #d3e8d1 #447340, failure: #fad7c1 #a24b16, diff --git a/src/css/common/_toolbar.scss b/src/css/common/_toolbar.scss index e2bda2072..d3a16967a 100644 --- a/src/css/common/_toolbar.scss +++ b/src/css/common/_toolbar.scss @@ -68,6 +68,22 @@ $wpcontent-inline-start-indent: 20px; color: inherit; text-decoration: none; } + + @media (width <= 480px) { + padding-inline: 10px; + + .logo img { + block-size: 34px; + } + + .logo div { + display: none; + } + + .toolbar-upgrade-item .button { + padding-inline: 10px; + } + } } .code-snippets-toolbar-lower { @@ -114,6 +130,7 @@ $wpcontent-inline-start-indent: 20px; &.active-link, &:hover, &:focus, &:active { color: theme.$accent; + z-index: 1; } } @@ -149,22 +166,27 @@ $wpcontent-inline-start-indent: 20px; } } - // Mobile: the primary navigation scrolls horizontally on its band rather - // than wrapping, with the scrollbar chrome hidden. + // On narrow screens Settings remains available through the WordPress submenu. + // The remaining primary destinations fill the toolbar evenly rather than + // becoming a second horizontally-scrolling navigation row. @media (width <= 782px) { - overflow-x: auto; - scrollbar-width: none; - - &::-webkit-scrollbar { + li.toolbar-end-item { display: none; } - ul { - flex-wrap: nowrap; + li:not(.toolbar-end-item) { + flex: 1 1 0; + min-inline-size: 0; + } + + li:not(.toolbar-end-item) + li.toolbar-end-item { + margin-inline-start: 0; } li a { - white-space: nowrap; + inline-size: 100%; + padding-inline: 8px; + white-space: normal; } } } @@ -206,3 +228,104 @@ $wpcontent-inline-start-indent: 20px; .code-snippets-return-link { float: inline-end; } + +.code-snippets-toolbar-upper .toolbar-more-item { + display: none; +} + +.code-snippets-toolbar-upper .toolbar-more-menu { + position: relative; + + .dashicons, .dashicons::before { + inline-size: 16px; + block-size: 16px; + font-size: 16px; + } +} + +.code-snippets-toolbar-upper .toolbar-more-menu summary { + display: inline-flex; + align-items: center; + gap: 4px; + cursor: pointer; +} + +.code-snippets-toolbar-upper .toolbar-more-menu ul { + position: absolute; + inset-block-start: calc(100% + 8px); + inset-inline-end: 0; + z-index: 2; + display: grid; + min-inline-size: 180px; + block-size: auto; + margin: 0; + padding: 8px; + background: #fff; + border: 1px solid theme.$control-border; + box-shadow: 0 3px 8px rgb(0 0 0 / 15%); +} + +.code-snippets-toolbar-upper .toolbar-more-menu li { + margin: 0; +} + +// The upper and lower toolbars are distinct navigation trees; keep this rule +// after the lower-toolbar link state rules so the compact menu owns its hover state. +// stylelint-disable-next-line no-descending-specificity +.code-snippets-toolbar-upper .toolbar-more-menu a { + display: block; + padding: 8px; + white-space: nowrap; +} + +.code-snippets-toolbar-upper .toolbar-more-menu a:hover, +.code-snippets-toolbar-upper .toolbar-more-menu a:focus { + background: #f6f7f7; +} + +@media (width <= 960px) { + .code-snippets-toolbar-upper { + gap: 12px; + padding-inline: 16px; + } + + .code-snippets-toolbar-upper .logo { + flex: 0 1 auto; + min-inline-size: 0; + } + + .code-snippets-toolbar-upper nav { + margin-inline-start: auto; + } + + .code-snippets-toolbar-upper > nav > ul { + gap: 8px; + } + + .code-snippets-toolbar-upper > nav > ul > li:not(.toolbar-upgrade-item, .toolbar-more-item) { + display: none; + } + + .code-snippets-toolbar-upper .toolbar-more-item { + display: flex; + } + + .code-snippets-toolbar-upper .toolbar-more-menu summary { + padding: 8px; + white-space: nowrap; + } + + .code-snippets-toolbar-upper .toolbar-upgrade-item .button { + display: block; + max-inline-size: 180px; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + } +} + +@media (width <= 640px) { + .code-snippets-toolbar-upper .logo div { + display: none; + } +} diff --git a/src/css/common/_tooltips.scss b/src/css/common/_tooltips.scss index 1582d2942..dfc7a99d0 100644 --- a/src/css/common/_tooltips.scss +++ b/src/css/common/_tooltips.scss @@ -1,4 +1,4 @@ -$bg-color: hsl(0deg 0% 20% / 90%); +$bg-color: rgb(19 18 18 / 90%); .tooltip { position: relative; @@ -57,14 +57,15 @@ $bg-color: hsl(0deg 0% 20% / 90%); .tooltip-content { z-index: 1000; padding: 8px; - background-color: $bg-color; + background-color: rgb(19 18 18 / 90%); color: #fff; border-radius: 6px; position: absolute; - font-size: small; + font-size: 12px; font-weight: normal; text-transform: none; - min-inline-size: 200px; + inline-size: max-content; + max-inline-size: 200px; backdrop-filter: blur(3px); .tooltip-block & { diff --git a/src/css/common/_upsell.scss b/src/css/common/_upsell.scss index 5b2a25f77..afa61420c 100644 --- a/src/css/common/_upsell.scss +++ b/src/css/common/_upsell.scss @@ -1,4 +1,3 @@ -@use 'sass:color'; @use 'theme'; .code-snippets-upsell-banner { @@ -26,7 +25,7 @@ margin-inline-start: auto; &:hover, &:focus { - background-color: color.adjust(theme.$secondary, $lightness: -10%); + background-color: #0ca0a9; } } @@ -99,8 +98,12 @@ margin-inline: auto; border-color: currentcolor; - &:hover { - background-color: color.adjust(#d46f4d, $lightness: -10%); + // Matches the specificity of the native-control override in _wp-admin.scss + // (.wrap .button-primary:not(.button-link):hover:not(:disabled)) so this + // upsell-specific hover styling isn't overridden by the shared button rule. + &:hover:not(.button-link, :disabled) { + background-color: #0ca0a9; + border-color: #0ca0a9; } } } @@ -121,6 +124,19 @@ border-radius: 8px; } +// Bleed the upsell to the full width of the admin content area and fill the +// remaining viewport height, so it reads as a full page rather than a small +// boxed card floating in the subpage. 168px accounts for the WP admin bar +// (32px) plus the plugin toolbar ($toolbar-block-size, 136px in _toolbar.scss). +.code-snippets-upsell-page { + box-sizing: border-box; + margin-inline-start: -22px; + inline-size: calc(100% + 42px); + min-block-size: calc(100vh - 168px); + border-radius: 0; + justify-content: center; +} + .code-snippets-upsell-page, .code-snippets-upsell-dialog .components-modal__content > div:last-child { display: flex; diff --git a/src/css/common/_wp-admin.scss b/src/css/common/_wp-admin.scss index e0b9b839d..1dd6f035a 100644 --- a/src/css/common/_wp-admin.scss +++ b/src/css/common/_wp-admin.scss @@ -1,6 +1,17 @@ @use 'checkbox'; @use 'theme'; +// Match the active subnavigation tile so it blends into the admin canvas. +body.wp-admin { + background: #f0f0f1; +} + +// Remove the WordPress core 10px top margin on the manage snippets container +// so the subnav band sits flush against the toolbar. +#manage-snippets-container.wrap { + margin-block-start: 0; +} + /** * Native form control styling. * @@ -38,18 +49,18 @@ input[type='tel']:not([class*='components-']) { // `min-block-size` (not a fixed `block-size`) so controls floor at the token height but // can still flex-stretch where the layout calls for it (e.g. the 54px cloud search bar). - min-block-size: theme.$control-height; + min-block-size: var(--cs-control-height); padding-block: 0; padding-inline: 8px; - border: 1px solid theme.$control-border; - border-radius: theme.$control-radius; + border: 1px solid var(--cs-color-border); + border-radius: var(--cs-control-radius); line-height: 2; - color: theme.$control-text; + color: var(--cs-color-text); font-size: 14px; &:focus { - border-color: theme.$accent; - box-shadow: 0 0 0 1px theme.$accent; + border-color: var(--cs-color-accent); + box-shadow: 0 0 0 1px var(--cs-color-accent); outline: 2px solid transparent; } } @@ -58,21 +69,21 @@ // side. WP 7.0 keeps the chevron as a background image; clamping both paddings to 8px (as // for text inputs) would let the arrow overlap the text, so the inline-end padding is wider. select:not([class*='components-']) { - min-block-size: theme.$control-height; + min-block-size: var(--cs-control-height); padding-block: 0; padding-inline: 8px 24px; - border: 1px solid theme.$control-border; - border-radius: theme.$control-radius; + border: 1px solid var(--cs-color-border); + border-radius: var(--cs-control-radius); // WP 7.0 leaves a tall (≈38px) line-height on selects, pushing the value off-centre. // Pin it so the text stays vertically centred within the token height. line-height: 2; - color: theme.$control-text; + color: var(--cs-color-text); font-size: 14px; &:focus { - border-color: theme.$accent; - box-shadow: 0 0 0 1px theme.$accent; + border-color: var(--cs-color-accent); + box-shadow: 0 0 0 1px var(--cs-color-accent); outline: 2px solid transparent; } } @@ -84,21 +95,21 @@ .button:not(.button-primary, .button-link), .button-secondary, .page-title-action { - min-block-size: theme.$control-height; + min-block-size: var(--cs-control-height); padding-block: 0; padding-inline: 12px; - border-radius: theme.$control-radius; + border-radius: var(--cs-control-radius); line-height: 2.5715; font-size: 14px; font-weight: 400; background: #f6f7f7; - border-color: theme.$accent; - color: theme.$accent; + border-color: var(--cs-color-accent); + color: var(--cs-color-accent); &:hover:not(:disabled) { background: #f0f0f1; - border-color: theme.$accent-hover; - color: theme.$accent-hover; + border-color: var(--cs-color-accent-hover); + color: var(--cs-color-accent-hover); } &:focus:not(:disabled) { @@ -113,27 +124,27 @@ // matches the secondary rule's specificity so a `.button-small.button-primary` // keeps the token height instead of collapsing to the 26px small size. .button-primary:not(.button-link) { - min-block-size: theme.$control-height; + min-block-size: var(--cs-control-height); padding-block: 0; padding-inline: 12px; - border-radius: theme.$control-radius; + border-radius: var(--cs-control-radius); line-height: 2.5715; font-size: 14px; font-weight: 700; - background: theme.$accent; - border-color: theme.$accent; + background: var(--cs-color-accent); + border-color: var(--cs-color-accent); color: #fff; &:hover:not(:disabled) { - background: theme.$accent-hover; - border-color: theme.$accent-hover; + background: var(--cs-color-accent-hover); + border-color: var(--cs-color-accent-hover); color: #fff; } &:focus:not(:disabled) { - background: theme.$accent-hover; - border-color: theme.$accent-hover; - box-shadow: 0 0 0 1px #fff, 0 0 0 3px theme.$accent; + background: var(--cs-color-accent-hover); + border-color: var(--cs-color-accent-hover); + box-shadow: 0 0 0 1px #fff, 0 0 0 3px var(--cs-color-accent); outline: 2px solid transparent; } } diff --git a/src/css/common/list-table/_layout.scss b/src/css/common/list-table/_layout.scss index 009bded69..713742696 100644 --- a/src/css/common/list-table/_layout.scss +++ b/src/css/common/list-table/_layout.scss @@ -49,11 +49,29 @@ @include checkbox.canonical; } + // Shared cell rhythm for snippet and Cloud tables. Padding, rather than a + // fixed row height, keeps multi-line values comfortable and uncropped. + td, + th { + padding-block: 16px; + padding-inline: 8px; + } + + th:first-child, + td:first-child { + padding-inline-start: 16px; + } + + th:last-child, + td:last-child { + padding-inline-end: 16px; + } + // Shared horizontal rhythm for every snippet table, so the cloud table lines // up with the snippets table rather than keeping the wider WordPress default. th:not(.check-column), td:not(.check-column) { - padding-inline: 9px; + padding-inline: 8px; } td.column-id { @@ -203,8 +221,8 @@ tfoot td.check-column, tbody th.check-column, tbody td.check-column { - padding-block: 0; - padding-inline-start: 9px; + padding-block: 16px; + padding-inline-start: 8px; vertical-align: middle; } @@ -223,7 +241,6 @@ .active-snippet, .inactive-snippet { td, th { - padding: 10px 9px; box-shadow: inset 0 -1px 0 rgb(0 0 0 / 10%); vertical-align: middle; } diff --git a/src/css/common/list-table/_pagination.scss b/src/css/common/list-table/_pagination.scss index 4dc8e7943..137f791fb 100644 --- a/src/css/common/list-table/_pagination.scss +++ b/src/css/common/list-table/_pagination.scss @@ -1,4 +1,5 @@ @use '../checkbox'; +@use '../theme'; // The pagination group and view toggle wrap together as one end-pinned // cluster so narrow viewports never split them across rows. @@ -65,7 +66,7 @@ } .wrap .snippets-search-area input[type='search'] { - border-color: #e3e3e4; + border-color: theme.$control-border; } // Tablet widths: let the search area grow to fill the remainder of its row @@ -79,6 +80,14 @@ } @media (width <= 782px) { + // Wide table columns scroll inside the results region instead of extending + // the WordPress admin document horizontally. + .snippets-list-view { + max-inline-size: 100%; + overflow-x: auto; + overscroll-behavior-inline: contain; + } + p.search-box { float: inline-start; position: initial; @@ -87,10 +96,21 @@ block-size: auto; } - // Mobile: the search area takes a full row of its own, and the action - // groups stay visible (core admin hides .tablenav.top .actions here). + + // Mobile keeps the filters compact. Pagination remains below the results, + // avoiding a second navigation cluster above the table. + .tablenav.top .tablenav-pages-nav { + display: none; + } + + .tablenav.top .tablenav-end-group { + margin-inline-start: 0; + } + .tablenav .snippets-search-area { - flex-basis: 100%; + flex: 0 1 20rem; + inline-size: min(100%, 20rem); + max-inline-size: 20rem; } .tablenav .alignleft.actions { diff --git a/src/css/edit.scss b/src/css/edit.scss index b7a10773d..6f270cea9 100644 --- a/src/css/edit.scss +++ b/src/css/edit.scss @@ -95,7 +95,7 @@ } } -.wrap > h2:first-of-type { +.wrap > h1:first-of-type { font-size: 1.5rem; font-weight: 400; line-height: 1.3; diff --git a/src/css/edit/_form.scss b/src/css/edit/_form.scss index 6153c4840..a9b1bbcee 100644 --- a/src/css/edit/_form.scss +++ b/src/css/edit/_form.scss @@ -3,9 +3,8 @@ $sidebar-width: 321px; $sidebar-gap: 30px; -.snippet-form #titlediv #title, -.snippet-type-container { - border-color: #ccc; +.snippet-form #titlediv #title { + border-color: theme.$control-border; block-size: 45px } @@ -18,6 +17,7 @@ $sidebar-gap: 30px; // Target the control box only (:first-of-type). The open menu is a later // sibling div; matching it here would clamp and flex-row the option list. > div:first-of-type { + border-color: theme.$control-border; min-block-size: 45px; block-size: 45px; max-block-size: 45px; @@ -54,8 +54,14 @@ $sidebar-gap: 30px; .conditions-editor-header { display: flex; align-items: center; - justify-content: space-between; + justify-content: flex-start; gap: 8px; + margin-block-end: 8px; + + strong { + font-size: 14px; + line-height: 20px; + } } .button.button-large { @@ -63,8 +69,14 @@ $sidebar-gap: 30px; align-items: center; gap: 8px; inline-size: 100%; - border-color: #ccc; + border-color: theme.$control-border; + background: transparent; padding: 6px 12px; + + &:hover:not(:disabled), + &:focus:not(:disabled) { + background: #f6f7f7; + } } &.no-condition .cond-badge { @@ -115,8 +127,15 @@ $sidebar-gap: 30px; grid-area: span 3 / sidebar; max-inline-size: $sidebar-width; position: sticky; - inset-block-start: 32px; + + // Keep the sidebar clear of the fixed WordPress admin bar and leave a + // usable visual gap beneath it while the editor scrolls. + inset-block-start: 48px; align-self: start; + + @media (width <= 782px) { + position: static; + } } @media (width <= 1024px) { diff --git a/src/css/edit/_sidebar.scss b/src/css/edit/_sidebar.scss index 888307702..3685abf51 100644 --- a/src/css/edit/_sidebar.scss +++ b/src/css/edit/_sidebar.scss @@ -57,7 +57,7 @@ .box { background-color: #fff; - border: 1px solid #ccc; + border: 1px solid theme.$control-border; border-radius: 4px; padding: 1.5em; display: flex; diff --git a/src/css/manage/_cloud-community-cards.scss b/src/css/manage/_cloud-community-cards.scss index 8a0c9c3f4..82ead781a 100644 --- a/src/css/manage/_cloud-community-cards.scss +++ b/src/css/manage/_cloud-community-cards.scss @@ -1,4 +1,3 @@ -@use 'sass:color'; @use '../common/theme'; @use '../common/cards'; @@ -62,6 +61,7 @@ flex-wrap: wrap; gap: 16px; font-size: 14px; + line-height: 1.5; .cloud-snippet-tags { color: theme.$accent; @@ -81,6 +81,7 @@ overflow: hidden; margin: 0; font-size: 14px; + line-height: 1.5; color: #646970; border-block-start: 1px solid #dcdcde; padding-block-start: 16px; @@ -112,7 +113,7 @@ } .button:not(.button-primary, .cloud-pro-button) { - background: #fff; + background: transparent; } } } @@ -121,18 +122,17 @@ margin: 0; } -// Anchored to the card container so this keeps its brand-orange fill above the WP-admin -// compatibility layer's secondary-button styling (equal specificity, resolved by source order). -.cloud-search-result .cloud-pro-button.button { - background-color: theme.$secondary; - border-color: theme.$secondary; - color: #fff; +// Pro-only actions use the same quiet outline treatment in card and table views. +.cloud-pro-button.button { + background-color: transparent; + border-color: theme.$accent; + color: theme.$accent; &:hover, &:focus { - background-color: color.adjust(theme.$secondary, $lightness: -10%); - border-color: color.adjust(theme.$secondary, $lightness: -10%); - color: #fff; + background-color: #eff5f9; + border-color: theme.$accent; + color: theme.$accent; } } diff --git a/src/css/manage/_cloud-community.scss b/src/css/manage/_cloud-community.scss index ed637aa9a..686c52088 100644 --- a/src/css/manage/_cloud-community.scss +++ b/src/css/manage/_cloud-community.scss @@ -1,4 +1,5 @@ @use '../common/banners'; +@use '../common/checkbox'; @use '../common/theme'; .cloud-snippet-status { @@ -102,23 +103,30 @@ $status-colors: ( // Keep the Download / Edit / Pro Only button a consistent width so // rows line up regardless of which state the snippet is in. .button-primary, - .cloud-pro-button { - min-inline-size: 90px; + .cloud-pro-button, + .button:not(.button-primary) { + inline-size: 103px; + min-inline-size: 103px; text-align: center; justify-content: center; } } .cloud-snippets-table { - // Body rows only: the header row also holds a `td` for the select-all cell, - // and a fixed height there would make this header taller than the one on the - // snippets table. + // Body rows inherit the shared table-cell padding so descriptions can grow + // naturally instead of being constrained to a fixed row height. tbody td { - box-sizing: border-box; - block-size: 60px; vertical-align: middle; } + .check-column { + vertical-align: middle; + + input[type='checkbox'] { + @include checkbox.canonical; + } + } + .column-name { inline-size: 22%; } @@ -132,7 +140,7 @@ $status-colors: ( } .column-actions { - inline-size: 210px; + inline-size: 234px; } .cloud-table-name-button { diff --git a/src/css/manage/_snippets-table.scss b/src/css/manage/_snippets-table.scss index d4a3de071..5a8e23f28 100644 --- a/src/css/manage/_snippets-table.scss +++ b/src/css/manage/_snippets-table.scss @@ -162,6 +162,7 @@ flex-wrap: wrap; gap: 16px; font-size: 14px; + line-height: 1.5; .snippet-card-tags-label { color: #646970; @@ -173,7 +174,10 @@ } .snippet-card-modified { - color: #646970; + color: var(--cs-color-text-muted); + } + + &.has-tags .snippet-card-modified { margin-inline-start: auto; } } @@ -185,6 +189,7 @@ line-clamp: 2; overflow: hidden; font-size: 14px; + line-height: 1.5; color: #646970; border-block-start: 1px solid #dcdcde; padding-block-start: 16px; @@ -203,7 +208,7 @@ } .button:not(.button-primary) { - background: #fff; + background: transparent; } } diff --git a/src/css/menu.scss b/src/css/menu.scss index 53aa21321..c4a9ec286 100644 --- a/src/css/menu.scss +++ b/src/css/menu.scss @@ -36,7 +36,7 @@ } &:hover { - background-color: #08c5d1; + background-color: #0ca0a9; } .dashicons { diff --git a/src/css/settings.scss b/src/css/settings.scss index 9622512d1..be7038058 100644 --- a/src/css/settings.scss +++ b/src/css/settings.scss @@ -242,5 +242,75 @@ body.js { } #settings-sections-tabs { - margin-block-end: 15px; + margin: 0; + padding: 0; + + ul { + display: flex; + align-items: stretch; + margin: 0; + padding: 0; + list-style: none; + } + + .snippet-type-link { + display: flex; + align-items: center; + min-block-size: 52px; + margin: 0; + padding-inline: 24px; + color: #646970; + font-size: 14px; + font-weight: 600; + line-height: 1.5; + border: 0; + border-inline-end: 1px solid #e2e2e4; + background: transparent; + + &:hover, + &:focus { + color: #2c3337; + background: #f6f7f7; + } + + &.active-type, + &.active-type:hover, + &.active-type:focus { + position: relative; + z-index: 1; + margin-block-end: -1px; + color: theme.$accent; + background: #f0f0f1; + border-color: #f0f0f1; + } + } +} + +@media (width <= 782px) { + body.js { + .settings-type-nav-wrapper { + display: none; + } + + .settings-section-title { + position: static; + inline-size: auto; + block-size: auto; + margin: 0 0 16px; + overflow: visible; + clip: auto; + clip-path: none; + font-size: 20px; + line-height: 1.3; + } + + .settings-section { + display: block !important; + margin-block-end: 40px; + } + + .wrap[data-active-tab='license'] .submit { + display: flex; + } + } } diff --git a/src/js/components/EditMenu/EditorSidebar/EditorSidebar.tsx b/src/js/components/EditMenu/EditorSidebar/EditorSidebar.tsx index 77845851e..2a5a4ab86 100644 --- a/src/js/components/EditMenu/EditorSidebar/EditorSidebar.tsx +++ b/src/js/components/EditMenu/EditorSidebar/EditorSidebar.tsx @@ -1,11 +1,12 @@ import React from 'react' import { Spinner } from '@wordpress/components' import { __, isRTL } from '@wordpress/i18n' +import { useDeleteSnippet } from '../../../hooks/useDeleteSnippet' import { buildUrl } from '../../../utils/urls' +import { Button } from '../../common/Button' import { useSnippetForm } from '../SnippetForm/WithSnippetFormContext' import { isNetworkAdmin } from '../../../utils/screen' import { isCondition } from '../../../utils/snippets/snippets' -import { DeleteButton } from '../../common/DeleteButton' import { ConditionModalButton } from '../ConditionModal/ConditionModalButton' import { SnippetLocationInput } from '../SnippetForm/fields/SnippetLocationInput' import { Notices } from '../SnippetForm/page/Notices' @@ -26,6 +27,17 @@ export interface EditorSidebarProps { export const EditorSidebar: React.FC = ({ setIsUpgradeDialogOpen }) => { const { snippet, isWorking, setIsWorking, handleRequestError } = useSnippetForm() + const { requestDelete, ConfirmDeleteDialog } = useDeleteSnippet({ + snippet, + setIsWorking, + onSuccess: () => { + window.location.replace(buildUrl(window.CODE_SNIPPETS?.urls.manage, { result: 'deleted' })) + }, + onError: error => { + handleRequestError(error, __('Could not delete snippet.', 'code-snippets')) + } + }) + return (
@@ -40,23 +52,16 @@ export const EditorSidebar: React.FC = ({ setIsUpgradeDialog - {snippet.id - ?
+ {snippet.id && ( +
- { - window.location.replace(buildUrl(window.CODE_SNIPPETS?.urls.manage, { result: 'deleted' })) - }} - onError={error => { - handleRequestError(error, __('Could not delete snippet.', 'code-snippets')) - }} - /> + + + -
- : null} +
)}

@@ -65,6 +70,7 @@ export const EditorSidebar: React.FC = ({ setIsUpgradeDialog

+
) } diff --git a/src/js/components/ManageMenu/CommunityCloud/CloudSnippetsTable.tsx b/src/js/components/ManageMenu/CommunityCloud/CloudSnippetsTable.tsx index ebc13e1aa..cb3c9d4f6 100644 --- a/src/js/components/ManageMenu/CommunityCloud/CloudSnippetsTable.tsx +++ b/src/js/components/ManageMenu/CommunityCloud/CloudSnippetsTable.tsx @@ -5,8 +5,8 @@ import { stripTags, truncateChars } from '../../../utils/text' import { Badge } from '../../common/Badge' import { Button } from '../../common/Button' import { CloudSnippetDownloadButton } from '../../common/cloud/CloudSnippetDownloadButton' -import { CloudSnippetPreviewModal } from '../../common/cloud/CloudSnippetPreviewModal' import { CloudStatusBadge } from '../../common/cloud/CloudStatusBadge' +import { CloudSnippetPreviewModal } from '../../common/SnippetPreviewModal' import { useCloudSearch } from './WithCloudSearchContext' import type { CloudSnippetSchema } from '../../../types/schema/CloudSnippetSchema' import type { Dispatch, SetStateAction } from 'react' @@ -50,12 +50,8 @@ const CloudSnippetActions: React.FC = ({ - + {isPreviewOpen && ( + )} ) } diff --git a/src/js/components/ManageMenu/CommunityCloud/CommunityCloud.tsx b/src/js/components/ManageMenu/CommunityCloud/CommunityCloud.tsx index e42dfa532..e6f8ee611 100644 --- a/src/js/components/ManageMenu/CommunityCloud/CommunityCloud.tsx +++ b/src/js/components/ManageMenu/CommunityCloud/CommunityCloud.tsx @@ -57,19 +57,23 @@ const CommunityCloudInner = () => { }} /> - +