@activecollab/components
Version:
ActiveCollab Components
201 lines (181 loc) • 9.86 kB
JavaScript
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