Signed-off-by: NotAShelf <raf@notashelf.dev> Change-Id: I05de526f0cea5df269b0fee226ef1edf6a6a6964
788 lines
15 KiB
SCSS
788 lines
15 KiB
SCSS
@use 'variables' as *;
|
|
@use 'mixins' as *;
|
|
|
|
// Plugin UI renderer layout classes.
|
|
//
|
|
// Dynamic values are passed via CSS custom properties set on the element.
|
|
// The layout rules here consume those properties via var() so the renderer
|
|
// never injects full CSS rule strings.
|
|
|
|
// Page wrapper
|
|
.plugin-page {
|
|
padding: $space-8 $space-12;
|
|
max-width: 100%;
|
|
overflow-x: hidden;
|
|
}
|
|
|
|
.plugin-page-title {
|
|
font-size: $font-size-xl;
|
|
font-weight: $font-weight-semibold;
|
|
color: $text-0;
|
|
margin: 0 0 $space-8;
|
|
}
|
|
|
|
// Container: vertical flex column with configurable gap and padding.
|
|
.plugin-container {
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: var(--plugin-gap, 0px);
|
|
padding: var(--plugin-padding, 0);
|
|
}
|
|
|
|
// Grid: CSS grid with a configurable column count and gap.
|
|
.plugin-grid {
|
|
display: grid;
|
|
grid-template-columns: repeat(var(--plugin-columns, 1), 1fr);
|
|
gap: var(--plugin-gap, 0px);
|
|
}
|
|
|
|
// Flex: display:flex driven by data-* attribute selectors.
|
|
// The gap is a CSS custom property; direction/justify/align/wrap are
|
|
// plain enum strings placed in data attributes by the renderer.
|
|
.plugin-flex {
|
|
display: flex;
|
|
gap: var(--plugin-gap, 0px);
|
|
|
|
&[data-direction='row'] { flex-direction: row; }
|
|
&[data-direction='column'] { flex-direction: column; }
|
|
|
|
&[data-justify='flex-start'] { justify-content: flex-start; }
|
|
&[data-justify='flex-end'] { justify-content: flex-end; }
|
|
&[data-justify='center'] { justify-content: center; }
|
|
&[data-justify='space-between'] { justify-content: space-between; }
|
|
&[data-justify='space-around'] { justify-content: space-around; }
|
|
&[data-justify='space-evenly'] { justify-content: space-evenly; }
|
|
|
|
&[data-align='flex-start'] { align-items: flex-start; }
|
|
&[data-align='flex-end'] { align-items: flex-end; }
|
|
&[data-align='center'] { align-items: center; }
|
|
&[data-align='stretch'] { align-items: stretch; }
|
|
&[data-align='baseline'] { align-items: baseline; }
|
|
|
|
&[data-wrap='wrap'] { flex-wrap: wrap; }
|
|
&[data-wrap='nowrap'] { flex-wrap: nowrap; }
|
|
}
|
|
|
|
// Split: side-by-side sidebar + main area.
|
|
.plugin-split {
|
|
display: flex;
|
|
}
|
|
|
|
// Sidebar width is driven by --plugin-sidebar-width.
|
|
.plugin-split-sidebar {
|
|
width: var(--plugin-sidebar-width, 200px);
|
|
flex-shrink: 0;
|
|
}
|
|
|
|
.plugin-split-main {
|
|
flex: 1;
|
|
min-width: 0;
|
|
}
|
|
|
|
// Card
|
|
.plugin-card {
|
|
background: $bg-2;
|
|
border: 1px solid $border;
|
|
border-radius: $radius-md;
|
|
overflow: hidden;
|
|
}
|
|
|
|
.plugin-card-header {
|
|
padding: $space-6 $space-8;
|
|
font-size: $font-size-md;
|
|
font-weight: $font-weight-semibold;
|
|
color: $text-0;
|
|
border-bottom: 1px solid $border;
|
|
background: $bg-3;
|
|
}
|
|
|
|
.plugin-card-content {
|
|
padding: $space-8;
|
|
}
|
|
|
|
.plugin-card-footer {
|
|
padding: $space-6 $space-8;
|
|
border-top: 1px solid $border;
|
|
background: $bg-1;
|
|
}
|
|
|
|
// Typography
|
|
.plugin-heading {
|
|
color: $text-0;
|
|
margin: 0;
|
|
line-height: $line-height-tight;
|
|
|
|
&.level-1 { font-size: $font-size-6xl; font-weight: $font-weight-bold; }
|
|
&.level-2 { font-size: $font-size-4xl; font-weight: $font-weight-semibold; }
|
|
&.level-3 { font-size: $font-size-3xl; font-weight: $font-weight-semibold; }
|
|
&.level-4 { font-size: $font-size-xl; font-weight: $font-weight-medium; }
|
|
&.level-5 { font-size: $font-size-lg; font-weight: $font-weight-medium; }
|
|
&.level-6 { font-size: $font-size-md; font-weight: $font-weight-medium; }
|
|
}
|
|
|
|
.plugin-text {
|
|
margin: 0;
|
|
font-size: $font-size-md;
|
|
color: $text-0;
|
|
line-height: $line-height-normal;
|
|
|
|
&.text-secondary { color: $text-1; }
|
|
&.text-error { color: $error-text; }
|
|
&.text-success { color: $success; }
|
|
&.text-warning { color: $warning; }
|
|
&.text-bold { font-weight: $font-weight-semibold; }
|
|
&.text-italic { font-style: italic; }
|
|
&.text-small { font-size: $font-size-sm; }
|
|
&.text-large { font-size: $font-size-2xl; }
|
|
}
|
|
|
|
.plugin-code {
|
|
background: $bg-1;
|
|
border: 1px solid $border;
|
|
border-radius: $radius;
|
|
padding: $space-8 $space-12;
|
|
font-family: $font-family-mono;
|
|
font-size: $font-size-md;
|
|
color: $text-0;
|
|
overflow-x: auto;
|
|
white-space: pre;
|
|
|
|
code {
|
|
font-family: inherit;
|
|
font-size: inherit;
|
|
color: inherit;
|
|
}
|
|
}
|
|
|
|
// Tabs
|
|
.plugin-tabs {
|
|
display: flex;
|
|
flex-direction: column;
|
|
}
|
|
|
|
.plugin-tab-list {
|
|
display: flex;
|
|
gap: 2px;
|
|
border-bottom: 1px solid $border;
|
|
margin-bottom: $space-8;
|
|
}
|
|
|
|
.plugin-tab {
|
|
padding: $space-4 $space-10;
|
|
font-size: $font-size-md;
|
|
font-weight: $font-weight-medium;
|
|
color: $text-1;
|
|
background: transparent;
|
|
border: none;
|
|
border-bottom: 2px solid transparent;
|
|
cursor: pointer;
|
|
transition: color $transition-base, border-color $transition-base;
|
|
|
|
&:hover {
|
|
color: $text-0;
|
|
}
|
|
|
|
&.active {
|
|
color: $accent-text;
|
|
border-bottom-color: $accent;
|
|
}
|
|
|
|
.tab-icon {
|
|
margin-right: $space-2;
|
|
}
|
|
}
|
|
|
|
.plugin-tab-panels {}
|
|
|
|
.plugin-tab-panel {
|
|
&:not(.active) { display: none; }
|
|
}
|
|
|
|
// Description list
|
|
.plugin-description-list-wrapper {
|
|
width: 100%;
|
|
}
|
|
|
|
.plugin-description-list {
|
|
display: grid;
|
|
grid-template-columns: max-content 1fr;
|
|
gap: $space-2 $space-8;
|
|
margin: 0;
|
|
padding: 0;
|
|
|
|
dt {
|
|
font-size: $font-size-sm;
|
|
font-weight: $font-weight-medium;
|
|
color: $text-1;
|
|
text-transform: uppercase;
|
|
letter-spacing: $letter-spacing-uppercase;
|
|
padding: $space-3 0;
|
|
white-space: nowrap;
|
|
}
|
|
|
|
dd {
|
|
font-size: $font-size-md;
|
|
color: $text-0;
|
|
padding: $space-3 0;
|
|
margin: 0;
|
|
word-break: break-word;
|
|
}
|
|
|
|
&.horizontal {
|
|
display: flex;
|
|
flex-wrap: wrap;
|
|
gap: $space-8 $space-12;
|
|
|
|
dt {
|
|
width: auto;
|
|
padding: 0;
|
|
}
|
|
|
|
dd {
|
|
width: auto;
|
|
padding: 0;
|
|
}
|
|
|
|
// Pair dt+dd side by side
|
|
dt, dd {
|
|
display: inline;
|
|
}
|
|
|
|
// Each dt/dd pair sits in its own flex group via a wrapper approach.
|
|
// Since we can't group them, use a two-column repeat trick instead.
|
|
display: grid;
|
|
grid-template-columns: repeat(auto-fill, minmax(180px, 1fr));
|
|
|
|
dt {
|
|
font-size: $font-size-xs;
|
|
text-transform: uppercase;
|
|
letter-spacing: $letter-spacing-uppercase;
|
|
color: $text-2;
|
|
margin-bottom: $space-1;
|
|
}
|
|
|
|
dd {
|
|
font-size: $font-size-lg;
|
|
font-weight: $font-weight-semibold;
|
|
color: $text-0;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Data table
|
|
.plugin-data-table-wrapper {
|
|
overflow-x: auto;
|
|
}
|
|
|
|
.plugin-data-table {
|
|
width: 100%;
|
|
border-collapse: collapse;
|
|
font-size: $font-size-md;
|
|
|
|
thead {
|
|
tr {
|
|
border-bottom: 1px solid $border-strong;
|
|
}
|
|
|
|
th {
|
|
padding: $space-4 $space-6;
|
|
text-align: left;
|
|
font-size: $font-size-sm;
|
|
font-weight: $font-weight-semibold;
|
|
color: $text-1;
|
|
text-transform: uppercase;
|
|
letter-spacing: $letter-spacing-uppercase;
|
|
white-space: nowrap;
|
|
}
|
|
}
|
|
|
|
tbody {
|
|
tr {
|
|
border-bottom: 1px solid $border-subtle;
|
|
transition: background $transition-fast;
|
|
|
|
&:hover {
|
|
background: $overlay-light;
|
|
}
|
|
|
|
&:last-child {
|
|
border-bottom: none;
|
|
}
|
|
}
|
|
|
|
td {
|
|
padding: $space-4 $space-6;
|
|
color: $text-0;
|
|
vertical-align: middle;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Table column with a plugin-specified fixed width.
|
|
.plugin-col-constrained {
|
|
width: var(--plugin-col-width);
|
|
}
|
|
|
|
.table-filter {
|
|
margin-bottom: $space-6;
|
|
|
|
input {
|
|
width: 240px;
|
|
padding: $space-3 $space-6;
|
|
background: $bg-1;
|
|
border: 1px solid $border;
|
|
border-radius: $radius;
|
|
color: $text-0;
|
|
font-size: $font-size-md;
|
|
|
|
&::placeholder { color: $text-2; }
|
|
&:focus {
|
|
outline: none;
|
|
border-color: $accent;
|
|
}
|
|
}
|
|
}
|
|
|
|
.table-pagination {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: $space-6;
|
|
padding: $space-4 0;
|
|
font-size: $font-size-md;
|
|
color: $text-1;
|
|
}
|
|
|
|
.row-actions {
|
|
white-space: nowrap;
|
|
width: 1%;
|
|
|
|
.plugin-button {
|
|
padding: $space-2 $space-4;
|
|
font-size: $font-size-sm;
|
|
margin-right: $space-2;
|
|
}
|
|
}
|
|
|
|
// Media grid: reuses column/gap variables from plugin-grid.
|
|
.plugin-media-grid {
|
|
display: grid;
|
|
grid-template-columns: repeat(var(--plugin-columns, 2), 1fr);
|
|
gap: var(--plugin-gap, 8px);
|
|
}
|
|
|
|
.media-grid-item {
|
|
background: $bg-2;
|
|
border: 1px solid $border;
|
|
border-radius: $radius-md;
|
|
overflow: hidden;
|
|
display: flex;
|
|
flex-direction: column;
|
|
}
|
|
|
|
.media-grid-img {
|
|
width: 100%;
|
|
aspect-ratio: 16 / 9;
|
|
object-fit: cover;
|
|
display: block;
|
|
}
|
|
|
|
.media-grid-no-img {
|
|
width: 100%;
|
|
aspect-ratio: 16 / 9;
|
|
background: $bg-3;
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
font-size: $font-size-sm;
|
|
color: $text-2;
|
|
}
|
|
|
|
.media-grid-caption {
|
|
padding: $space-4 $space-6;
|
|
font-size: $font-size-sm;
|
|
color: $text-0;
|
|
white-space: nowrap;
|
|
overflow: hidden;
|
|
text-overflow: ellipsis;
|
|
}
|
|
|
|
// List
|
|
.plugin-list-wrapper {}
|
|
|
|
.plugin-list {
|
|
list-style: none;
|
|
margin: 0;
|
|
padding: 0;
|
|
}
|
|
|
|
.plugin-list-item {
|
|
padding: $space-4 0;
|
|
}
|
|
|
|
.plugin-list-divider {
|
|
border: none;
|
|
border-top: 1px solid $border-subtle;
|
|
margin: 0;
|
|
}
|
|
|
|
.plugin-list-empty {
|
|
padding: $space-8;
|
|
text-align: center;
|
|
color: $text-2;
|
|
font-size: $font-size-md;
|
|
}
|
|
|
|
// Interactive: buttons
|
|
.plugin-button {
|
|
display: inline-flex;
|
|
align-items: center;
|
|
gap: $space-3;
|
|
padding: $space-4 $space-8;
|
|
border: 1px solid $border;
|
|
border-radius: $radius;
|
|
font-size: $font-size-md;
|
|
font-weight: $font-weight-medium;
|
|
cursor: pointer;
|
|
transition: background $transition-fast, border-color $transition-fast,
|
|
color $transition-fast;
|
|
background: $bg-2;
|
|
color: $text-0;
|
|
|
|
&:disabled {
|
|
opacity: 0.45;
|
|
cursor: not-allowed;
|
|
}
|
|
|
|
&.btn-primary {
|
|
background: $accent;
|
|
border-color: $accent;
|
|
color: #fff;
|
|
|
|
&:hover:not(:disabled) { background: $accent-hover; }
|
|
}
|
|
|
|
&.btn-secondary {
|
|
background: $bg-3;
|
|
border-color: $border-strong;
|
|
color: $text-0;
|
|
|
|
&:hover:not(:disabled) { background: $overlay-medium; }
|
|
}
|
|
|
|
&.btn-tertiary {
|
|
background: transparent;
|
|
border-color: transparent;
|
|
color: $accent-text;
|
|
|
|
&:hover:not(:disabled) { background: $accent-dim; }
|
|
}
|
|
|
|
&.btn-danger {
|
|
background: transparent;
|
|
border-color: $error-border;
|
|
color: $error-text;
|
|
|
|
&:hover:not(:disabled) { background: $error-bg; }
|
|
}
|
|
|
|
&.btn-success {
|
|
background: transparent;
|
|
border-color: $success-border;
|
|
color: $success;
|
|
|
|
&:hover:not(:disabled) { background: $success-bg; }
|
|
}
|
|
|
|
&.btn-ghost {
|
|
background: transparent;
|
|
border-color: transparent;
|
|
color: $text-1;
|
|
|
|
&:hover:not(:disabled) { background: $btn-ghost-hover; }
|
|
}
|
|
}
|
|
|
|
// Badges
|
|
.plugin-badge {
|
|
display: inline-flex;
|
|
align-items: center;
|
|
padding: $space-1 $space-4;
|
|
border-radius: $radius-full;
|
|
font-size: $font-size-xs;
|
|
font-weight: $font-weight-semibold;
|
|
letter-spacing: $letter-spacing-uppercase;
|
|
text-transform: uppercase;
|
|
|
|
&.badge-default, &.badge-neutral {
|
|
background: $overlay-medium;
|
|
color: $text-1;
|
|
}
|
|
|
|
&.badge-primary {
|
|
background: $accent-dim;
|
|
color: $accent-text;
|
|
}
|
|
|
|
&.badge-secondary {
|
|
background: $overlay-light;
|
|
color: $text-0;
|
|
}
|
|
|
|
&.badge-success {
|
|
background: $success-bg;
|
|
color: $success;
|
|
}
|
|
|
|
&.badge-warning {
|
|
background: $warning-bg;
|
|
color: $warning;
|
|
}
|
|
|
|
&.badge-error {
|
|
background: $error-bg;
|
|
color: $error-text;
|
|
}
|
|
|
|
&.badge-info {
|
|
background: $info-bg;
|
|
color: $accent-text;
|
|
}
|
|
}
|
|
|
|
// Form
|
|
.plugin-form {
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: $space-8;
|
|
}
|
|
|
|
.form-field {
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: $space-3;
|
|
|
|
label {
|
|
font-size: $font-size-md;
|
|
font-weight: $font-weight-medium;
|
|
color: $text-0;
|
|
}
|
|
|
|
input, textarea, select {
|
|
padding: $space-4 $space-6;
|
|
background: $bg-1;
|
|
border: 1px solid $border;
|
|
border-radius: $radius;
|
|
color: $text-0;
|
|
font-size: $font-size-md;
|
|
font-family: inherit;
|
|
|
|
&::placeholder { color: $text-2; }
|
|
|
|
&:focus {
|
|
outline: none;
|
|
border-color: $accent;
|
|
box-shadow: 0 0 0 2px $accent-dim;
|
|
}
|
|
}
|
|
|
|
textarea {
|
|
min-height: 80px;
|
|
resize: vertical;
|
|
}
|
|
|
|
select {
|
|
appearance: none;
|
|
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='8' viewBox='0 0 12 8'%3E%3Cpath d='M1 1l5 5 5-5' stroke='%23a0a0b8' stroke-width='1.5' fill='none' stroke-linecap='round'/%3E%3C/svg%3E");
|
|
background-repeat: no-repeat;
|
|
background-position: right $space-6 center;
|
|
padding-right: $space-16;
|
|
}
|
|
}
|
|
|
|
.form-help {
|
|
margin: 0;
|
|
font-size: $font-size-sm;
|
|
color: $text-2;
|
|
}
|
|
|
|
.form-actions {
|
|
display: flex;
|
|
gap: $space-6;
|
|
padding-top: $space-4;
|
|
}
|
|
|
|
.required {
|
|
color: $error;
|
|
}
|
|
|
|
// Link
|
|
.plugin-link {
|
|
color: $accent-text;
|
|
text-decoration: none;
|
|
|
|
&:hover { text-decoration: underline; }
|
|
}
|
|
|
|
.plugin-link-blocked {
|
|
color: $text-2;
|
|
text-decoration: line-through;
|
|
cursor: not-allowed;
|
|
}
|
|
|
|
// Progress
|
|
.plugin-progress {
|
|
background: $bg-1;
|
|
border: 1px solid $border;
|
|
border-radius: $radius;
|
|
height: 8px;
|
|
overflow: hidden;
|
|
display: flex;
|
|
align-items: center;
|
|
gap: $space-4;
|
|
}
|
|
|
|
.plugin-progress-bar {
|
|
height: 100%;
|
|
background: $accent;
|
|
border-radius: 4px;
|
|
transition: width 0.3s ease;
|
|
width: var(--plugin-progress, 0%);
|
|
}
|
|
|
|
.plugin-progress-label {
|
|
font-size: $font-size-sm;
|
|
color: $text-1;
|
|
white-space: nowrap;
|
|
flex-shrink: 0;
|
|
}
|
|
|
|
// Chart wrapper: height is driven by --plugin-chart-height.
|
|
.plugin-chart {
|
|
overflow: auto;
|
|
height: var(--plugin-chart-height, 200px);
|
|
|
|
.chart-title {
|
|
font-size: $font-size-lg;
|
|
font-weight: $font-weight-semibold;
|
|
color: $text-0;
|
|
margin-bottom: $space-4;
|
|
}
|
|
|
|
.chart-x-label, .chart-y-label {
|
|
font-size: $font-size-sm;
|
|
color: $text-2;
|
|
margin-bottom: $space-2;
|
|
}
|
|
|
|
.chart-data-table {
|
|
overflow-x: auto;
|
|
}
|
|
|
|
.chart-no-data {
|
|
padding: $space-12;
|
|
text-align: center;
|
|
color: $text-2;
|
|
font-size: $font-size-md;
|
|
}
|
|
}
|
|
|
|
// Loading / error states
|
|
.plugin-loading {
|
|
padding: $space-8;
|
|
color: $text-1;
|
|
font-size: $font-size-md;
|
|
font-style: italic;
|
|
}
|
|
|
|
.plugin-error {
|
|
padding: $space-6 $space-8;
|
|
background: $error-bg;
|
|
border: 1px solid $error-border;
|
|
border-radius: $radius;
|
|
color: $error-text;
|
|
font-size: $font-size-md;
|
|
}
|
|
|
|
// Feedback toast
|
|
.plugin-feedback {
|
|
position: sticky;
|
|
bottom: $space-8;
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: space-between;
|
|
gap: $space-8;
|
|
padding: $space-6 $space-8;
|
|
border-radius: $radius-md;
|
|
font-size: $font-size-md;
|
|
z-index: $z-toast;
|
|
box-shadow: $shadow-lg;
|
|
|
|
&.success {
|
|
background: $success-bg;
|
|
border: 1px solid $success-border;
|
|
color: $success;
|
|
}
|
|
|
|
&.error {
|
|
background: $error-bg;
|
|
border: 1px solid $error-border;
|
|
color: $error-text;
|
|
}
|
|
}
|
|
|
|
.plugin-feedback-dismiss {
|
|
background: transparent;
|
|
border: none;
|
|
color: inherit;
|
|
font-size: $font-size-xl;
|
|
cursor: pointer;
|
|
line-height: 1;
|
|
padding: 0;
|
|
opacity: 0.7;
|
|
|
|
&:hover { opacity: 1; }
|
|
}
|
|
|
|
// Modal
|
|
.plugin-modal-overlay {
|
|
position: fixed;
|
|
inset: 0;
|
|
background: rgba(0, 0, 0, 0.65);
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
z-index: $z-modal-backdrop;
|
|
}
|
|
|
|
.plugin-modal {
|
|
position: relative;
|
|
background: $bg-2;
|
|
border: 1px solid $border-strong;
|
|
border-radius: $radius-xl;
|
|
padding: $space-16;
|
|
min-width: 380px;
|
|
max-width: 640px;
|
|
max-height: 80vh;
|
|
overflow-y: auto;
|
|
box-shadow: $shadow-lg;
|
|
z-index: $z-modal;
|
|
}
|
|
|
|
.plugin-modal-close {
|
|
position: absolute;
|
|
top: $space-8;
|
|
right: $space-8;
|
|
background: transparent;
|
|
border: none;
|
|
color: $text-1;
|
|
font-size: $font-size-xl;
|
|
cursor: pointer;
|
|
line-height: 1;
|
|
padding: $space-2;
|
|
border-radius: $radius;
|
|
|
|
&:hover {
|
|
background: $overlay-medium;
|
|
color: $text-0;
|
|
}
|
|
}
|