/
githubmirror
/
tldraw
Обзор
Документация
Войти
/
githubmirror
/
tldraw
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
main
apps/dotcom/client/src/tla/components/dialogs/dialogs.module.css
345 строк
7 KB
Jessica Claire Edwards
refactor(dotcom): use --tl-space tokens for matching spacing values (#9211)
20 июн 2026, 14:20
Не верифицирован
20 июн 2026, 14:20
33cb580
Код
Авторство
О чём код?
.dialogContainer { width: 350px; min-width: 350px; max-width: 100%; } .dialogBody { display: flex; flex-direction: column; gap: var(--tl-space-4); max-width: 500px; overflow: auto; } /* ----------------- Feedback dialog ---------------- */ .feedbackDialogTextArea { border: 1px solid var(--tl-color-muted-2); border-radius: var(--tl-radius-2) var(--tl-radius-2) 0px var(--tl-radius-2); background-color: var(--tl-color-muted-0); color: var(--tl-color-text-0); padding: var(--tl-space-3) var(--tl-space-4); resize: vertical; width: 100%; min-height: 100px; max-height: 400px; } @supports (-webkit-touch-callout: none) { .feedbackDialogTextArea { font-size: 16px; } } .feedbackDialogTextArea::placeholder { color: var(--tl-color-text-3); } .feedbackDialogCheckbox { margin-right: auto; } /* --------------------- Cookie --------------------- */ .cookieConsent { background: var(--tla-color-sidebar); border-radius: 8px; padding: 6px; max-width: 240px; box-shadow: var(--tla-shadow-3); margin-bottom: 4px; margin-right: 4px; transform: translate(0px, 110%); animation: slideUp 3s ease-out forwards; animation-delay: 2s; } :global(.tl-container[dir='rtl']) .cookieConsent { margin-right: 0; margin-left: 4px; } @keyframes slideUp { 0% { transform: translate(0px, 110%); } 100% { transform: translate(0px, 0%); } } .cookieText { padding: var(--tl-space-3); padding-bottom: 12px; font-size: 12px; color: var(--tl-color-text-0); line-height: 1.4; } .cookieText a { color: var(--tl-color-primary); } .cookieButtonsRow { display: flex; gap: var(--tl-space-2); justify-content: space-between; flex-wrap: wrap; } .cookieButtons { display: flex; gap: var(--tl-space-2); flex-wrap: wrap; justify-content: space-between; } .cookieButton { background: none; position: relative; border: none; padding: 4px 8px; color: var(--tl-color-text-3); font-size: 12px; cursor: pointer; text-decoration: none; white-space: nowrap; border-radius: 4px; flex-shrink: 0; } .cookieAcceptButton { color: var(--tla-color-sidebar); background-color: var(--tl-color-text-0); overflow: hidden; position: relative; } .cookieAcceptButtonTextWrapper { overflow: hidden; } .cookieAcceptButtonText { display: inline-block; animation: marquee 3s linear infinite; white-space: nowrap; } :global(.tl-container[dir='rtl']) .cookieAcceptButtonText { animation-direction: reverse; } @keyframes marquee { 0% { transform: translateX(100%); } 100% { transform: translateX(-100%); } } /* Respect user's motion preferences */ @media (prefers-reduced-motion: reduce) { .cookieConsent { animation: none; transform: translate(0px, 0%); } .cookieAcceptButtonText { animation: none; transform: translateX(0); } } @media (hover: hover) { .cookieAcceptButton:hover { color: var(--tla-color-sidebar); background-color: var(--tl-color-text-0); } } .cookieConsentWrapper { position: fixed; bottom: 0; right: 0; z-index: var(--tl-layer-toasts); width: fit-content; } :global(.tl-container[dir='rtl']) .cookieConsentWrapper { right: auto; left: 0; } .noPadding { padding: 0px; } .dialogFieldLabelRow { height: 40px; display: flex; align-items: center; } .dialogInput { height: 36px; border: 1px solid var(--tl-color-divider); border-radius: var(--tl-radius-2); background-color: var(--tl-color-muted-0); padding: 0px var(--tl-space-3); margin: 0px 0px; display: flex; align-items: center; justify-content: center; width: 100%; } .dialogInput:focus { border: 1px solid var(--tl-color-primary); } /* ----------------- Group Settings Dialog ---------------- */ .workspaceSettingsBody { padding-top: 0px; max-width: 360px; max-height: max(420px, 80%); width: calc(100vw - 48px); } .section { display: flex; flex-direction: column; padding: 6px 0px; } /* No trailing gap when a section is the last thing in the dialog (e.g. the member list, for non-owners who have no destroy action below it). */ .section:last-child { margin-bottom: 0; } .sectionLabel { height: 36px; display: flex; align-items: center; font-weight: 500; } /* Help text under a section's control (e.g. the home workspace's private note). */ .sectionHelp { margin: 8px 0 0; text-align: center; text-wrap: balance; color: var(--tl-color-text-0); } .membersList { display: flex; flex-direction: column; } .memberItem { display: flex; align-items: center; gap: 10px; height: 36px; } .memberAvatar { width: 24px; height: 24px; border-radius: 50%; display: flex; align-items: center; justify-content: center; color: white; font-weight: bold; } .memberName { flex: 1; } .memberRole { color: var(--tl-color-text-3); font-size: 12px; } /* Pull the tab strip out by the shared 12px tab padding so the first tab's label aligns with the headings, button, and member rows. Since the dialog body's padding also equals that 12px, the strip now spans the body's full width — so drop the tab nav's bottom rule inset to 0 and let it bleed to the modal edges. */ .workspaceTabs { margin: 12px -12px 0px -12px; --tabs-line-inset: 0px; /* Tighten the gap between the Members and Settings tabs (default leaves too much). */ --tabs-tab-gap: -12px; } /* Tab pages sit below the tab bar, which already provides the horizontal rule. The page sizes to its content (so neither tab leaves an empty gap), growing until the dialog reaches its max-height (see WorkspaceSettingsDialog: 20vh top anchor + 70vh max), past which the members list scrolls while the name/invite/tabs stay put. The 70vh − 280px bound matches the dialog's max-height minus the fixed content above this page, so the list fills exactly the available space. The scroll container clips both axes (CSS forces overflow-x to clip when overflow-y is auto), so bleed it 12px past the content on each side — matching the tab strip — and pad it back, giving row hover highlights and the member role select room to render without clipping their corners. */ .tabPage { padding: 16px 12px 0; margin: 0 -12px; max-height: calc(70vh - 280px); /* Hidden by default so no scrollbar shows when the content fits. The component measures the content and adds .scrollable to flip overflow to auto only when it actually overflows — avoids a permanent scrollbar/gutter on systems that always render scrollbars. */ overflow-y: hidden; } .tabPage.scrollable { overflow-y: auto; } /* The toggle row and the action links below it sit at the content edge (no inset), so their labels line up with the section headings and tab labels above. */ .settingsPage { display: flex; flex-direction: column; } /* Regenerate / leave / delete render as text links rather than full menu buttons. align-self keeps each one's hit target tight to its text, while the toggle row above still stretches full width for its label + switch. */ .inlineButton { align-self: flex-start; padding: 4px 0; background: none; border: none; cursor: pointer; font-size: 12px; font-weight: 500; color: var(--tl-color-text-0); text-align: left; height: 36px; } @media (hover: hover) { .inlineButton:hover:not(:disabled) { text-decoration: underline; } } .inlineButton:disabled { color: var(--tl-color-text-3); cursor: not-allowed; } /* Destructive action ("Delete workspace"). */ .inlineButtonDanger { color: var(--tl-color-danger); } .copyInviteLinkIconRight { right: 12.5px !important; }