mirror of
https://github.com/gristlabs/grist-core.git
synced 2024-10-27 20:44:07 +00:00
feat(ColumnDesc): Info Tooltip with column desc in DetailView
This commit is contained in:
parent
969280629b
commit
f0dc24306a
@ -37,13 +37,6 @@
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.g_record_detail_description {
|
||||
min-height: 1rem;
|
||||
color: #666;
|
||||
font-size: 0.9rem;
|
||||
font-weight: normal;
|
||||
margin-bottom: 2px;
|
||||
}
|
||||
.g_record_detail_value {
|
||||
position: relative;
|
||||
min-height: 16px;
|
||||
@ -237,7 +230,7 @@
|
||||
padding: 1px 1px 1px 5px;
|
||||
}
|
||||
|
||||
.detail_theme_field_form > .g_record_detail_label {
|
||||
.detail_theme_field_form>.g_record_detail_label {
|
||||
font-size: var(--grist-small-font-size);
|
||||
color: var(--grist-theme-card-form-label, var(--grist-color-slate));
|
||||
font-weight: bold;
|
||||
@ -248,16 +241,11 @@
|
||||
margin-right: -8px;
|
||||
}
|
||||
|
||||
.detail_theme_field_form>.g_record_detail_description {
|
||||
font-size: var(--grist-small-font-size);
|
||||
color: var(--grist-theme-card-form-label, var(--grist-color-slate));
|
||||
font-weight: normal;
|
||||
min-height: 0px;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
margin-right: -8px;
|
||||
.detail_theme_field_form .info_toggle_icon {
|
||||
width: 13px;
|
||||
height: 13px;
|
||||
}
|
||||
|
||||
/* TODO want to style better the values themselves (e.g. more padding, rounded corners, move label
|
||||
* inside value box for compact view for better cursor looks, etc), but first the cell editor
|
||||
* needs to learn to match the value box's style. Right now, the cell editor style is hard-coded.
|
||||
|
@ -15,6 +15,7 @@ const RecordLayout = require('./RecordLayout');
|
||||
const commands = require('./commands');
|
||||
const {RowContextMenu} = require('../ui/RowContextMenu');
|
||||
const {parsePasteForView} = require("./BaseView2");
|
||||
const {withInfoTooltip} = require('../ui/tooltips');
|
||||
|
||||
/**
|
||||
* DetailView component implements a list of record layouts.
|
||||
@ -227,8 +228,11 @@ DetailView.prototype.buildFieldDom = function(field, row) {
|
||||
if (field.isNewField) {
|
||||
return dom('div.g_record_detail_el.flexitem',
|
||||
kd.cssClass(function() { return 'detail_theme_field_' + self.viewSection.themeDef(); }),
|
||||
dom('div.g_record_detail_label', field.label),
|
||||
dom('div.g_record_detail_description', field.description),
|
||||
field.description.peek() ?
|
||||
withInfoTooltip(
|
||||
dom('div.g_record_detail_label', kd.text(field.displayLabel)),
|
||||
dom('div.g_record_detail_description', kd.text(field.description)),
|
||||
) : dom('div.g_record_detail_label', kd.text(field.displayLabel)),
|
||||
dom('div.g_record_detail_value', field.value)
|
||||
);
|
||||
}
|
||||
@ -258,8 +262,11 @@ DetailView.prototype.buildFieldDom = function(field, row) {
|
||||
dom.autoDispose(isCellSelected),
|
||||
dom.autoDispose(isCellActive),
|
||||
kd.cssClass(function() { return 'detail_theme_field_' + self.viewSection.themeDef(); }),
|
||||
field.description.peek() ?
|
||||
withInfoTooltip(
|
||||
dom('div.g_record_detail_label', kd.text(field.displayLabel)),
|
||||
dom('div.g_record_detail_description', kd.text(field.description)),
|
||||
) : dom('div.g_record_detail_label', kd.text(field.displayLabel)),
|
||||
dom('div.g_record_detail_value',
|
||||
kd.toggleClass('scissors', isCopyActive),
|
||||
kd.toggleClass('record-add', row._isAddRow),
|
||||
|
@ -2,7 +2,7 @@ import {DocPageModel} from 'app/client/models/DocPageModel';
|
||||
import {urlState} from 'app/client/models/gristUrlState';
|
||||
import {docListHeader} from 'app/client/ui/DocMenuCss';
|
||||
import {GristTooltips, TooltipContentFunc} from 'app/client/ui/GristTooltips';
|
||||
import {withInfoTooltip} from 'app/client/ui/tooltips';
|
||||
import { withQuestionMarkTooltip } from 'app/client/ui/tooltips';
|
||||
import {mediaXSmall, theme} from 'app/client/ui2018/cssVars';
|
||||
import {icon} from 'app/client/ui2018/icons';
|
||||
import {loadingDots, loadingSpinner} from 'app/client/ui2018/loaders';
|
||||
@ -284,7 +284,7 @@ function buildUsageMetric(options: MetricOptions, ...domArgs: DomElementArg[]) {
|
||||
return cssUsageMetric(
|
||||
cssMetricName(
|
||||
tooltipContentFunc
|
||||
? withInfoTooltip(
|
||||
? withQuestionMarkTooltip(
|
||||
cssOverflowableText(name, testId('name')),
|
||||
tooltipContentFunc()
|
||||
)
|
||||
|
@ -5,7 +5,7 @@ import {BEHAVIOR, ColumnRec} from 'app/client/models/entities/ColumnRec';
|
||||
import {buildHighlightedCode, cssCodeBlock} from 'app/client/ui/CodeHighlight';
|
||||
import {GristTooltips} from 'app/client/ui/GristTooltips';
|
||||
import {cssBlockedCursor, cssLabel, cssRow} from 'app/client/ui/RightPanelStyles';
|
||||
import {withInfoTooltip} from 'app/client/ui/tooltips';
|
||||
import { withQuestionMarkTooltip } from 'app/client/ui/tooltips';
|
||||
import {buildFormulaTriggers} from 'app/client/ui/TriggerFormulas';
|
||||
import {textButton} from 'app/client/ui2018/buttons';
|
||||
import {testId, theme} from 'app/client/ui2018/cssVars';
|
||||
@ -371,7 +371,7 @@ export function buildFormulaConfig(
|
||||
dom.prop("disabled", disableOtherActions),
|
||||
testId("field-set-formula")
|
||||
)),
|
||||
cssRow(withInfoTooltip(
|
||||
cssRow(withQuestionMarkTooltip(
|
||||
textButton(
|
||||
t("Set trigger formula"),
|
||||
dom.on("click", setTrigger),
|
||||
@ -424,7 +424,7 @@ export function buildFormulaConfig(
|
||||
// Else offer a way to convert to trigger formula.
|
||||
dom.maybe((use) => !(use(maybeTrigger) || use(origColumn.hasTriggerFormula)), () => [
|
||||
cssEmptySeparator(),
|
||||
cssRow(withInfoTooltip(
|
||||
cssRow(withQuestionMarkTooltip(
|
||||
textButton(
|
||||
t("Set trigger formula"),
|
||||
dom.on("click", convertDataColumnToTriggerColumn),
|
||||
|
@ -5,7 +5,7 @@ import { reportError } from 'app/client/models/AppModel';
|
||||
import { ColumnRec, TableRec, ViewSectionRec } from 'app/client/models/DocModel';
|
||||
import { GristTooltips } from 'app/client/ui/GristTooltips';
|
||||
import { linkId, NoLink } from 'app/client/ui/selectBy';
|
||||
import { withInfoTooltip } from 'app/client/ui/tooltips';
|
||||
import { withQuestionMarkTooltip } from 'app/client/ui/tooltips';
|
||||
import { getWidgetTypes, IWidgetType } from 'app/client/ui/widgetTypes';
|
||||
import { bigPrimaryButton } from "app/client/ui2018/buttons";
|
||||
import { theme, vars } from "app/client/ui2018/cssVars";
|
||||
@ -358,7 +358,7 @@ export class PageWidgetSelect extends Disposable {
|
||||
cssFooterContent(
|
||||
// If _selectByOptions exists and has more than then "NoLinkOption", show the selector.
|
||||
dom.maybe((use) => this._selectByOptions && use(this._selectByOptions).length > 1, () =>
|
||||
withInfoTooltip(
|
||||
withQuestionMarkTooltip(
|
||||
cssSelectBy(
|
||||
cssSmallLabel('SELECT BY'),
|
||||
dom.update(cssSelect(this._value.link, this._selectByOptions!),
|
||||
|
@ -5,7 +5,7 @@ import {docUrl, urlState} from 'app/client/models/gristUrlState';
|
||||
import {GristTooltips} from 'app/client/ui/GristTooltips';
|
||||
import {makeCopy, replaceTrunkWithFork} from 'app/client/ui/MakeCopyMenu';
|
||||
import {sendToDrive} from 'app/client/ui/sendToDrive';
|
||||
import {hoverTooltip, withInfoTooltip} from 'app/client/ui/tooltips';
|
||||
import { hoverTooltip, withQuestionMarkTooltip } from 'app/client/ui/tooltips';
|
||||
import {cssHoverCircle, cssTopBarBtn} from 'app/client/ui/TopBarCss';
|
||||
import {primaryButton} from 'app/client/ui2018/buttons';
|
||||
import {mediaXSmall, testId, theme} from 'app/client/ui2018/cssVars';
|
||||
@ -207,7 +207,7 @@ function menuWorkOnCopy(pageModel: DocPageModel) {
|
||||
return [
|
||||
menuItem(makeUnsavedCopy, t("Work on a Copy"), testId('work-on-copy')),
|
||||
menuText(
|
||||
withInfoTooltip(
|
||||
withQuestionMarkTooltip(
|
||||
t("Edit without affecting the original"),
|
||||
GristTooltips.workOnACopy(),
|
||||
{tooltipMenuOptions: {attach: null}}
|
||||
|
@ -28,7 +28,7 @@ import {UserManagerModel, UserManagerModelImpl} from 'app/client/models/UserMana
|
||||
import {getResourceParent, ResourceType} from 'app/client/models/UserManagerModel';
|
||||
import {GristTooltips} from 'app/client/ui/GristTooltips';
|
||||
import {shadowScroll} from 'app/client/ui/shadowScroll';
|
||||
import {hoverTooltip, ITooltipControl, showTransientTooltip, withInfoTooltip} from 'app/client/ui/tooltips';
|
||||
import { hoverTooltip, ITooltipControl, showTransientTooltip, withQuestionMarkTooltip } from 'app/client/ui/tooltips';
|
||||
import {createUserImage} from 'app/client/ui/UserImage';
|
||||
import {cssMemberBtn, cssMemberImage, cssMemberListItem,
|
||||
cssMemberPrimary, cssMemberSecondary, cssMemberText, cssMemberType, cssMemberTypeProblem,
|
||||
@ -169,7 +169,7 @@ function buildUserManagerModal(
|
||||
testId('um-cancel')
|
||||
),
|
||||
(model.resourceType === 'document' && model.gristDoc && !model.isPersonal
|
||||
? withInfoTooltip(
|
||||
? withQuestionMarkTooltip(
|
||||
cssLink({href: urlState().makeUrl({docPage: 'acl'})},
|
||||
dom.text(use => use(model.isAnythingChanged) ? 'Save & ' : ''),
|
||||
'Open Access Rules',
|
||||
|
@ -9,7 +9,7 @@ import {prepareForTransition} from 'app/client/ui/transitions';
|
||||
import {testId, theme, vars} from 'app/client/ui2018/cssVars';
|
||||
import {icon} from 'app/client/ui2018/icons';
|
||||
import {menuCssClass} from 'app/client/ui2018/menus';
|
||||
import {dom, DomContents, DomElementArg, DomElementMethod, styled} from 'grainjs';
|
||||
import { dom, DomContents, DomElementArg, DomElementMethod, IDomArgs, styled } from 'grainjs';
|
||||
import Popper from 'popper.js';
|
||||
import {cssMenu, defaultMenuOptions, IMenuOptions, setPopupToCreateDom} from 'popweasel';
|
||||
|
||||
@ -240,43 +240,59 @@ export function tooltipCloseButton(ctl: ITooltipControl): HTMLElement {
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders an info icon that shows a tooltip with the specified `content` on click.
|
||||
* Renders an icon that shows a tooltip with the specified `content` on click.
|
||||
*/
|
||||
function infoTooltip(content: DomContents, menuOptions?: IMenuOptions, ...domArgs: DomElementArg[]) {
|
||||
return cssInfoTooltipButton('?',
|
||||
(elem) => {
|
||||
function iconTooltip(
|
||||
cssStyledFunc: (...args: IDomArgs<HTMLElement>) => HTMLElement,
|
||||
tooltipButtonContent: HTMLElement,
|
||||
content: DomContents,
|
||||
menuOptions?: IMenuOptions,
|
||||
...domArgs: DomElementArg[]
|
||||
) {
|
||||
return cssStyledFunc(tooltipButtonContent, (elem) => {
|
||||
setPopupToCreateDom(
|
||||
elem,
|
||||
(ctl) => {
|
||||
return cssInfoTooltipPopup(
|
||||
cssInfoTooltipPopupCloseButton(
|
||||
icon('CrossSmall'),
|
||||
dom.on('click', () => ctl.close()),
|
||||
testId('info-tooltip-close'),
|
||||
),
|
||||
cssInfoTooltipPopupBody(
|
||||
content,
|
||||
testId('info-tooltip-popup-body'),
|
||||
icon("CrossSmall"),
|
||||
dom.on("click", () => ctl.close()),
|
||||
testId("info-tooltip-close")
|
||||
),
|
||||
cssInfoTooltipPopupBody(content, testId("info-tooltip-popup-body")),
|
||||
dom.cls(menuCssClass),
|
||||
dom.cls(cssMenu.className),
|
||||
dom.onKeyDown({
|
||||
Enter: () => ctl.close(),
|
||||
Escape: () => ctl.close(),
|
||||
}),
|
||||
(popup) => { setTimeout(() => popup.focus(), 0); },
|
||||
testId('info-tooltip-popup'),
|
||||
(popup) => {
|
||||
setTimeout(() => popup.focus(), 0);
|
||||
},
|
||||
testId("info-tooltip-popup")
|
||||
);
|
||||
},
|
||||
{...defaultMenuOptions, ...{placement: 'bottom-end'}, ...menuOptions},
|
||||
);
|
||||
},
|
||||
testId('info-tooltip'),
|
||||
...domArgs,
|
||||
{ ...defaultMenuOptions, ...{ placement: "bottom-end" }, ...menuOptions }
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
export interface WithInfoTooltipOptions {
|
||||
function questionMarkTooltip(content: DomContents, menuOptions?: IMenuOptions, ...domArgs: DomElementArg[]) {
|
||||
return iconTooltip(
|
||||
cssQuestionMarkTooltipButton,
|
||||
cssQuestionMark('?', testId('info-tooltip'), ...domArgs),
|
||||
content,
|
||||
menuOptions);
|
||||
}
|
||||
|
||||
function infoTooltip(content: DomContents, menuOptions?: IMenuOptions, ...domArgs: DomElementArg[]) {
|
||||
return iconTooltip(
|
||||
cssInfoTooltipButton,
|
||||
icon('Info', dom.cls('info_toggle_icon'), testId('info-tooltip'), ...domArgs),
|
||||
content, menuOptions);
|
||||
}
|
||||
|
||||
export interface WithIconTooltipOptions {
|
||||
domArgs?: DomElementArg[];
|
||||
tooltipButtonDomArgs?: DomElementArg[];
|
||||
tooltipMenuOptions?: IMenuOptions;
|
||||
@ -296,17 +312,30 @@ export interface WithInfoTooltipOptions {
|
||||
*
|
||||
* Usage:
|
||||
*
|
||||
* withInfoTooltip(
|
||||
* withQuestionMarkTooltip(
|
||||
* dom('div', 'Hello World!'),
|
||||
* dom('p', 'This is some text to show inside the tooltip.'),
|
||||
* )
|
||||
*/
|
||||
export function withQuestionMarkTooltip(
|
||||
domContents: DomContents,
|
||||
tooltipContent: DomContents,
|
||||
options: WithIconTooltipOptions = {},
|
||||
) {
|
||||
const { domArgs, tooltipButtonDomArgs, tooltipMenuOptions } = options;
|
||||
return cssDomWithTooltip(
|
||||
domContents,
|
||||
questionMarkTooltip(tooltipContent, tooltipMenuOptions, tooltipButtonDomArgs),
|
||||
...(domArgs ?? [])
|
||||
);
|
||||
}
|
||||
|
||||
export function withInfoTooltip(
|
||||
domContents: DomContents,
|
||||
tooltipContent: DomContents,
|
||||
options: WithInfoTooltipOptions = {},
|
||||
options: WithIconTooltipOptions = {},
|
||||
) {
|
||||
const {domArgs, tooltipButtonDomArgs, tooltipMenuOptions} = options;
|
||||
const { domArgs, tooltipButtonDomArgs, tooltipMenuOptions } = options;
|
||||
return cssDomWithTooltip(
|
||||
domContents,
|
||||
infoTooltip(tooltipContent, tooltipMenuOptions, tooltipButtonDomArgs),
|
||||
@ -347,7 +376,7 @@ const cssTooltipCloseButton = styled('div', `
|
||||
}
|
||||
`);
|
||||
|
||||
const cssInfoTooltipButton = styled('div', `
|
||||
const cssQuestionMark = styled('div', `
|
||||
flex-shrink: 0;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
@ -366,6 +395,25 @@ const cssInfoTooltipButton = styled('div', `
|
||||
}
|
||||
`);
|
||||
|
||||
const cssQuestionMarkTooltipButton = styled('div', `
|
||||
cursor: pointer;
|
||||
`);
|
||||
|
||||
const cssInfoTooltipButton = styled('div', `
|
||||
cursor: pointer;
|
||||
--icon-color: ${theme.infoButtonFg};
|
||||
border-radius: 50%;
|
||||
&:hover {
|
||||
--icon-color: ${theme.infoButtonHoverFg};
|
||||
}
|
||||
&:active {
|
||||
--icon-color: ${theme.infoButtonActiveFg};
|
||||
}
|
||||
& > .info_toggle_icon {
|
||||
display: block; /* don't create a line */
|
||||
}
|
||||
`);
|
||||
|
||||
const cssInfoTooltipPopup = styled('div', `
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
@ -605,10 +605,10 @@ export const theme = {
|
||||
menuToggleBg: new CustomProp('theme-menu-toggle-bg', undefined, 'white'),
|
||||
menuToggleBorder: new CustomProp('theme-menu-toggle-border', undefined, colors.slate),
|
||||
|
||||
/* Info Toggles */
|
||||
infoToggleFg: new CustomProp('theme-info-toggle-fg', undefined, "#8F8F8F"),
|
||||
infoToggleHoverFg: new CustomProp('theme-info-toggle-hover-fg', undefined, "#707070"),
|
||||
infoToggleActiveFg: new CustomProp('theme-info-toggle-active-fg', undefined, "#5C5C5C"),
|
||||
/* Info Button */
|
||||
infoButtonFg: new CustomProp('theme-info-button-fg', undefined, "#8F8F8F"),
|
||||
infoButtonHoverFg: new CustomProp('theme-info-button-hover-fg', undefined, "#707070"),
|
||||
infoButtonActiveFg: new CustomProp('theme-info-button-active-fg', undefined, "#5C5C5C"),
|
||||
|
||||
/* Button Groups */
|
||||
buttonGroupFg: new CustomProp('theme-button-group-fg', undefined, colors.dark),
|
||||
|
@ -6,7 +6,7 @@ import {RuleOwner} from 'app/client/models/RuleOwner';
|
||||
import {Style} from 'app/client/models/Styles';
|
||||
import {cssFieldFormula} from 'app/client/ui/FieldConfig';
|
||||
import {GristTooltips} from 'app/client/ui/GristTooltips';
|
||||
import {withInfoTooltip} from 'app/client/ui/tooltips';
|
||||
import { withQuestionMarkTooltip } from 'app/client/ui/tooltips';
|
||||
import {textButton} from 'app/client/ui2018/buttons';
|
||||
import {ColorOption, colorSelect} from 'app/client/ui2018/ColorSelect';
|
||||
import {theme, vars} from 'app/client/ui2018/cssVars';
|
||||
@ -71,7 +71,7 @@ export class ConditionalStyle extends Disposable {
|
||||
return [
|
||||
cssRow(
|
||||
{ style: 'margin-top: 16px' },
|
||||
withInfoTooltip(
|
||||
withQuestionMarkTooltip(
|
||||
textButton(
|
||||
t('Add conditional style'),
|
||||
testId('add-conditional-style'),
|
||||
|
Loading…
Reference in New Issue
Block a user