UNPKG

@activecollab/components

Version:

ActiveCollab Components

201 lines (181 loc) 9.86 kB
import _objectWithoutPropertiesLoose from "@babel/runtime/helpers/esm/objectWithoutPropertiesLoose"; import _extends from "@babel/runtime/helpers/esm/extends"; const _excluded = ["icon", "label", "height", "dashed"]; import React from "react"; import styled, { css } from "styled-components"; import { PlayIcon, TreeDotsIcon } from "../../../components/Icons"; import { STACKED_CARD_CONTROL_CLASS, StackedCardCollapseGlyph as CollapseGlyph, StackedCardCoverButton as CoverButton, StackedCardPlayBadge as PlayBadge, StackedCardRemoveCoverGlyph as RemoveCoverGlyph } from "../../../components/StackedCard"; import { Body2, Caption2 } from "../../../components/Typography"; import { Typography } from "../../../components/Typography/Typography"; /** * Content-level chrome shared by the typed StackedCard components. * * These live OUTSIDE the shell on purpose. The shell is hollow; the "…" entity * menu, the cover-management controls, the clamp, the favicon, the chips and * the placeholder frame are content concerns, so they belong here where the * typed cards (TaskCard, LinkCard, …) compose them. * * The card itself — the shell, the Stack/StackRow/Cover primitives and the * cover chrome — is the shipped design-system component, * `components/StackedCard`. These stories import it under the concept * vocabulary (Cover, StackRow, …) so the spec prose and the code keep using * the same words. */ /* ------------------------------------------------------------------ */ /* The font stack for raw text */ /* ------------------------------------------------------------------ */ /** * There is no global CSS reset in this Storybook, so a raw element (a `<span>` * holding a date, a `<button>` holding a word) falls back to the browser default * — a SERIF face at the UA's own size. Anything that is not a DS `Typography` * has to name the font itself. Use a DS Typography where one fits; use this * where the app itself sets the size in CSS (the column card's date row is a * plain `div` in `view.project_tasks_column_mode.less`, not a Typography). */ export const CARD_FONT = "-apple-system, BlinkMacSystemFont, \"Roboto\",\n \"Helvetica Neue\", Arial, sans-serif"; /* ------------------------------------------------------------------ */ /* Per-type cover ratios */ /* ------------------------------------------------------------------ */ /** * The design system ships one default cover ratio * (`STACKED_CARD_COVER_RATIO`). How tall a cover reads is a decision of the * content type, so the variants live here with the content: a link hero, a * full-bleed image, a colour swatch band. */ export const COVER_RATIO_HERO = "320 / 190"; export const COVER_RATIO_IMAGE = "260 / 168"; export const COVER_RATIO_SWATCH = "260 / 104"; /* ------------------------------------------------------------------ */ /* Cover chrome — media control + cover management */ /* ------------------------------------------------------------------ */ /** Centered media control (play), for a cover that wraps audio/video. */ export const playControl = /*#__PURE__*/React.createElement(PlayBadge, null, /*#__PURE__*/React.createElement(PlayIcon, null)); /** * Top-right cover management. Acts on the COVER (collapse it, remove it) — not * on the entity. Callers wire the click handlers; the default is inert chrome * for the static demos. */ export const coverManagement = function (_temp) { let _ref = _temp === void 0 ? {} : _temp, _ref$removeLabel = _ref.removeLabel, removeLabel = _ref$removeLabel === void 0 ? "Remove cover" : _ref$removeLabel, onCollapse = _ref.onCollapse, onRemove = _ref.onRemove; return /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(CoverButton, { type: "button", "aria-label": "Collapse cover", onClick: onCollapse }, /*#__PURE__*/React.createElement(CollapseGlyph, null)), /*#__PURE__*/React.createElement(CoverButton, { type: "button", "aria-label": removeLabel, onClick: onRemove }, /*#__PURE__*/React.createElement(RemoveCoverGlyph, null))); }; /* ------------------------------------------------------------------ */ /* Entity "…" menu — acts on the ENTITY, lives in a content row */ /* ------------------------------------------------------------------ */ const StyledEntityDots = styled.button.withConfig({ displayName: "shared__StyledEntityDots", componentId: "sc-1x5md9a-0" })(["display:inline-flex;align-items:center;justify-content:center;width:26px;height:26px;padding:0;border:0;border-radius:6px;cursor:pointer;color:var(--color-theme-700);background:var(--color-theme-200);svg{width:16px;height:16px;display:block;}&:hover{background:var(--color-theme-300);}"]); export const EntityDots = props => /*#__PURE__*/React.createElement(StyledEntityDots, _extends({ type: "button", "aria-label": "Options", "data-fixed": true, className: STACKED_CARD_CONTROL_CLASS }, props), /*#__PURE__*/React.createElement(TreeDotsIcon, null)); /* ------------------------------------------------------------------ */ /* Text + inline bits */ /* ------------------------------------------------------------------ */ /** Two-line title clamp — the card's name row content. */ export const StyledClamp = styled(Body2).withConfig({ displayName: "shared__StyledClamp", componentId: "sc-1x5md9a-1" })(["display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden;"]); /** * The title block — everything the title row stacks to the LEFT of the "…" * menu. A card that only has a title puts the clamp straight in the row; a card * that puts a line above or below it (the project a task belongs to, the client * a project is for) stacks them here so the row keeps its two-child shape: * text block, then the fixed-width menu. */ export const StyledTitleBlock = styled.div.withConfig({ displayName: "shared__StyledTitleBlock", componentId: "sc-1x5md9a-2" })(["display:flex;flex-direction:column;min-width:0;"]); /** * The project a card's entity lives in, above the title. * * On a canvas a task card has lost the column that used to say which project it * came from, so the card says it itself. One line, one treatment, shared by * every content type that can carry it (the whiteboard's own task face already * wrote it this way: `Caption 2` tertiary, tight above the title, ellipsis on * overflow — a project name is a reference, never a second title). */ export const StyledProjectLine = styled(Caption2).withConfig({ displayName: "shared__StyledProjectLine", componentId: "sc-1x5md9a-3" })(["display:block;margin-bottom:2px;overflow:hidden;white-space:nowrap;text-overflow:ellipsis;"]); export const CardProjectLine = _ref2 => { let children = _ref2.children; return /*#__PURE__*/React.createElement(StyledProjectLine, { color: "tertiary", className: "sc-project" }, children); }; /** A favicon square — a solid data colour stands in for the real favicon. */ export const StyledFavicon = styled.span.withConfig({ displayName: "shared__StyledFavicon", componentId: "sc-1x5md9a-4" })(["display:inline-flex;width:16px;height:16px;border-radius:4px;background:", ";flex-shrink:0;"], _ref3 => { let $bg = _ref3.$bg; return $bg; }); /** A small pill for link metadata (media kind, duration, …). */ export const StyledChip = styled.span.withConfig({ displayName: "shared__StyledChip", componentId: "sc-1x5md9a-5" })(["display:inline-flex;align-items:center;padding:2px 8px;border-radius:10px;background:var(--color-theme-300);color:var(--color-theme-800);font-size:11px;white-space:nowrap;"]); /** A solid-colour cover fill (swatch value, generic link cover, image stand-in). */ export const StyledColorCover = styled.div.withConfig({ displayName: "shared__StyledColorCover", componentId: "sc-1x5md9a-6" })(["width:100%;height:100%;background:", ";"], _ref4 => { let $color = _ref4.$color; return $color; }); /* ------------------------------------------------------------------ */ /* Placeholder frame — the interactive empty state, per type */ /* ------------------------------------------------------------------ */ const StyledPlaceholder = styled.button.withConfig({ displayName: "shared__StyledPlaceholder", componentId: "sc-1x5md9a-7" })(["display:flex;flex-direction:column;align-items:center;justify-content:center;gap:10px;width:100%;height:", "px;padding:0;border:0;background:transparent;color:var(--color-theme-600);text-align:center;cursor:pointer;", " > svg{width:40px;height:40px;color:var(--color-theme-500);}"], _ref5 => { let $height = _ref5.$height; return $height != null ? $height : 150; }, _ref6 => { let $dashed = _ref6.$dashed; return $dashed && css(["margin:8px;width:calc(100% - 16px);border:1.5px dashed var(--color-theme-400);border-radius:6px;&:hover{border-color:var(--sc-selection-ring);color:var(--color-theme-700);}"]); }); /** * The shared placeholder frame. Each type supplies its own icon and verb-first, * sentence-case invitation (ActiveCollab voice). Interactive by design — the * whole frame is a button — and distinct from the loading skeleton. */ export const Placeholder = _ref7 => { let icon = _ref7.icon, label = _ref7.label, height = _ref7.height, dashed = _ref7.dashed, rest = _objectWithoutPropertiesLoose(_ref7, _excluded); return /*#__PURE__*/React.createElement(StyledPlaceholder, _extends({ type: "button", $height: height, $dashed: dashed }, rest), icon, /*#__PURE__*/React.createElement(Typography, { as: "span", variant: "Body 2", color: "secondary" }, label)); }; //# sourceMappingURL=shared.js.map