diff --git a/frontend/src/app/app.component.css b/frontend/src/app/app.component.css index 05a64e488..3c436c2c5 100644 --- a/frontend/src/app/app.component.css +++ b/frontend/src/app/app.component.css @@ -139,6 +139,20 @@ .logo__image { height: 24px; margin-right: 12px; + display: block; + vertical-align: middle; +} + +.logo picture { + display: inline-flex; + align-items: center; +} + +@media (width <= 600px) { + .logo__image { + height: 28px; + margin-right: 8px; + } } .logo__demo-mark { diff --git a/frontend/src/app/app.component.html b/frontend/src/app/app.component.html index 7c57050d9..beec4e212 100644 --- a/frontend/src/app/app.component.html +++ b/frontend/src/app/app.component.html @@ -86,11 +86,18 @@

settings diff --git a/frontend/src/app/components/dashboard/db-table-view/db-table-row-view/db-table-row-view.component.css b/frontend/src/app/components/dashboard/db-table-view/db-table-row-view/db-table-row-view.component.css index 37d801447..a4cc7de50 100644 --- a/frontend/src/app/components/dashboard/db-table-view/db-table-row-view/db-table-row-view.component.css +++ b/frontend/src/app/components/dashboard/db-table-view/db-table-row-view/db-table-row-view.component.css @@ -30,13 +30,72 @@ @media (width <= 600px) { .row-preview-sidebar_open { position: fixed; - top: 44px; + top: auto; bottom: 0; left: 0; + right: 0; min-height: initial; - max-height: initial; + max-height: calc(80vh + env(safe-area-inset-bottom, 0px)); width: 100vw; - z-index: 2; + z-index: 1001; + border-top-left-radius: 16px; + border-top-right-radius: 16px; + border-left: none !important; + box-shadow: 0 -8px 32px rgba(0, 0, 0, 0.18); + padding-bottom: env(safe-area-inset-bottom, 0px); + animation: rowPreviewSlideUp 240ms cubic-bezier(0.2, 0.8, 0.2, 1); + } +} + +.row-preview-backdrop { + display: none; +} + +.row-preview-sidebar__handle { + display: none; +} + +@media (width <= 600px) { + .row-preview-backdrop { + display: block; + position: fixed; + inset: 0; + background: rgba(0, 0, 0, 0.4); + z-index: 1000; + animation: rowPreviewBackdropFadeIn 240ms ease-out; + } + + .row-preview-sidebar__handle { + display: block; + width: 36px; + height: 4px; + border-radius: 2px; + background: rgba(0, 0, 0, 0.2); + margin: 8px auto 0; + } +} + +@media (prefers-color-scheme: dark) { + .row-preview-sidebar__handle { + background: rgba(255, 255, 255, 0.24); + } +} + +@keyframes rowPreviewSlideUp { + from { + transform: translateY(100%); + } + to { + transform: translateY(0); + } +} + +@keyframes rowPreviewBackdropFadeIn { + from { + opacity: 0; + } + to { + opacity: 1; } } @@ -49,8 +108,8 @@ justify-content: space-between; padding-top: 20px; padding-bottom: 20px; - padding-left: 16px; - padding-right: 16px; + padding-left: 20px; + padding-right: 12px; z-index: 1; } @@ -70,7 +129,7 @@ flex-direction: column; align-items: flex-start; gap: 4px; - padding: 12px 16px; + padding: 12px 20px; } .row-preview-sidebar__field:not(:last-child) { @@ -88,18 +147,20 @@ width: 100%; } -.related-records-panel { - margin-left: 4px; - width: calc(100% - 8px); -} - -.related-records-panel__header { - height: 36px !important; - padding: 0 12px 0 8px; +.related-records-section { + margin: 8px 0 0; + padding: 0 20px; } -.related-records-panel ::ng-deep .mat-expansion-panel-body { +.related-records-section__title { + margin: 0 0 4px !important; padding: 0; + font-size: 12px !important; + font-weight: 600 !important; + line-height: 1.4 !important; + text-transform: uppercase; + letter-spacing: 0.06em; + opacity: 0.6; } .related-records__header { @@ -122,6 +183,16 @@ padding-right: 8px; } +.related-record__open { + color: rgba(0, 0, 0, 0.54); +} + +@media (prefers-color-scheme: dark) { + .related-record__open { + color: rgba(255, 255, 255, 0.7); + } +} + .related-record ::ng-deep .mdc-list-item__primary-text::before { height: 24px; } diff --git a/frontend/src/app/components/dashboard/db-table-view/db-table-row-view/db-table-row-view.component.html b/frontend/src/app/components/dashboard/db-table-view/db-table-row-view/db-table-row-view.component.html index d8a41175c..572a39908 100644 --- a/frontend/src/app/components/dashboard/db-table-view/db-table-row-view/db-table-row-view.component.html +++ b/frontend/src/app/components/dashboard/db-table-view/db-table-row-view/db-table-row-view.component.html @@ -1,6 +1,10 @@ +
+

Preview

@@ -23,10 +27,8 @@

Preview

- - - Related records - +
diff --git a/frontend/src/app/components/dashboard/db-table-view/db-table-row-view/db-table-row-view.component.ts b/frontend/src/app/components/dashboard/db-table-view/db-table-row-view/db-table-row-view.component.ts index 50a96305c..13997e992 100644 --- a/frontend/src/app/components/dashboard/db-table-view/db-table-row-view/db-table-row-view.component.ts +++ b/frontend/src/app/components/dashboard/db-table-view/db-table-row-view/db-table-row-view.component.ts @@ -313,7 +313,7 @@ export class DbTableRowViewComponent implements OnInit, OnDestroy { } showCopyNotification(message: string) { - this._notifications.showSuccessSnackbar(message); + this._notifications.showSuccessSnackbar(message, 'top'); } stashUrlParams() { diff --git a/frontend/src/app/components/dashboard/db-table-view/db-table-view.component.css b/frontend/src/app/components/dashboard/db-table-view/db-table-view.component.css index 13184e2a3..4be4b813f 100644 --- a/frontend/src/app/components/dashboard/db-table-view/db-table-view.component.css +++ b/frontend/src/app/components/dashboard/db-table-view/db-table-view.component.css @@ -2,6 +2,43 @@ display: none; } +.pull-refresh-indicator { + display: none; +} + +@media (width <= 600px) { + .pull-refresh-indicator { + display: flex; + align-items: center; + justify-content: center; + height: 0; + overflow: hidden; + transition: height 150ms ease; + } + + .pull-refresh-indicator__icon { + opacity: 0.6; + transition: transform 100ms linear; + } + + .pull-refresh-indicator__icon_spinning { + animation: pullRefreshSpin 700ms linear infinite; + } + + .refresh-button { + display: none !important; + } +} + +@keyframes pullRefreshSpin { + from { + transform: rotate(0deg); + } + to { + transform: rotate(360deg); + } +} + .db-table-header { display: flex; justify-content: flex-end; @@ -29,6 +66,7 @@ .db-table-title { flex-grow: 1; margin-right: 0; + margin-bottom: 12px; justify-content: space-between; } } @@ -44,27 +82,477 @@ } } +.table-title__settings, +.table-title__ai { + display: none; +} + +.settings-menu__transfer { + display: none !important; +} + +@media (width <= 600px) { + .table-title__ai { + display: inline-flex; + margin-left: auto; + } + + .table-title__settings { + display: inline-flex; + } + + .actions__settings, + .actions__transfer, + .ai-insights-button { + display: none !important; + } + + button.settings-menu__transfer { + display: flex !important; + } + + mat-divider.settings-menu__transfer { + display: block !important; + } +} + .table-switcher { display: none; } @media (width <= 600px) { .table-switcher { - display: initial; - margin-top: 12px; + display: inline-flex; + align-items: center; + padding: 0 4px 0 8px; + line-height: 1.2; + min-height: 40px; + --mdc-text-button-label-text-size: 20px; + --mdc-text-button-label-text-weight: 500; + --mat-text-button-label-text-size: 20px; + --mat-text-button-label-text-weight: 500; + } + + .table-switcher ::ng-deep .mdc-button__label { + font-size: 20px; + font-weight: 500; } + + .table-switcher__name { + max-width: 60vw; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + font-size: 20px; + font-weight: 500; + } + + .table-switcher__chevron { + margin-left: 0 !important; + font-size: 24px; + width: 24px; + height: 24px; + } +} + +.table-sheet-backdrop { + position: fixed; + inset: 0; + background: rgba(0, 0, 0, 0.4); + backdrop-filter: blur(2px); + z-index: 1000; + transform: translateZ(0); + animation: tableSheetFadeIn 200ms ease-out; +} + +.table-sheet { + position: fixed; + left: 0; + right: 0; + bottom: 0; + z-index: 1001; + display: flex; + flex-direction: column; + max-height: 80vh; + background: var(--mat-sidenav-content-background-color, #fff); + border-top-left-radius: 16px; + border-top-right-radius: 16px; + box-shadow: 0 -8px 32px rgba(0, 0, 0, 0.18); + padding-bottom: env(safe-area-inset-bottom, 0px); + transform: translateZ(0); + animation: tableSheetSlideUp 260ms cubic-bezier(0.2, 0.8, 0.2, 1); +} + +.table-sheet__handle { + width: 36px; + height: 4px; + border-radius: 2px; + background: rgba(0, 0, 0, 0.2); + margin: 8px auto 0; + flex: 0 0 auto; +} + +.table-sheet__header { + display: flex; + align-items: center; + justify-content: space-between; + padding: 8px 8px 8px 16px; + flex: 0 0 auto; +} + +.table-sheet__title { + font-size: 16px; + font-weight: 600; +} + +.table-sheet__search { + display: flex; + align-items: center; + gap: 8px; + margin: 0 16px 12px; + padding: 8px 12px; + border-radius: 999px; + background: rgba(0, 0, 0, 0.05); + flex: 0 0 auto; +} + +.table-sheet__search-icon { + font-size: 20px; + width: 20px; + height: 20px; + opacity: 0.55; + flex: 0 0 auto; +} + +.table-sheet__search-input { + flex: 1 1 auto; + min-width: 0; + background: transparent; + border: none; + outline: none; + font-size: 15px; + padding: 2px 0; + color: rgba(0, 0, 0, 0.87); +} + +.table-sheet__search-input::placeholder { + color: rgba(0, 0, 0, 0.45); +} + +.table-sheet__search-clear { + font-size: 18px; + width: 18px; + height: 18px; + opacity: 0.5; + cursor: pointer; + flex: 0 0 auto; +} + +.table-sheet__list { + overflow-y: auto; + padding: 0 8px 12px; + flex: 1 1 auto; + -webkit-overflow-scrolling: touch; } -.table-switcher-option ::ng-deep .mdc-list-item__primary-text { +.table-sheet__group-label { + display: flex; + align-items: center; + gap: 6px; width: 100%; + padding: 10px 12px; + margin-top: 4px; + border: none; + background: transparent; + font-size: 13px; + font-weight: 600; + color: inherit; + cursor: pointer; + text-align: left; } -.table-switcher-link { - display: inline-block; +.table-sheet__group-icon { + font-size: 18px; + width: 18px; + height: 18px; + flex: 0 0 auto; +} + +.table-sheet__group-name { + flex: 0 1 auto; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} + +.table-sheet__group-count { + font-size: 12px; + font-weight: 500; + opacity: 0.5; +} + +.table-sheet__group-chevron { + margin-left: auto; + font-size: 20px; + width: 20px; + height: 20px; + opacity: 0.55; + flex: 0 0 auto; +} + +.table-sheet__item { + display: flex; + align-items: center; + justify-content: space-between; + gap: 8px; + width: 100%; + border: none; + background: transparent; + text-align: left; + padding: 12px; + border-radius: 8px; + font-size: 15px; color: inherit; - line-height: 48px; - text-decoration: none; + cursor: pointer; +} + +.table-sheet__item:active { + background: rgba(0, 0, 0, 0.06); +} + +.table-sheet__item_active { + font-weight: 600; + background: rgba(0, 0, 0, 0.04); +} + +.table-sheet__item-name { + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + margin-right: auto; +} + +.table-sheet__item-icon { + font-size: 22px; + width: 22px; + height: 22px; + flex: 0 0 auto; + margin-right: 12px; + opacity: 0.7; +} + +.table-sheet__item-check { + font-size: 20px; + width: 20px; + height: 20px; + flex: 0 0 auto; + color: var(--color-accentedPalette-600); +} + +.table-sheet__empty { + padding: 24px 16px; + font-size: 14px; + opacity: 0.6; + text-align: center; +} + +.sort-sheet__row { + display: flex; + align-items: center; + justify-content: space-between; + gap: 8px; width: 100%; + padding: 12px; + border: none; + background: transparent; + border-radius: 8px; + cursor: pointer; + text-align: left; + color: inherit; + font: inherit; +} + +.sort-sheet__row_expanded { + background: rgba(0, 0, 0, 0.04); +} + +.sort-sheet__col-name { + flex: 1 1 auto; + min-width: 0; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + font-size: 15px; +} + +.sort-sheet__row-indicator { + flex: 0 0 auto; + font-size: 20px; + width: 20px; + height: 20px; + opacity: 0.5; +} + +.sort-sheet__options { + display: flex; + flex-direction: column; + gap: 2px; + padding: 2px 8px 10px 8px; +} + +.sort-sheet__opt { + display: flex; + align-items: center; + gap: 10px; + width: 100%; + border: none; + background: transparent; + text-align: left; + padding: 10px 12px; + border-radius: 8px; + font-size: 14px; + color: inherit; + cursor: pointer; + opacity: 0.85; +} + +.sort-sheet__opt .mat-icon { + font-size: 20px; + width: 20px; + height: 20px; + flex: 0 0 auto; + opacity: 0.7; +} + +.sort-sheet__opt:active { + background: rgba(0, 0, 0, 0.06); +} + +.sort-sheet__opt:disabled { + opacity: 0.35; + cursor: default; +} + +.sort-sheet__opt_active { + opacity: 1; + font-weight: 600; + color: var(--color-accentedPalette-700); + background: var(--color-accentedPalette-50); +} + +.sort-sheet__opt_active .mat-icon { + opacity: 1; + color: var(--color-accentedPalette-700); +} + +@media (prefers-color-scheme: dark) { + .sort-sheet__row_expanded { + background: rgba(255, 255, 255, 0.06); + } + + .sort-sheet__opt:active { + background: rgba(255, 255, 255, 0.08); + } + + .sort-sheet__opt_active { + background: var(--color-accentedPalette-900); + color: var(--color-accentedPalette-100); + } + + .sort-sheet__opt_active .mat-icon { + color: var(--color-accentedPalette-200); + } +} + +.columns-sheet__list { + display: flex; + flex-direction: column; +} + +.columns-sheet__item { + display: flex; + align-items: center; + gap: 8px; + padding: 6px 12px; + border-radius: 8px; + background: var(--mat-sidenav-content-background-color, #fff); +} + +.columns-sheet__item.cdk-drag-preview { + box-shadow: 0 4px 16px rgba(0, 0, 0, 0.2); +} + +.columns-sheet__item.cdk-drag-placeholder { + opacity: 0.3; +} + +.columns-sheet__drag-handle { + color: rgba(0, 0, 0, 0.4); + cursor: grab; + flex: 0 0 auto; +} + +.columns-sheet__checkbox { + flex: 1 1 auto; + min-width: 0; +} + +@media (prefers-color-scheme: dark) { + .columns-sheet__item { + background: var(--surface-dark-color); + } + + .columns-sheet__drag-handle { + color: rgba(255, 255, 255, 0.5); + } +} + +@keyframes tableSheetSlideUp { + from { + transform: translateY(100%); + } + to { + transform: translateY(0); + } +} + +@keyframes tableSheetFadeIn { + from { + opacity: 0; + } + to { + opacity: 1; + } +} + +@media (prefers-color-scheme: dark) { + .table-sheet { + background: var(--surface-dark-color); + } + + .table-sheet__handle { + background: rgba(255, 255, 255, 0.24); + } + + .table-sheet__search { + background: rgba(255, 255, 255, 0.08); + } + + .table-sheet__search-input { + color: rgba(255, 255, 255, 0.87); + } + + .table-sheet__search-input::placeholder { + color: rgba(255, 255, 255, 0.5); + } + + .table-sheet__item:active { + background: rgba(255, 255, 255, 0.08); + } + + .table-sheet__item_active { + background: rgba(255, 255, 255, 0.08); + } } .db-table-bulk-actions { @@ -75,7 +563,9 @@ @media (width <= 600px) { .db-table-bulk-actions { - height: 124px; + height: auto; + min-height: 48px; + padding: 8px 0; } } @@ -111,6 +601,134 @@ padding: 8px; } +.search-input__icon { + opacity: 0.6; +} + +.search-row { + display: contents; +} + +.search-row__buttons { + display: contents; +} + +.search-row__filter { + display: none; +} + +.add-row-fab { + display: none; +} + +@media (width <= 600px) { + .add-row-fab { + display: inline-flex; + position: fixed; + right: 16px; + bottom: calc(16px + env(safe-area-inset-bottom, 0px)); + z-index: 50; + } +} + +.saved-filters-row__columns { + display: none; +} + +@media (width <= 600px) { + .search-row { + display: flex; + flex-direction: column; + align-items: flex-start; + gap: 8px; + width: 100%; + } + + .search-form { + display: flex; + align-items: center; + width: 100%; + height: 40px; + border-radius: 999px; + background: rgba(0, 0, 0, 0.06); + overflow: hidden; + } + + .search-row__buttons { + display: flex; + align-items: center; + gap: 8px; + width: 100%; + } + + .search-row__filter { + display: inline-flex; + flex: 0 0 auto; + height: 32px; + line-height: 32px; + padding: 0 12px; + border-radius: 999px; + font-size: 13px; + } + + .search-row__filter .mat-icon { + font-size: 18px; + width: 18px; + height: 18px; + } + + .saved-filters-row__columns { + display: inline-flex; + flex: 0 0 auto; + } + + .actions__filter, + .actions__add-row, + .db-table-manage-columns-button { + display: none !important; + } + + .search-input { + width: 100%; + min-width: 0; + height: 40px; + background: transparent !important; + } + + .search-input ::ng-deep .mat-mdc-text-field-wrapper { + background: transparent !important; + padding: 0 8px 0 4px; + height: 40px; + } + + .search-input ::ng-deep .mdc-line-ripple, + .search-input ::ng-deep .mat-mdc-form-field-subscript-wrapper { + display: none; + } + + .search-input__icon { + font-size: 22px; + width: 22px; + height: 22px; + opacity: 0.55; + } + + .search-input ::ng-deep input.mat-mdc-input-element { + font-size: 14px; + } +} + +@media (prefers-color-scheme: dark) and (width <= 600px) { + .search-form { + background: rgba(255, 255, 255, 0.08); + } + + .search-form:focus-within, + .search-form_filled { + background: rgba(255, 255, 255, 0.05); + } +} + .db-table-actions { flex-grow: 1; display: flex; @@ -133,11 +751,105 @@ margin-top: -16px; } +.saved-filters-row { + display: contents; +} + +.mobile-sort-button { + display: none !important; +} + +.saved-filters-row__mobile-actions { + display: none; +} + @media (width <= 600px) { - .actions { - flex-wrap: wrap; + .saved-filters-row { + display: flex; + flex-direction: column; + align-items: flex-start; gap: 8px; } + + .saved-filters-row > app-saved-filters-panel { + flex: 0 1 auto; + min-width: 0; + display: block; + } + + .saved-filters-row__mobile-actions { + display: flex; + align-items: center; + justify-content: flex-end; + /* grow to fill the row so the buttons sit on the far right; panel keeps its natural width to avoid overlapping .saved-filters-trigger_active */ + flex: 1 1 auto; + min-width: 0; + width: 100%; + margin-bottom: -44px; + } + + .mobile-sort-button { + display: inline-flex !important; + align-items: center; + flex: 0 0 auto; + min-height: 36px; + padding: 0 4px; + font-size: 13px; + font-weight: 500; + } + + .saved-filters-row__columns { + display: inline-flex !important; + align-items: center; + justify-content: center; + flex: 0 0 auto; + } + + .mobile-sort-button__label { + white-space: nowrap; + } + + .mobile-sort-button_active { + color: var(--color-accentedPalette-700); + } + + .actions { + flex-wrap: nowrap; + gap: 0; + width: 100%; + justify-content: flex-end; + margin-top: 0; + } + + .actions .action-label { + display: none; + } + + .actions .db-table-manage-columns-button__count { + display: none; + } + + .actions .mat-mdc-button { + --mdc-text-button-container-height: 40px; + min-width: 40px; + padding: 0 8px; + } + + .actions .mat-mdc-button .mat-icon { + margin: 0 !important; + } + + .ai-insights-button { + margin-left: 0; + } +} + +@media (prefers-color-scheme: dark) and (width <= 600px) { + .mobile-sort-button_active { + background: var(--color-accentedPalette-900); + border-color: var(--color-accentedPalette-600) !important; + color: var(--color-accentedPalette-100); + } } .action_active { @@ -205,6 +917,13 @@ margin-bottom: 12px; } +@media (width <= 600px) { + .active-filters { + margin-top: -12px; + margin-bottom: 16px; + } +} + ::ng-deep .active-filters .mat-mdc-chip { --mdc-chip-container-color: #e8ecee !important; --mdc-chip-elevated-container-color: #e8ecee !important; @@ -268,14 +987,6 @@ } } -.active-filters { - display: flex; - align-items: center; - flex-wrap: wrap; - gap: 8px; - margin-bottom: 12px; -} - .db-table-active-filter-chip ::ng-deep .mdc-evolution-chip__text-label { max-width: 300px; overflow: hidden; @@ -329,12 +1040,29 @@ @media (width <= 600px) { .db-table { grid-template-columns: minmax(0, 120px) 1fr !important; + grid-row-gap: 8px; + background: transparent !important; } .db-table ::ng-deep tbody { display: grid; grid-template-columns: subgrid; grid-column: 1 / 3; + row-gap: 16px; + background: transparent; + } + + .table-surface { + background: transparent !important; + box-shadow: none !important; + } + + .table-surface ::ng-deep mat-paginator { + margin-top: 20px; + } + + .table-box { + background: transparent; } } @@ -401,12 +1129,11 @@ display: grid; grid-template-columns: subgrid; grid-column: 1 / 3; - grid-gap: 12px 28px; - border-bottom-color: var(--mat-table-row-item-outline-color, rgba(0, 0, 0, 0.12)); - border-bottom-width: var(--mat-table-row-item-outline-width, 1px); - border-bottom-style: solid; + grid-gap: 2px 12px; + border: 1px solid var(--mat-table-row-item-outline-color, rgba(0, 0, 0, 0.12)) !important; + border-radius: 10px; height: auto; - padding: 8px 0; + padding: 8px 8px 8px 16px; } .db-table-header-row { @@ -429,18 +1156,33 @@ display: grid; grid-template-columns: subgrid; grid-column: 1 / 3; - align-items: flex-start; + align-items: center; + border-bottom: 1px dashed rgba(0, 0, 0, 0.12); + padding-left: 0 !important; + padding-right: 0 !important; + padding-top: 0; + padding-bottom: 0; + } + + .db-table-cell:not(:has(~ .db-table-cell)) { border-bottom: none; } .db-table-cell::before { content: attr(data-label); display: inline-block; - font-weight: bold; + font-weight: 500; + font-size: 12px; white-space: wrap; } } +@media (prefers-color-scheme: dark) and (width <= 600px) { + .db-table-cell { + border-bottom-color: rgba(255, 255, 255, 0.12); + } +} + .db-table ::ng-deep .db-table-cell:first-of-type, .db-table ::ng-deep .mat-mdc-header-cell:first-of-type, .db-table ::ng-deep .mat-mdc-footer-cell:first-of-type { @@ -452,7 +1194,8 @@ .db-table ::ng-deep .db-table-cell:first-of-type, .db-table ::ng-deep .mat-mdc-header-cell:first-of-type, .db-table ::ng-deep .mat-mdc-footer-cell:first-of-type { - border-bottom: none; + padding-left: 0; + margin-top: 4px; } /* .db-table-cell { @@ -620,7 +1363,7 @@ td.mat-cell { } .db-table-checkbox { - transform: scale(1.25); + transform: scale(1.1); } .db-table-cell-actions { @@ -630,6 +1373,26 @@ td.mat-cell { gap: 4px; border-bottom: none; padding-left: 40px; + padding-right: 0 !important; + margin-right: -8px; + color: rgba(0, 0, 0, 0.87); + } + + .db-table-cell-action-button { + --mat-icon-button-state-layer-size: 36px !important; + --mat-icon-button-icon-size: 22px !important; + } + + .db-table-cell-action-button ::ng-deep .mat-icon { + font-size: 22px; + height: 22px; + width: 22px; + } +} + +@media (prefers-color-scheme: dark) and (width <= 600px) { + .db-table-cell-actions { + color: rgba(255, 255, 255, 0.87); } } @@ -720,6 +1483,47 @@ tr.mat-row:hover { width: 100%; } +.empty-table__icon { + font-size: 32px; + width: 32px; + height: 32px; + margin-bottom: 8px; + opacity: 0.5; +} + +.bulk-actions__select-all { + display: none !important; +} + +@media (width <= 600px) { + .bulk-actions__select-all { + display: inline-flex !important; + } +} + +@media (width <= 600px) { + .empty-table { + align-items: center; + padding: 24px 16px; + border: 1px solid var(--mat-table-row-item-outline-color, rgba(0, 0, 0, 0.12)); + border-radius: 10px; + background: transparent; + margin: 0; + text-align: center; + } + + .empty-table .mat-body-1 { + margin: 0; + padding: 0 4px; + } + + .empty-table .mat-button { + margin-top: 12px; + width: auto; + border-radius: 999px; + } +} + .hidden { display: none; } diff --git a/frontend/src/app/components/dashboard/db-table-view/db-table-view.component.html b/frontend/src/app/components/dashboard/db-table-view/db-table-view.component.html index 7670a1746..5bedbdcb0 100644 --- a/frontend/src/app/components/dashboard/db-table-view/db-table-view.component.html +++ b/frontend/src/app/components/dashboard/db-table-view/db-table-view.component.html @@ -1,31 +1,56 @@ +
+ + refresh + +
+

{{ displayName }}

- - Table - - - - - {{table.normalizedTableName || table.display_name || table.table}} - - - - - - {{table.normalizedTableName || table.display_name || table.table}} - - - - - - + + + + + +
+
- - - - + + +
+ - - +
+

angularticsAction="Dashboard: AI is clicked" (click)="handleViewAIpanel(); posthog.capture('Dashboard: AI is clicked')"> - AI insights + AI insights - - add - Add row + add + Add row +
-
- - - UI Widgets - - - Automations -
- - Primary keys are required. - -
- - Settings - -
+ + + + UI Widgets + + + Automations +
+ + Primary keys are required. + +
+ + Settings + + + + + +
+ + add + Add row + +
{{ displayName }}
- +
+
+ + + +
+ + +
@@ -235,7 +337,8 @@

{{ displayName }}

[aria-label]="checkboxLabel()"> - + {{ displayName }} - +
{{ displayName }} Actions - +
-
-

No field matches this filter.

+
+ filter_list_off +

+ {{ hasSavedFilterActive ? 'No records match the selected fast filter.' : 'No records match this filter.' }} +

-
+ + + +
+
+ +
+ Select table + +
+ + + +
+ + + + + + + +
Others
+ +
+ +
+ No tables match "{{ tableSwitcherSearch }}". +
+
+
+ + +
+
+ +
+ Sort by + +
+ +
+ + + +
+ + + +
+
+
+
+ + +
+
+ +
+ Columns + +
+ +
+
+
+ drag_indicator + + {{ column.normalizedTitle }} + +
+
+
+
+ + +
+
+ +
+ Import / Export + +
+ +
+ + +
+
diff --git a/frontend/src/app/components/dashboard/db-table-view/db-table-view.component.ts b/frontend/src/app/components/dashboard/db-table-view/db-table-view.component.ts index 9212f7d09..359a875e2 100644 --- a/frontend/src/app/components/dashboard/db-table-view/db-table-view.component.ts +++ b/frontend/src/app/components/dashboard/db-table-view/db-table-view.component.ts @@ -7,6 +7,7 @@ import { Component, computed, EventEmitter, + HostListener, Input, inject, OnChanges, @@ -311,6 +312,8 @@ export class DbTableViewComponent implements OnInit, OnChanges { return this.tableFolders?.find((cat) => cat.category_id === null)?.tables || []; } + public tableSwitcherSearch: string = ''; + get tableFoldersForSelect(): TableCategory[] { if (!this.tableFolders) return []; return this.tableFolders.filter((cat) => cat.category_id !== null); @@ -324,6 +327,105 @@ export class DbTableViewComponent implements OnInit, OnChanges { return this.allTables.filter((t) => !tablesInFolders.has(t.table)); } + get filteredTableFoldersForSelect(): TableCategory[] { + const query = this.tableSwitcherSearch.trim().toLowerCase(); + if (!query) return this.tableFoldersForSelect; + return this.tableFoldersForSelect + .map((folder) => ({ + ...folder, + tables: (folder.tables || []).filter((t) => this._matchesTableQuery(t, query)), + })) + .filter((folder) => folder.tables.length > 0); + } + + get filteredUncategorizedTables(): TableProperties[] { + const query = this.tableSwitcherSearch.trim().toLowerCase(); + if (!query) return this.uncategorizedTables; + return this.uncategorizedTables.filter((t) => this._matchesTableQuery(t, query)); + } + + @ViewChild('tableSwitcherSearchInput') + tableSwitcherSearchInputRef?: { nativeElement: HTMLInputElement }; + + public tableSwitcherOpen = false; + public collapsedFolders = new Set(); + public sortSheetOpen = false; + public sortExpandedColumn: string | null = null; + public columnsSheetOpen = false; + + get isMobileView(): boolean { + return typeof window !== 'undefined' && window.innerWidth <= 600; + } + + openSortSheet() { + this.sortSheetOpen = true; + } + + closeSortSheet() { + this.sortSheetOpen = false; + this.sortExpandedColumn = null; + } + + toggleSortColumn(column: string) { + this.sortExpandedColumn = this.sortExpandedColumn === column ? null : column; + } + + openColumnsSheet() { + this.columnsSheetOpen = true; + } + + closeColumnsSheet() { + this.columnsSheetOpen = false; + } + + public transferSheetOpen = false; + + openTransferSheet() { + this.transferSheetOpen = true; + } + + closeTransferSheet() { + this.transferSheetOpen = false; + } + + get sortableDataColumns(): string[] { + return (this.tableData?.displayedDataColumns || []).filter((c: string) => this.isSortable(c)); + } + + clearTableSwitcherSearch() { + this.tableSwitcherSearch = ''; + } + + toggleFolderCollapse(folderId: string) { + if (this.collapsedFolders.has(folderId)) { + this.collapsedFolders.delete(folderId); + } else { + this.collapsedFolders.add(folderId); + } + } + + isFolderCollapsed(folderId: string): boolean { + if (this.tableSwitcherSearch.trim()) return false; + return this.collapsedFolders.has(folderId); + } + + openTableSwitcher() { + this.tableSwitcherOpen = true; + setTimeout(() => { + this.tableSwitcherSearchInputRef?.nativeElement.focus(); + }, 50); + } + + closeTableSwitcher() { + this.tableSwitcherOpen = false; + this.clearTableSwitcherSearch(); + } + + switchTableFromSheet(tableName: string) { + this.closeTableSwitcher(); + this.switchTable(tableName); + } + loadRowsPage() { this.tableRelatedRecords = null; this.tableData.fetchRows({ @@ -339,6 +441,49 @@ export class DbTableViewComponent implements OnInit, OnChanges { }); } + public pullDistance = 0; + public pullRefreshing = false; + private _pullStartY = 0; + private _pullTracking = false; + private readonly _pullThreshold = 70; + + @HostListener('touchstart', ['$event']) + onPullTouchStart(event: TouchEvent) { + if (!this.isMobileView || this.pullRefreshing) return; + const scrollTop = window.scrollY || document.documentElement.scrollTop || 0; + if (scrollTop > 0) return; + this._pullStartY = event.touches[0].clientY; + this._pullTracking = true; + } + + @HostListener('touchmove', ['$event']) + onPullTouchMove(event: TouchEvent) { + if (!this._pullTracking || this.pullRefreshing) return; + const delta = event.touches[0].clientY - this._pullStartY; + if (delta <= 0) { + this.pullDistance = 0; + return; + } + this.pullDistance = Math.min(delta * 0.5, this._pullThreshold + 20); + } + + @HostListener('touchend') + onPullTouchEnd() { + if (!this._pullTracking) return; + this._pullTracking = false; + if (this.pullDistance >= this._pullThreshold) { + this.pullRefreshing = true; + this.pullDistance = this._pullThreshold; + this.loadRowsPage(); + setTimeout(() => { + this.pullRefreshing = false; + this.pullDistance = 0; + }, 800); + } else { + this.pullDistance = 0; + } + } + isSortable(column: string) { return this.tableData.sortByColumns.includes(column) || !this.tableData.sortByColumns.length; } @@ -926,4 +1071,16 @@ export class DbTableViewComponent implements OnInit, OnChanges { return rid ? this._permissions.canI(action, 'Table', rid)() : null; }); } + + private _matchesTableQuery(table: TableProperties, query: string): boolean { + const haystack = [ + (table as any).normalizedTableName, + table.display_name, + table.table, + ] + .filter(Boolean) + .join(' ') + .toLowerCase(); + return haystack.includes(query); + } } diff --git a/frontend/src/app/components/dashboard/db-table-view/saved-filters-panel/saved-filters-dialog/saved-filters-dialog.component.css b/frontend/src/app/components/dashboard/db-table-view/saved-filters-panel/saved-filters-dialog/saved-filters-dialog.component.css index 8b45b57f1..0bae5269f 100644 --- a/frontend/src/app/components/dashboard/db-table-view/saved-filters-panel/saved-filters-dialog/saved-filters-dialog.component.css +++ b/frontend/src/app/components/dashboard/db-table-view/saved-filters-panel/saved-filters-dialog/saved-filters-dialog.component.css @@ -555,9 +555,32 @@ } .filters-form { - flex: 1 0 auto; + flex: 1 1 auto; display: flex; flex-direction: column; + min-height: 0; +} + +.filters-content { + flex: 1 1 auto; + min-height: 0; + overflow-y: auto; +} + +::ng-deep .filters-form mat-dialog-actions { + flex: 0 0 auto; + position: sticky; + bottom: 0; + background: var(--mat-dialog-container-color, #fff); + z-index: 2; + border-top: 1px solid rgba(0, 0, 0, 0.08); +} + +@media (prefers-color-scheme: dark) { + ::ng-deep .filters-form mat-dialog-actions { + background: var(--mat-sidenav-content-background-color); + border-top-color: rgba(255, 255, 255, 0.08); + } } .filters-header-description { @@ -628,6 +651,323 @@ line-height: 18px; } +.filters-header { + margin-top: 16px; + margin-bottom: 12px; + min-height: 0 !important; + line-height: 1.2 !important; +} + +.condition-card { + grid-column: 1 / -1; + display: flex; + flex-direction: column; + gap: 8px; + padding: 12px 0; + border-bottom: 1px dashed rgba(0, 0, 0, 0.12); +} + +.condition-card:last-of-type { + border-bottom: none; +} + +@media (prefers-color-scheme: dark) { + .condition-card { + border-bottom-color: rgba(255, 255, 255, 0.12); + } +} + +.condition-card__header { + display: flex; + align-items: center; + justify-content: space-between; + gap: 8px; +} + +.condition-card__column-name { + font-size: 12px; + font-weight: 600; + opacity: 0.6; +} + +.condition-card .filter-delete-button { + grid-column: auto !important; + margin: 0 !important; + width: 32px !important; + height: 32px !important; + flex: 0 0 32px; + opacity: 0.7; +} + +.condition-card .filter-delete-button:hover { + opacity: 1; +} + +.condition-card .filter-delete-button ::ng-deep .mat-icon { + font-size: 18px; + width: 18px; + height: 18px; + line-height: 18px; +} + +.condition-card__inputs { + display: flex; + gap: 4px; + align-items: flex-start; + flex-wrap: wrap; +} + +.condition-card__inputs ::ng-deep .mat-mdc-form-field:not(.comparator-select-field) .mat-mdc-text-field-wrapper { + padding-left: 12px !important; + padding-right: 12px !important; +} + +.condition-card__inputs ::ng-deep .mat-mdc-form-field-subscript-wrapper { + display: none; +} + +.condition-card__inputs > * { + flex: 1 1 0; + min-width: 0; +} + +.condition-card__inputs > .comparator-select-field { + flex: 0 0 auto; +} + +/* ndc-dynamic renders the component as a sibling and leaves an empty anchor element behind; keep it from taking up flex space */ +.condition-card__inputs > ndc-dynamic { + flex: 0 0 auto; + width: auto; +} + +/* the actual component is rendered as the sibling right after the anchor; let it (and its host child) fill the available space */ +.condition-card__inputs > ndc-dynamic + *, +.condition-card__inputs ::ng-deep ndc-dynamic + * { + flex: 1 1 0; + width: 100%; + min-width: 0; +} + +.comparator-trigger__symbol { + display: none; +} + +.comparator-trigger__text { + display: inline; +} + +@media (width <= 600px) { + .condition-card__inputs > .comparator-select-field { + flex: 0 0 56px !important; + } + + .comparator-trigger__symbol { + display: inline; + } + + .comparator-trigger__text { + display: none; + } +} + +.condition-card__value { + display: flex; + min-width: 0; + flex: 1 1 0; +} + +.condition-card__value > *, +.condition-card__value ::ng-deep .mat-mdc-form-field { + flex: 1 1 auto; + width: 100%; + min-width: 0; +} + +/* ndc-dynamic renders the component as a sibling and leaves an empty anchor element behind; keep it from taking up flex space */ +.condition-card__value > ndc-dynamic { + flex: 0 0 auto; + width: auto; +} + +/* the actual component is rendered as the sibling right after the anchor; let it (and its host child) fill the available space */ +.condition-card__value > ndc-dynamic + *, +.condition-card__value ::ng-deep ndc-dynamic + * { + flex: 1 1 0; + width: 100%; + min-width: 0; +} + +.condition-card__value ::ng-deep .full-width { + width: 100%; +} + +.condition-card__inputs .comparator-select-field { + flex: 0 0 auto; +} + +@media (width <= 600px) { + .condition-card__inputs .comparator-select-field { + flex: 0 0 56px !important; + width: 56px !important; + max-width: 56px !important; + min-width: 0 !important; + } + + .condition-card__inputs .comparator-select-field ::ng-deep .mat-mdc-text-field-wrapper { + width: 56px !important; + min-width: 0 !important; + padding-left: 8px !important; + padding-right: 4px !important; + } +} + +@media (width <= 600px) { + .condition-card__inputs .comparator-select-field ::ng-deep .mat-mdc-form-field-flex { + min-width: 0 !important; + } + + .condition-card__inputs .comparator-select-field ::ng-deep .mat-mdc-form-field-infix { + min-width: 0 !important; + width: auto !important; + padding-left: 0 !important; + padding-right: 0 !important; + } + + .condition-card__inputs .comparator-select-field ::ng-deep .mat-mdc-select-arrow-wrapper { + padding-left: 0; + } +} + +.condition-card__inputs .comparator-select-field ::ng-deep .mat-mdc-form-field-subscript-wrapper { + display: none !important; +} + +.condition-card__footer { + display: flex; + align-items: center; + justify-content: space-between; + gap: 8px; + padding-top: 4px; +} + +.condition-card__editable-label { + font-size: 12px; + opacity: 0.65; +} + +.condition-card__help-icon { + font-size: 16px; + width: 16px; + height: 16px; + cursor: pointer; + opacity: 0.5; + margin-right: auto; +} + +.condition-card__help-icon:hover { + opacity: 0.85; +} + +.condition-card .quick-edit-toggle { + flex: 0 0 auto; +} + +.filters-header::before { + height: 0 !important; + content: none !important; +} + +.filters-header__text { + display: flex; + flex-direction: column; + align-items: flex-start; + gap: 2px; + line-height: 1.2; + text-align: left; +} + +.filters-header__label { + font-size: 18px; + font-weight: 600; +} + +.filters-header__table { + font-size: 12px; + font-weight: 500; + opacity: 0.6; +} + +@media (width <= 600px) { + .filters-content { + grid-template-columns: 32px 1fr auto !important; + grid-row-gap: 0 !important; + align-items: start !important; + padding-left: 12px !important; + padding-right: 12px !important; + } + + .filters-select { + grid-column: 1 / -1 !important; + } + + .filter-line { + grid-column: 2 / span 2 !important; + flex-direction: column; + gap: 4px; + padding-right: 0; + } + + .filter-line > .column-name { + font-size: 12px; + font-weight: 600; + opacity: 0.6; + margin: 0; + flex: 1 1 100%; + align-self: flex-start; + } + + .filter-line > div, + .filter-line > ndc-dynamic, + .filter-line > ng-template { + flex: 1 1 100%; + width: 100%; + } + + .column-name { + font-size: 12px !important; + font-weight: 600 !important; + opacity: 0.6; + margin-top: 0 !important; + } + + .empty-conditions-container, + .add-condition-container { + grid-column: 1 / -1 !important; + } + + .filter-delete-button { + grid-column: 1 !important; + margin: 0 !important; + align-self: start !important; + } + + .quick-edit-toggle { + grid-column: 1 / -1 !important; + justify-self: flex-end; + margin: 0 0 12px !important; + align-self: start !important; + } + + .filter-line ::ng-deep .mat-mdc-form-field-subscript-wrapper { + display: none; + } + + .conditions-vertical-line { + display: none !important; + } +} + .settings-form__reset-button { margin-right: auto; } @@ -688,6 +1028,10 @@ pointer-events: none; } +.comparator-select-field ::ng-deep .mat-mdc-select-value { + padding-right: 24px; +} + .comparator-select-field ::ng-deep .mat-mdc-select-panel { min-width: max-content !important; width: max-content !important; diff --git a/frontend/src/app/components/dashboard/db-table-view/saved-filters-panel/saved-filters-dialog/saved-filters-dialog.component.html b/frontend/src/app/components/dashboard/db-table-view/saved-filters-panel/saved-filters-dialog/saved-filters-dialog.component.html index 61e176ecb..da9f2ddc2 100644 --- a/frontend/src/app/components/dashboard/db-table-view/saved-filters-panel/saved-filters-dialog/saved-filters-dialog.component.html +++ b/frontend/src/app/components/dashboard/db-table-view/saved-filters-panel/saved-filters-dialog/saved-filters-dialog.component.html @@ -1,6 +1,9 @@

- New fast filter for {{ data.displayTableName }} + + {{ data.filtersSet.id ? 'Edit fast filter' : 'New fast filter' }} + Table: {{ data.displayTableName }} +

Use conditions to quickly filter {{ data.displayTableName.toLowerCase() }} and optionally edit one column. @@ -49,170 +52,190 @@

subdirectory_arrow_right where

-
- Quick edit - - info_outline - - -
-

Enable to change this value
directly from the table view

-
-
-
-
-
+ +
+

Enable to change this value
directly from the table view

+
+
+
+
-
-
- status = active -
-
- status: - - - | - -
+
+
+
+ status = active +
+
+ status: + + + | +
- -
+
+
-
- - -
- {{value.key}} +
+
+ {{value.key}} + +
-
- -
+
+ + + + - - - -
+ + + + - - {{value.key}} + + + + + + {{ {startswith: 'a…', endswith: '…a', eq: '=', contains: '∋', icontains: '∌', empty: '∅'}[tableRowFieldsComparator[value.key]] || tableRowFieldsComparator[value.key] }} + + + {{ {startswith: 'starts with', endswith: 'ends with', eq: 'equal', contains: 'contains', icontains: 'not contains', empty: 'is empty'}[tableRowFieldsComparator[value.key]] || tableRowFieldsComparator[value.key] }} + + + + play_arrow + starts with + + + play_arrow + ends with + + + drag_handle + equal + + + search + contains + + + block + not contains + + + space_bar + is empty + + + - - - - play_arrow - starts with - - - play_arrow - ends with - - - drag_handle - equal - - - search - contains - - - block - not contains - - - space_bar - is empty - - - + + + + + {{ {eq: '=', gt: '>', lt: '<', gte: '≥', lte: '≤'}[tableRowFieldsComparator[value.key]] || tableRowFieldsComparator[value.key] }} + + + {{ {eq: 'equal', gt: 'greater than', lt: 'less than', gte: 'greater than or equal', lte: 'less than or equal'}[tableRowFieldsComparator[value.key]] || tableRowFieldsComparator[value.key] }} + + + + drag_handle + equal + + + keyboard_arrow_right + greater than + + + keyboard_arrow_left + less than + + + keyboard_double_arrow_right + greater than or equal + + + keyboard_double_arrow_left + less than or equal + + + - - - - drag_handle - equal - - - keyboard_arrow_right - greater than - - - keyboard_arrow_left - less than - - - keyboard_double_arrow_right - greater than or equal - - - keyboard_double_arrow_left - less than or equal - - - +
+ +
+
+
- - - - - + +
diff --git a/frontend/src/app/components/dashboard/db-table-view/saved-filters-panel/saved-filters-panel.component.css b/frontend/src/app/components/dashboard/db-table-view/saved-filters-panel/saved-filters-panel.component.css index 594bd81ef..2180b4c10 100644 --- a/frontend/src/app/components/dashboard/db-table-view/saved-filters-panel/saved-filters-panel.component.css +++ b/frontend/src/app/components/dashboard/db-table-view/saved-filters-panel/saved-filters-panel.component.css @@ -1,11 +1,13 @@ .saved-filters-container { display: flex; flex-direction: column; + min-width: 0; + max-width: 100%; } .saved-filters-list { display: flex; - align-items: center; + align-items: flex-start; gap: 16px; margin-bottom: 12px; } @@ -14,7 +16,145 @@ transition: background 0.3s ease; } -.create-filter-button { +.saved-filters-trigger { + display: none; + align-items: center; + gap: 6px; + border-radius: 999px; + padding: 0 8px 0 12px; + min-height: 36px; +} + +@media (width <= 600px) { + .saved-filters-trigger { + display: inline-flex; + } + + .saved-filters-trigger_active { + width: calc(100vw - 130px - 2*24px); + box-sizing: border-box; + } + + /* let the button's label shrink and ellipsis when it can't fit into calc(100% - 130px) */ + .saved-filters-trigger_active ::ng-deep .mdc-button__label { + display: flex; + align-items: center; + min-width: 0; + overflow: hidden; + } + + .saved-filters-trigger_active .saved-filters-trigger__label { + max-width: none; + min-width: 0; + flex: 1 1 auto; + } + + .create-filter-button, + .saved-filters-tabs { + display: none !important; + } +} + +.saved-filters-trigger__label { + max-width: 200px; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} + +.saved-filters-trigger__chevron { + margin-left: 0 !important; +} + +@media (prefers-color-scheme: light) { + .saved-filters-trigger_active { + background: var(--color-accentedPalette-50); + border-color: var(--color-accentedPalette-300) !important; + color: var(--color-accentedPalette-700); + } + + .saved-filters-trigger_active .saved-filters-trigger__icon { + color: var(--color-accentedPalette-700); + } +} + +@media (prefers-color-scheme: dark) { + .saved-filters-trigger_active { + background: var(--color-accentedPalette-900); + border-color: var(--color-accentedPalette-600) !important; + color: var(--color-accentedPalette-100); + } + + .saved-filters-trigger_active .saved-filters-trigger__icon { + color: var(--color-accentedPalette-200); + } +} + +.saved-filters-menu__check { + color: var(--color-accentedPalette-600); + visibility: hidden; + flex-shrink: 0; +} + +.saved-filters-menu__check_visible { + visibility: visible; +} + +.saved-filters-menu__item_active .saved-filters-menu__name { + font-weight: 600; +} + +::ng-deep .saved-filters-menu .mat-mdc-menu-item .mat-mdc-menu-item-text { + display: inline-flex; + align-items: center; + width: 100%; + gap: 8px; +} + +.saved-filters-menu__name { + flex: 1 1 auto; + display: inline-flex; + align-items: center; +} + +.saved-filters-menu__row-menu { + display: inline-flex; + align-items: center; + justify-content: center; + width: 32px; + height: 32px; + margin-left: auto; + margin-right: -8px; + border-radius: 50%; + cursor: pointer; + flex-shrink: 0; +} + +.saved-filters-menu__row-menu .mat-icon { + margin: 0 !important; + width: 20px; + height: 20px; + font-size: 20px; +} + +.saved-filters-menu__row-menu:hover { + background: rgba(0, 0, 0, 0.06); +} + +@media (prefers-color-scheme: dark) { + .saved-filters-menu__row-menu:hover { + background: rgba(255, 255, 255, 0.08); + } +} + +.saved-filters-menu__create { + border-top: 1px solid rgba(0, 0, 0, 0.08); +} + +@media (prefers-color-scheme: dark) { + .saved-filters-menu__create { + border-top-color: rgba(255, 255, 255, 0.08); + } } @media (prefers-color-scheme: light) { @@ -176,8 +316,107 @@ @media (width <= 600px) { .filters-container { - flex-direction: column; + align-items: center; + flex-direction: row; + flex-wrap: wrap; + gap: 6px; + margin-top: 0; + margin-bottom: 16px; + padding: 8px 16px; + border-radius: 10px; + background: rgba(0, 0, 0, 0.03); transform: none; + max-width: 100%; + min-width: 0; + overflow-x: clip; + overflow-y: visible; + } + + + .dynamic-column-editor { + flex: 1 1 100%; + flex-direction: row; + align-items: center; + flex-wrap: wrap; + gap: 6px; + min-width: 0; + } + + .dynamic-column-editor > * { + min-width: 0; + } + + .dynamic-column-editor ::ng-deep .mat-mdc-form-field, + .dynamic-column-editor ::ng-deep .foreign-key { + flex: 1 1 100%; + } + + .dynamic-column-editor .column-name { + flex: 1 1 100%; + font-size: 12px; + line-height: 1.3; + gap: 6px; + margin: 0; + opacity: 0.6; + font-weight: 600; + white-space: nowrap; + } + + .dynamic-column-editor .column-name strong { + margin-left: 0; + font-size: 12px; + font-weight: 600; + color: inherit; + text-transform: none; + } + + .dynamic-column-editor .comparator-text { + display: inline-flex; + align-items: center; + padding: 2px 8px; + border-radius: 999px; + background: var(--color-accentedPalette-50); + color: var(--color-accentedPalette-700); + font-size: 12px; + font-weight: 500; + white-space: nowrap; + } + + .dynamic-column-editor ::ng-deep .foreign-key { + min-width: 0 !important; + flex: 1 1 auto; + margin-bottom: 0; + } + + .dynamic-column-editor ::ng-deep .mat-mdc-form-field { + flex: 1 1 auto; + min-width: 0; + width: auto; + } + + .dynamic-column-editor ::ng-deep .mat-mdc-form-field-subscript-wrapper { + display: none; + } + + .dynamic-column-editor ::ng-deep .mat-mdc-text-field-wrapper { + padding: 0 10px; + } +} + +@media (prefers-color-scheme: dark) and (width <= 600px) { + .dynamic-column-editor .column-name strong { + color: rgba(255, 255, 255, 0.87); + } + + .dynamic-column-editor .comparator-text { + background: var(--color-accentedPalette-900); + color: var(--color-accentedPalette-100); + } +} + +@media (prefers-color-scheme: dark) and (width <= 600px) { + .filters-container { + background: rgba(255, 255, 255, 0.04); } } @@ -190,6 +429,12 @@ white-space: nowrap; } +@media (width <= 600px) { + .filters-where-label { + margin-top: 0 !important; + } +} + .filters-where-label .column-name-icon { font-size: 18px; width: 18px; @@ -227,6 +472,12 @@ font-weight: 500; } +@media (width <= 600px) { + .column-name { + margin-top: 0 !important; + } +} + .column-name-icon { font-size: 18px; width: 18px; @@ -301,6 +552,7 @@ @media (width <= 600px) { .static-filters { transform: none; + padding-bottom: 0; } } diff --git a/frontend/src/app/components/dashboard/db-table-view/saved-filters-panel/saved-filters-panel.component.html b/frontend/src/app/components/dashboard/db-table-view/saved-filters-panel/saved-filters-panel.component.html index a063d95bd..66edd276f 100644 --- a/frontend/src/app/components/dashboard/db-table-view/saved-filters-panel/saved-filters-panel.component.html +++ b/frontend/src/app/components/dashboard/db-table-view/saved-filters-panel/saved-filters-panel.component.html @@ -11,6 +11,7 @@ Create fast filter + @@ -38,6 +39,47 @@ + + + + + + + + + +