feat(web): improve media playground controls
This commit is contained in:
@@ -322,6 +322,17 @@
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.playgroundHero[data-media-board="true"] {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
min-height: 0;
|
||||
align-content: stretch;
|
||||
align-items: stretch;
|
||||
justify-items: stretch;
|
||||
overflow: hidden;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.playgroundModeSwitch {
|
||||
display: inline-flex;
|
||||
align-self: center;
|
||||
@@ -868,6 +879,530 @@
|
||||
color: var(--primary);
|
||||
}
|
||||
|
||||
.mediaSettingsTrigger {
|
||||
display: inline-flex;
|
||||
min-height: 34px;
|
||||
max-width: 260px;
|
||||
align-items: center;
|
||||
gap: 7px;
|
||||
padding: 0 10px;
|
||||
border: 1px solid var(--input);
|
||||
border-radius: var(--radius-md);
|
||||
background: var(--surface);
|
||||
color: var(--text-normal);
|
||||
font-size: var(--font-size-sm);
|
||||
white-space: nowrap;
|
||||
box-shadow: 0 1px 2px rgba(16, 24, 40, 0.04);
|
||||
}
|
||||
|
||||
.mediaSettingsTrigger span {
|
||||
min-width: 0;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
.mediaSettingsPanel {
|
||||
display: grid;
|
||||
width: min(560px, calc(100vw - 24px));
|
||||
gap: 12px;
|
||||
padding: 12px;
|
||||
border-radius: var(--radius-lg);
|
||||
}
|
||||
|
||||
.mediaSettingsSection {
|
||||
display: grid;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.mediaSettingsLabel {
|
||||
color: var(--muted-foreground);
|
||||
font-size: var(--font-size-xs);
|
||||
font-weight: var(--font-weight-medium);
|
||||
}
|
||||
|
||||
.mediaAspectGrid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fill, 44px);
|
||||
gap: 4px;
|
||||
justify-content: start;
|
||||
}
|
||||
|
||||
.mediaAspectGrid button {
|
||||
display: inline-flex;
|
||||
min-width: 0;
|
||||
min-height: 46px;
|
||||
align-items: center;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
gap: 2px;
|
||||
padding: 4px 2px;
|
||||
border: 1px solid var(--border);
|
||||
border-radius: var(--radius-md);
|
||||
background: var(--surface);
|
||||
color: var(--text-normal);
|
||||
font-size: var(--font-size-xs);
|
||||
}
|
||||
|
||||
.mediaAspectGrid button[data-active="true"] {
|
||||
border-color: var(--primary);
|
||||
background: color-mix(in srgb, var(--primary) 8%, var(--surface));
|
||||
color: var(--primary);
|
||||
box-shadow: 0 0 0 1px color-mix(in srgb, var(--primary) 20%, transparent);
|
||||
}
|
||||
|
||||
.mediaAspectIcon {
|
||||
position: relative;
|
||||
display: grid;
|
||||
width: 13px;
|
||||
height: 13px;
|
||||
place-items: center;
|
||||
color: var(--text-normal);
|
||||
}
|
||||
|
||||
.mediaAspectIcon::before {
|
||||
content: "";
|
||||
display: block;
|
||||
border: 1.5px solid currentColor;
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
.mediaAspectIcon[data-visual="smart"]::before {
|
||||
width: 12px;
|
||||
height: 12px;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.mediaAspectIcon[data-visual="smart"] svg {
|
||||
position: absolute;
|
||||
width: 8px;
|
||||
height: 8px;
|
||||
}
|
||||
|
||||
.mediaAspectIcon[data-visual="wide"]::before {
|
||||
width: 13px;
|
||||
height: 4px;
|
||||
}
|
||||
|
||||
.mediaAspectIcon[data-visual="landscape"]::before {
|
||||
width: 12px;
|
||||
height: 7px;
|
||||
}
|
||||
|
||||
.mediaAspectIcon[data-visual="square"]::before {
|
||||
width: 10px;
|
||||
height: 10px;
|
||||
}
|
||||
|
||||
.mediaAspectIcon[data-visual="portrait"]::before {
|
||||
width: 7px;
|
||||
height: 12px;
|
||||
}
|
||||
|
||||
.mediaAspectIcon[data-visual="tall"]::before {
|
||||
width: 5px;
|
||||
height: 13px;
|
||||
}
|
||||
|
||||
.mediaAspectGrid strong {
|
||||
overflow: hidden;
|
||||
max-width: 100%;
|
||||
font-size: var(--font-size-xs);
|
||||
font-weight: var(--font-weight-medium);
|
||||
line-height: 1;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.mediaResolutionSegment,
|
||||
.mediaOutputModeSegment {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(118px, 1fr));
|
||||
gap: 6px;
|
||||
}
|
||||
|
||||
.mediaResolutionSegment button,
|
||||
.mediaOutputModeSegment button {
|
||||
display: inline-flex;
|
||||
min-height: 34px;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 6px;
|
||||
border: 1px solid var(--border);
|
||||
border-radius: var(--radius-md);
|
||||
background: var(--surface);
|
||||
color: var(--text-normal);
|
||||
font-size: var(--font-size-sm);
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.mediaResolutionSegment button[data-active="true"],
|
||||
.mediaOutputModeSegment button[data-active="true"] {
|
||||
border-color: var(--primary);
|
||||
background: color-mix(in srgb, var(--primary) 8%, var(--surface));
|
||||
color: var(--primary);
|
||||
box-shadow: 0 0 0 1px color-mix(in srgb, var(--primary) 20%, transparent);
|
||||
}
|
||||
|
||||
.mediaResolutionSegment button:disabled,
|
||||
.mediaOutputModeSegment button:disabled,
|
||||
.mediaCountGrid button:disabled {
|
||||
cursor: not-allowed;
|
||||
opacity: 0.56;
|
||||
}
|
||||
|
||||
.mediaResolutionSegment svg,
|
||||
.mediaSettingsHint svg {
|
||||
color: #06a6bd;
|
||||
}
|
||||
|
||||
.mediaSizeRow {
|
||||
display: grid;
|
||||
grid-template-columns: minmax(0, 1fr) 24px minmax(0, 1fr) auto;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.mediaSizeRow label {
|
||||
display: grid;
|
||||
grid-template-columns: 24px minmax(0, 1fr);
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
min-height: 36px;
|
||||
padding: 0 8px;
|
||||
border: 1px solid var(--border);
|
||||
border-radius: var(--radius-md);
|
||||
background: var(--surface-muted);
|
||||
}
|
||||
|
||||
.mediaSizeRow label span,
|
||||
.mediaSizeRow strong {
|
||||
color: #607080;
|
||||
font-size: var(--font-size-sm);
|
||||
font-weight: var(--font-weight-semibold);
|
||||
}
|
||||
|
||||
.mediaSizeRow .shInput {
|
||||
border: 0;
|
||||
background: transparent;
|
||||
box-shadow: none;
|
||||
color: var(--text-strong);
|
||||
font-size: var(--font-size-sm);
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.mediaSizeRow > svg {
|
||||
justify-self: center;
|
||||
color: #607080;
|
||||
}
|
||||
|
||||
.mediaCountGrid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(64px, 1fr));
|
||||
gap: 6px;
|
||||
}
|
||||
|
||||
.mediaCountGrid button {
|
||||
min-height: 32px;
|
||||
border: 1px solid var(--border);
|
||||
border-radius: var(--radius-md);
|
||||
background: var(--surface);
|
||||
color: var(--text-normal);
|
||||
font-size: var(--font-size-sm);
|
||||
}
|
||||
|
||||
.mediaCountGrid button[data-active="true"] {
|
||||
border-color: var(--primary);
|
||||
background: var(--primary);
|
||||
color: var(--primary-foreground);
|
||||
}
|
||||
|
||||
.mediaCustomCount {
|
||||
display: grid;
|
||||
grid-template-columns: auto 110px;
|
||||
align-items: center;
|
||||
justify-content: start;
|
||||
gap: 10px;
|
||||
color: var(--text-soft);
|
||||
font-size: var(--font-size-sm);
|
||||
}
|
||||
|
||||
.mediaUnsupportedNote {
|
||||
margin: 0;
|
||||
padding: 8px 10px;
|
||||
border: 1px solid var(--border);
|
||||
border-radius: var(--radius-md);
|
||||
background: var(--surface-muted);
|
||||
color: var(--text-soft);
|
||||
font-size: var(--font-size-sm);
|
||||
}
|
||||
|
||||
.mediaSettingsHint {
|
||||
display: inline-flex;
|
||||
width: fit-content;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
color: var(--text-soft);
|
||||
font-size: var(--font-size-sm);
|
||||
}
|
||||
|
||||
.mediaTaskPage {
|
||||
display: grid;
|
||||
grid-template-rows: minmax(0, 1fr) auto;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
min-height: 0;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.mediaTaskTimeline {
|
||||
display: grid;
|
||||
align-content: start;
|
||||
gap: 22px;
|
||||
justify-items: center;
|
||||
min-height: 0;
|
||||
overflow-y: auto;
|
||||
padding: 38px 40px 22px;
|
||||
}
|
||||
|
||||
.mediaTaskTimeline h1 {
|
||||
width: min(1240px, 100%);
|
||||
font-size: 30px;
|
||||
}
|
||||
|
||||
.mediaTaskTimeline > .playgroundError {
|
||||
width: min(1240px, 100%);
|
||||
}
|
||||
|
||||
.mediaTaskItem {
|
||||
display: grid;
|
||||
gap: 14px;
|
||||
width: min(1240px, 100%);
|
||||
}
|
||||
|
||||
.mediaTaskHeader {
|
||||
display: flex;
|
||||
align-items: flex-end;
|
||||
justify-content: space-between;
|
||||
gap: 14px;
|
||||
}
|
||||
|
||||
.mediaTaskHeader > div {
|
||||
display: grid;
|
||||
gap: 4px;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.mediaTaskHeader p {
|
||||
display: flex;
|
||||
min-width: 0;
|
||||
align-items: baseline;
|
||||
gap: 9px;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.mediaTaskHeader p span {
|
||||
color: var(--text-strong);
|
||||
font-size: var(--font-size-lg);
|
||||
font-weight: var(--font-weight-medium);
|
||||
}
|
||||
|
||||
.mediaTaskHeader small,
|
||||
.mediaTaskHeader time {
|
||||
color: #7a8794;
|
||||
font-size: var(--font-size-sm);
|
||||
}
|
||||
|
||||
.mediaTaskStatus {
|
||||
flex: 0 0 auto;
|
||||
min-height: 28px;
|
||||
padding: 5px 9px;
|
||||
border-radius: 999px;
|
||||
background: var(--surface-muted);
|
||||
color: var(--text-soft);
|
||||
font-size: var(--font-size-xs);
|
||||
}
|
||||
|
||||
.mediaTaskStatus[data-status="succeeded"] {
|
||||
background: #eefdf4;
|
||||
color: #15803d;
|
||||
}
|
||||
|
||||
.mediaTaskStatus[data-status="failed"],
|
||||
.mediaTaskStatus[data-status="cancelled"] {
|
||||
background: #fef2f2;
|
||||
color: #b91c1c;
|
||||
}
|
||||
|
||||
.mediaPreviewStage {
|
||||
display: grid;
|
||||
position: relative;
|
||||
width: 100%;
|
||||
justify-items: center;
|
||||
}
|
||||
|
||||
.mediaPreviewStage[data-count="1"] {
|
||||
min-height: min(62vh, 600px);
|
||||
max-height: 600px;
|
||||
align-items: center;
|
||||
overflow: hidden;
|
||||
border: 1px solid rgba(15, 23, 42, 0.05);
|
||||
border-radius: 18px;
|
||||
background:
|
||||
linear-gradient(135deg, rgba(248, 250, 252, 0.96), rgba(234, 238, 243, 0.74)),
|
||||
repeating-linear-gradient(90deg, rgba(15, 23, 42, 0.035) 0 1px, transparent 1px 28px),
|
||||
repeating-linear-gradient(0deg, rgba(15, 23, 42, 0.03) 0 1px, transparent 1px 28px);
|
||||
box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.86);
|
||||
}
|
||||
|
||||
.mediaPreviewStage[data-count="1"]::after {
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
background: linear-gradient(180deg, rgba(255, 255, 255, 0.72), rgba(255, 255, 255, 0.18) 44%, rgba(15, 23, 42, 0.035));
|
||||
content: "";
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.mediaPreviewBackdrop {
|
||||
position: absolute;
|
||||
inset: -28px;
|
||||
width: calc(100% + 56px);
|
||||
height: calc(100% + 56px);
|
||||
opacity: 0.2;
|
||||
filter: blur(34px) saturate(1.08);
|
||||
object-fit: cover;
|
||||
pointer-events: none;
|
||||
transform: scale(1.04);
|
||||
}
|
||||
|
||||
.mediaGrid {
|
||||
--media-grid-columns: 1;
|
||||
display: grid;
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
grid-template-columns: repeat(var(--media-grid-columns), minmax(0, 1fr));
|
||||
gap: 2px;
|
||||
width: 100%;
|
||||
max-width: var(--media-grid-max-width, 100%);
|
||||
max-height: 600px;
|
||||
justify-self: center;
|
||||
overflow-y: auto;
|
||||
overscroll-behavior: contain;
|
||||
}
|
||||
|
||||
.mediaTile {
|
||||
position: relative;
|
||||
display: grid;
|
||||
min-width: 0;
|
||||
min-height: 210px;
|
||||
max-height: 600px;
|
||||
aspect-ratio: var(--media-result-aspect, 1 / 1);
|
||||
place-items: center;
|
||||
overflow: hidden;
|
||||
border-radius: 2px;
|
||||
background: #eef0f2;
|
||||
}
|
||||
|
||||
.mediaTile[data-count="1"] {
|
||||
min-height: min(62vh, 600px);
|
||||
box-shadow: 0 18px 44px rgba(15, 23, 42, 0.14);
|
||||
}
|
||||
|
||||
.mediaTile[data-count="2"] {
|
||||
min-height: min(48vh, 520px);
|
||||
}
|
||||
|
||||
.mediaTile img,
|
||||
.mediaTile video {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: cover;
|
||||
}
|
||||
|
||||
.mediaLoading,
|
||||
.mediaEmptyTile {
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
display: grid;
|
||||
place-items: center;
|
||||
gap: 10px;
|
||||
overflow: hidden;
|
||||
background: linear-gradient(110deg, #edf0f2 0%, #f7f8f9 42%, #e6eaee 78%);
|
||||
background-size: 220% 100%;
|
||||
color: #6b7280;
|
||||
font-size: var(--font-size-sm);
|
||||
animation: mediaLoadingShimmer 1.35s ease-in-out infinite;
|
||||
}
|
||||
|
||||
.mediaLoading svg {
|
||||
animation: mediaLoadingSpin 0.9s linear infinite;
|
||||
}
|
||||
|
||||
.mediaEmptyTile {
|
||||
animation: none;
|
||||
background: #eef0f2;
|
||||
}
|
||||
|
||||
.mediaTaskError {
|
||||
width: fit-content;
|
||||
max-width: 100%;
|
||||
padding: 8px 10px;
|
||||
border: 1px solid #fecaca;
|
||||
border-radius: var(--radius-md);
|
||||
background: #fef2f2;
|
||||
color: #991b1b;
|
||||
font-size: var(--font-size-sm);
|
||||
}
|
||||
|
||||
.mediaTaskActions {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.mediaTaskActions > span {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 5px;
|
||||
margin-left: auto;
|
||||
color: var(--text-soft);
|
||||
font-size: var(--font-size-sm);
|
||||
}
|
||||
|
||||
.mediaTaskActions > span svg {
|
||||
width: 14px;
|
||||
height: 14px;
|
||||
color: #607080;
|
||||
}
|
||||
|
||||
.mediaComposerDock {
|
||||
padding: 16px 40px 28px;
|
||||
background: linear-gradient(180deg, rgba(250, 250, 250, 0), var(--surface-subtle) 26%);
|
||||
}
|
||||
|
||||
.mediaComposerDock .playgroundComposer {
|
||||
width: min(1240px, 100%);
|
||||
min-height: 190px;
|
||||
margin: 0 auto;
|
||||
border-radius: 26px;
|
||||
}
|
||||
|
||||
@keyframes mediaLoadingSpin {
|
||||
to {
|
||||
transform: rotate(360deg);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes mediaLoadingShimmer {
|
||||
0% {
|
||||
background-position: 140% 0;
|
||||
}
|
||||
|
||||
100% {
|
||||
background-position: -80% 0;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 1180px) {
|
||||
.publicWorksMasonry {
|
||||
column-count: 3;
|
||||
@@ -954,6 +1489,61 @@
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.mediaSettingsTrigger,
|
||||
.composerFooter .playgroundModelSelect,
|
||||
.composerFooter .playgroundApiKeySelect,
|
||||
.playgroundModelSelect,
|
||||
.playgroundApiKeySelect {
|
||||
width: 100%;
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
.mediaSettingsPanel {
|
||||
max-height: calc(100vh - 32px);
|
||||
overflow-y: auto;
|
||||
padding: 12px;
|
||||
border-radius: var(--radius-lg);
|
||||
}
|
||||
|
||||
.mediaAspectGrid {
|
||||
grid-template-columns: repeat(3, minmax(0, 1fr));
|
||||
}
|
||||
|
||||
.mediaResolutionSegment button {
|
||||
min-height: 34px;
|
||||
font-size: var(--font-size-sm);
|
||||
}
|
||||
|
||||
.mediaSizeRow {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
|
||||
.mediaSizeRow > svg,
|
||||
.mediaSizeRow > strong {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.mediaTaskTimeline {
|
||||
padding: 30px 18px 18px;
|
||||
}
|
||||
|
||||
.mediaGrid {
|
||||
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||||
}
|
||||
|
||||
.mediaGrid[data-count="1"] {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
|
||||
.mediaTile[data-count="1"],
|
||||
.mediaTile[data-count="2"] {
|
||||
min-height: auto;
|
||||
}
|
||||
|
||||
.mediaComposerDock {
|
||||
padding: 12px 18px 18px;
|
||||
}
|
||||
|
||||
.composerQuickPrompts {
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
@@ -964,6 +1554,25 @@
|
||||
}
|
||||
|
||||
@media (max-width: 560px) {
|
||||
.mediaAspectGrid,
|
||||
.mediaCountGrid {
|
||||
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||||
}
|
||||
|
||||
.mediaGrid {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
|
||||
.mediaTaskHeader {
|
||||
align-items: flex-start;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.mediaTaskActions > span {
|
||||
width: 100%;
|
||||
margin-left: 0;
|
||||
}
|
||||
|
||||
.publicWorksMasonry {
|
||||
column-count: 1;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user