The published site showed one line of text — "요청한 문구를 표시할 수 없습니다."
— instead of any UI. Two independent faults produced it.
The screens ask for the whole catalogue by calling searchPublicContent(""). The
fixture answered that with everything it had, and four screens lean on it: the
home timeline, the project index, the release index, and the explore filter.
The contract has no such meaning — `q` is required, and an empty one answers
400 — so all four turned into error surfaces the moment the source became HTTP.
The adapter now assembles that catalogue from the list endpoints the contract
does provide, and only sends a real query to the search endpoint. Filtering
client-side instead would have been the other option, and it would silently
lose every result past the first page.
The message that surfaced was missing too. Twenty-two of the thirty-eight
failure kinds had no copy, so `errorMessage` fell through to
`common.unavailable` — which says nothing about what failed or what to do.
That is a systemic gap, not one absent key, so all twenty-two are written, in
both catalogues. They are phrased for the reader: what did not happen and what
to try, not the internal classification.
The Studio dialogs opened against the top-left corner. A modal dialog centres
through the UA's `margin: auto`, which is not surviving in this build; the
public `.search-dialog` already states `position/inset/margin` explicitly for
the same reason. The three that did not — unsaved-changes, asset upload, and
the publication flow — now follow it, with a max-height so a long dialog
scrolls rather than running off the screen.
177 lines
15 KiB
CSS
177 lines
15 KiB
CSS
.studio-app { min-height: 100vh; color: var(--ink); }
|
|
.studio-app .studio-skip-link { position: fixed; z-index: 100; top: 12px; left: 16px; padding: 10px 14px; border: 1px solid var(--line-strong); border-radius: 6px; background: var(--paper); transform: translateY(-160%); }
|
|
.studio-app .studio-skip-link:focus { transform: translateY(0); }
|
|
.studio-app .studio-header { border-bottom: 1px solid var(--line); background: rgba(252, 252, 251, 0.94); }
|
|
.studio-app .studio-header-inner,
|
|
.studio-app .studio-mobile-navigation,
|
|
.studio-app .studio-main { width: min(1180px, calc(100% - 80px)); margin-inline: auto; }
|
|
.studio-app .studio-header-inner { display: flex; min-height: 76px; align-items: center; justify-content: space-between; gap: 40px; }
|
|
.studio-app .studio-wordmark { display: inline-flex; min-height: 44px; align-items: center; font-size: 17px; font-weight: 700; letter-spacing: -0.02em; }
|
|
.studio-app .studio-wordmark span { margin-left: 5px; color: var(--signal); font-family: "IBM Plex Mono", monospace; font-size: 12px; letter-spacing: 0.04em; text-transform: uppercase; }
|
|
.studio-app .studio-desktop-navigation nav,
|
|
.studio-app .studio-mobile-navigation nav { display: flex; align-items: center; gap: 26px; }
|
|
.studio-app .studio-desktop-navigation a,
|
|
.studio-app .studio-mobile-navigation a { display: inline-flex; min-height: 44px; align-items: center; color: var(--muted); font-size: 14px; }
|
|
.studio-app nav a[aria-current="page"] { color: var(--ink); font-weight: 650; }
|
|
.studio-app .studio-menu-trigger { display: none; min-height: 44px; padding-inline: 12px; border: 1px solid var(--line-strong); border-radius: 5px; background: var(--paper); color: var(--ink); }
|
|
.studio-app .studio-mobile-navigation { padding-bottom: 16px; }
|
|
.studio-app .studio-main { padding-block: 72px 120px; }
|
|
.studio-app .studio-page-heading { max-width: 760px; padding-bottom: 52px; }
|
|
.studio-app .studio-page-heading h1,
|
|
.studio-app .studio-route-state h1 { margin: 0 0 18px; font-size: clamp(36px, 6vw, 64px); line-height: 1.08; letter-spacing: -0.045em; }
|
|
.studio-app .studio-eyebrow { margin: 0 0 14px; color: var(--muted); font-family: "IBM Plex Mono", monospace; font-size: 12px; letter-spacing: 0.08em; }
|
|
.studio-app .studio-overview-list { border-top: 1px solid var(--line-strong); }
|
|
.studio-app .studio-overview-list section { display: grid; grid-template-columns: 130px minmax(180px, 0.8fr) minmax(260px, 1.4fr) auto; align-items: baseline; gap: 24px; padding-block: 28px; border-bottom: 1px solid var(--line); }
|
|
.studio-app .studio-overview-list h2,
|
|
.studio-app .studio-overview-list p { margin: 0; }
|
|
.studio-app .studio-overview-list a,
|
|
.studio-app .studio-route-state > a { color: var(--signal); font-weight: 650; }
|
|
.studio-app .studio-route-state { max-width: 720px; padding-block: 48px; }
|
|
.studio-app .studio-route-state button { min-height: 44px; margin-top: 18px; padding-inline: 16px; border: 1px solid var(--signal); border-radius: 5px; background: var(--signal); color: #fff; }
|
|
.studio-app .studio-loading { min-height: 180px; }
|
|
.studio-app .studio-visually-hidden { position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px; overflow: hidden; clip: rect(0, 0, 0, 0); white-space: nowrap; border: 0; }
|
|
/* 모달 dialog 를 화면 가운데에 둔다. UA 기본값(margin:auto)에 맡기면 이 빌드에서는
|
|
좌상단에 붙는다 — 공개 화면의 .search-dialog 가 같은 이유로 position/inset/margin 을
|
|
이미 명시하고 있고, 여기도 같은 방식을 쓴다. max-height/overflow 는 내용이 길어졌을 때
|
|
화면 밖으로 나가지 않게 하는 짝이다. */
|
|
.studio-app .studio-unsaved-dialog { position: fixed; inset: 0; margin: auto; max-height: calc(100dvh - 32px); overflow: auto; width: min(560px, calc(100% - 32px)); padding: 0; border: 1px solid var(--line-strong); border-radius: 8px; background: var(--paper); color: var(--ink); }
|
|
.studio-app .studio-unsaved-dialog::backdrop { background: rgba(23, 24, 27, 0.48); }
|
|
.studio-app .studio-dialog-body { padding: 30px; }
|
|
.studio-app .studio-dialog-body h2 { margin: 0 0 12px; font-size: 26px; }
|
|
.studio-app .studio-dialog-error { color: #8f2f27; }
|
|
.studio-app .studio-dialog-actions { display: flex; flex-wrap: wrap; justify-content: flex-end; gap: 8px; margin-top: 28px; }
|
|
.studio-app .studio-dialog-actions button { min-height: 44px; padding-inline: 14px; border: 1px solid var(--line-strong); border-radius: 5px; background: var(--paper); color: var(--ink); }
|
|
.studio-app .studio-dialog-actions button:last-child { border-color: var(--signal); background: var(--signal); color: #fff; }
|
|
.studio-app .studio-asset-upload-dialog { position: fixed; inset: 0; margin: auto; max-height: calc(100dvh - 32px); overflow: auto; width: min(560px, calc(100% - 32px)); padding: 0; border: 1px solid var(--line-strong); border-radius: 8px; background: var(--paper); color: var(--ink); }
|
|
.studio-app .studio-asset-upload-dialog::backdrop { background: rgba(23, 24, 27, 0.48); }
|
|
.studio-app .studio-asset-upload-dialog .studio-dialog-status { min-height: 20px; margin: 16px 0 0; color: var(--muted); font-size: 13px; }
|
|
.studio-app .studio-asset-upload-dialog .studio-field + .studio-field { margin-top: 18px; }
|
|
.studio-app .studio-asset-upload-dialog .studio-field--checkbox { display: flex; align-items: center; gap: 10px; }
|
|
.studio-app .studio-asset-upload-dialog .studio-field--checkbox input { width: 18px; min-width: 18px; min-height: 18px; padding: 0; }
|
|
|
|
.studio-app .studio-page-top { display: flex; align-items: flex-end; justify-content: space-between; gap: 36px; border-bottom: 1px solid var(--line-strong); }
|
|
.studio-app .studio-page-top .studio-page-heading { padding-bottom: 42px; }
|
|
.studio-app .studio-primary-action,
|
|
.studio-app .studio-primary-button,
|
|
.studio-app .studio-secondary-button,
|
|
.studio-app .studio-document-tools button,
|
|
.studio-app .studio-asset-tools button,
|
|
.studio-app .studio-empty-state a { display: inline-flex; min-height: 44px; align-items: center; justify-content: center; padding-inline: 16px; border: 1px solid var(--line-strong); border-radius: 5px; background: var(--paper); color: var(--ink); font-weight: 650; }
|
|
.studio-app .studio-primary-action,
|
|
.studio-app .studio-primary-button { margin-bottom: 42px; border-color: var(--signal); background: var(--signal); color: #fff; }
|
|
.studio-app .studio-summary-grid { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); margin-top: 28px; border-block: 1px solid var(--line); }
|
|
.studio-app .studio-summary-grid div { display: grid; gap: 9px; padding: 22px; border-right: 1px solid var(--line); }
|
|
.studio-app .studio-summary-grid div:last-child { border-right: 0; }
|
|
.studio-app .studio-summary-grid span { color: var(--muted); font-size: 12px; }
|
|
.studio-app .studio-summary-grid strong { font-size: 24px; letter-spacing: -0.03em; }
|
|
.studio-app .studio-work-section { padding-top: 54px; }
|
|
.studio-app .studio-section-title { display: flex; min-height: 52px; align-items: center; justify-content: space-between; gap: 20px; border-bottom: 1px solid var(--line-strong); }
|
|
.studio-app .studio-section-title h2 { margin: 0; font-size: 24px; }
|
|
.studio-app .studio-section-title a { display: inline-flex; min-height: 44px; align-items: center; color: var(--signal); font-size: 13px; font-weight: 650; }
|
|
.studio-app .studio-work-list,
|
|
.studio-app .studio-document-list { border-bottom: 1px solid var(--line); }
|
|
.studio-app .studio-work-row { display: grid; grid-template-columns: 110px minmax(0, 1fr) 130px; gap: 24px; align-items: start; padding-block: 24px; border-top: 1px solid var(--line); }
|
|
.studio-app .studio-work-list > :first-child { border-top: 0; }
|
|
.studio-app .studio-row-label { margin: 3px 0 0; color: var(--muted); font-family: "IBM Plex Mono", monospace; font-size: 11px; letter-spacing: 0.05em; text-transform: uppercase; }
|
|
.studio-app .studio-work-row h3 { margin: 0; font-size: 17px; line-height: 1.5; overflow-wrap: anywhere; }
|
|
.studio-app .studio-work-row h3 a { display: inline-flex; min-height: 44px; align-items: flex-start; }
|
|
.studio-app .studio-work-row div p,
|
|
.studio-app .studio-work-row time { margin: 5px 0 0; color: var(--muted); font-size: 13px; }
|
|
.studio-app .studio-empty-inline { margin: 0; padding-block: 26px; color: var(--muted); }
|
|
.studio-app .studio-screen-error { margin-top: 26px; padding: 16px; border-left: 3px solid #a13b31; background: #fff7f4; color: #75271f; }
|
|
|
|
.studio-app .studio-document-tools { display: grid; grid-template-columns: minmax(280px, 1fr) 180px 180px; gap: 16px; padding-block: 28px; border-bottom: 1px solid var(--line-strong); }
|
|
.studio-app .studio-asset-tools { display: grid; grid-template-columns: minmax(0, 1fr); gap: 16px; padding-block: 28px; border-bottom: 1px solid var(--line-strong); }
|
|
.studio-app .studio-document-tools form,
|
|
.studio-app .studio-document-tools label,
|
|
.studio-app .studio-asset-tools form,
|
|
.studio-app .studio-asset-tools label { display: grid; gap: 8px; color: var(--muted); font-size: 12px; font-weight: 650; }
|
|
/* `min-width: 0` for the same reason `.asset-picker-search div` needs it: a
|
|
flex container's automatic minimum is its min-content size, which at 360px
|
|
forces the row wider than its column instead of shrinking the input. */
|
|
.studio-app .studio-document-tools form div,
|
|
.studio-app .studio-asset-tools form div { display: flex; min-width: 0; gap: 8px; }
|
|
.studio-app .studio-asset-tools form { min-width: 0; }
|
|
.studio-app .studio-document-tools input,
|
|
.studio-app .studio-document-tools select,
|
|
.studio-app .studio-asset-tools input { width: 100%; min-width: 0; min-height: 44px; padding-inline: 12px; border: 1px solid var(--line-strong); border-radius: 5px; background: var(--paper); color: var(--ink); }
|
|
.studio-app .studio-document-tools input,
|
|
.studio-app .studio-asset-tools input { flex: 1; }
|
|
.studio-app .studio-result-count { margin: 24px 0 10px; color: var(--muted); font-size: 13px; }
|
|
.studio-app .studio-document-row { display: grid; grid-template-columns: 105px minmax(240px, 1fr) minmax(360px, 0.9fr); gap: 24px; align-items: start; padding-block: 26px; border-top: 1px solid var(--line); }
|
|
.studio-app .studio-document-list > :first-child { border-top: 0; }
|
|
.studio-app .studio-document-title h2 { margin: 0; font-size: 17px; line-height: 1.5; overflow-wrap: anywhere; }
|
|
.studio-app .studio-document-title h2 a { display: inline-flex; min-height: 44px; align-items: flex-start; }
|
|
.studio-app .studio-document-title p { margin: 4px 0 0; color: var(--muted); font-size: 13px; }
|
|
.studio-app .studio-document-row dl { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 14px; margin: 0; }
|
|
.studio-app .studio-document-row dt { color: var(--muted); font-size: 11px; }
|
|
.studio-app .studio-document-row dd { margin: 5px 0 0; font-size: 13px; overflow-wrap: anywhere; }
|
|
.studio-app .studio-secondary-button { margin-top: 24px; }
|
|
.studio-app .studio-empty-state { padding-block: 56px; border-bottom: 1px solid var(--line); }
|
|
.studio-app .studio-empty-state h2 { margin: 0; font-size: 25px; }
|
|
.studio-app .studio-empty-state p { margin: 12px 0 22px; color: var(--muted); }
|
|
|
|
.studio-app .studio-type-list { margin: 0; padding: 0; border: 0; border-top: 1px solid var(--line-strong); }
|
|
.studio-app .studio-type-list legend { padding: 0 0 16px; font-size: 20px; font-weight: 700; }
|
|
.studio-app .studio-type-list label { display: grid; grid-template-columns: 32px 140px minmax(260px, 1fr) minmax(220px, 0.8fr); gap: 18px; min-height: 88px; align-items: center; padding-block: 20px; border-bottom: 1px solid var(--line); cursor: pointer; }
|
|
.studio-app .studio-type-list input { width: 20px; height: 20px; margin: 0; }
|
|
.studio-app .studio-type-list strong { font-size: 18px; }
|
|
.studio-app .studio-type-list span,
|
|
.studio-app .studio-type-list small { color: var(--muted); line-height: 1.6; }
|
|
.studio-app .studio-create-footer { display: flex; align-items: center; gap: 20px; margin-top: 28px; }
|
|
.studio-app .studio-create-footer .studio-primary-button { margin: 0; }
|
|
.studio-app .studio-create-footer p { margin: 0; color: var(--muted); font-size: 13px; }
|
|
.studio-app .studio-primary-button:disabled { opacity: 0.55; cursor: wait; }
|
|
|
|
@media (max-width: 900px) {
|
|
.studio-app .studio-overview-list section { grid-template-columns: 110px minmax(0, 1fr); }
|
|
.studio-app .studio-overview-list section > p:nth-of-type(2),
|
|
.studio-app .studio-overview-list section > a { grid-column: 2; }
|
|
.studio-app .studio-summary-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
|
|
.studio-app .studio-summary-grid div:nth-child(2) { border-right: 0; }
|
|
.studio-app .studio-summary-grid div:nth-child(-n + 2) { border-bottom: 1px solid var(--line); }
|
|
.studio-app .studio-document-tools { grid-template-columns: minmax(0, 1fr) repeat(2, 160px); }
|
|
.studio-app .studio-document-row { grid-template-columns: 90px minmax(0, 1fr); }
|
|
.studio-app .studio-document-row dl { grid-column: 2; }
|
|
}
|
|
|
|
@media (max-width: 767px) {
|
|
.studio-app .studio-header-inner,
|
|
.studio-app .studio-mobile-navigation,
|
|
.studio-app .studio-main { width: min(100% - 32px, 1180px); }
|
|
.studio-app .studio-header-inner { min-height: 68px; gap: 16px; }
|
|
.studio-app .studio-desktop-navigation { display: none; }
|
|
.studio-app .studio-menu-trigger { display: inline-flex; align-items: center; }
|
|
.studio-app .studio-mobile-navigation nav { align-items: stretch; flex-direction: column; gap: 2px; }
|
|
.studio-app .studio-mobile-navigation a { width: 100%; }
|
|
.studio-app .studio-main { padding-block: 48px 88px; }
|
|
.studio-app .studio-overview-list section { display: block; }
|
|
.studio-app .studio-overview-list h2 { margin-bottom: 8px; }
|
|
.studio-app .studio-overview-list a { display: inline-flex; min-height: 44px; margin-top: 12px; align-items: center; }
|
|
.studio-app .studio-dialog-body { padding: 24px 20px; }
|
|
.studio-app .studio-dialog-actions { align-items: stretch; flex-direction: column; }
|
|
.studio-app .studio-page-top { align-items: flex-start; flex-direction: column; gap: 0; }
|
|
.studio-app .studio-page-top .studio-page-heading { padding-bottom: 24px; }
|
|
.studio-app .studio-primary-action { width: 100%; margin: 0 0 32px; }
|
|
.studio-app .studio-work-section { padding-top: 42px; }
|
|
.studio-app .studio-work-row { grid-template-columns: 78px minmax(0, 1fr); gap: 12px; }
|
|
.studio-app .studio-work-row time { grid-column: 2; }
|
|
.studio-app .studio-document-tools { grid-template-columns: repeat(2, minmax(0, 1fr)); }
|
|
.studio-app .studio-document-tools form { grid-column: 1 / -1; }
|
|
.studio-app .studio-document-row { grid-template-columns: 74px minmax(0, 1fr); gap: 12px; }
|
|
.studio-app .studio-document-row dl { grid-column: 2; grid-template-columns: repeat(2, minmax(0, 1fr)); }
|
|
.studio-app .studio-type-list label { grid-template-columns: 30px minmax(0, 1fr); gap: 7px 12px; }
|
|
.studio-app .studio-type-list span,
|
|
.studio-app .studio-type-list small { grid-column: 2; }
|
|
.studio-app .studio-create-footer { align-items: stretch; flex-direction: column; }
|
|
}
|
|
|
|
@media (max-width: 420px) {
|
|
.studio-app .studio-summary-grid { grid-template-columns: minmax(0, 1fr); }
|
|
.studio-app .studio-summary-grid div { border-right: 0; border-bottom: 1px solid var(--line); }
|
|
.studio-app .studio-summary-grid div:last-child { border-bottom: 0; }
|
|
.studio-app .studio-document-tools { grid-template-columns: minmax(0, 1fr); }
|
|
.studio-app .studio-document-tools form { grid-column: 1; }
|
|
.studio-app .studio-document-row dl { grid-template-columns: minmax(0, 1fr); }
|
|
}
|