(core) Polish dark mode and remove beta tag

Summary:
Polishes support for dark mode and enables syncing with the OS theme
by default.

Test Plan: Manual.

Reviewers: JakubSerafin

Reviewed By: JakubSerafin

Subscribers: JakubSerafin

Differential Revision: https://phab.getgrist.com/D4041
This commit is contained in:
George Gevoian
2023-09-21 12:57:58 -04:00
parent d1826987bb
commit 273b976cab
87 changed files with 979 additions and 651 deletions

View File

@@ -18,7 +18,8 @@ import {getGristConfig} from 'app/common/urlUtils';
import {FullUser} from 'app/common/UserAPI';
import {detectCurrentLang, makeT} from 'app/client/lib/localization';
import {translateLocale} from 'app/client/ui/LanguageMenu';
import {Computed, Disposable, dom, domComputed, makeTestId, Observable, styled} from 'grainjs';
import {getPageTitleSuffix} from 'app/common/gristUrls';
import {Computed, Disposable, dom, domComputed, makeTestId, Observable, styled, subscribe} from 'grainjs';
const testId = makeTestId('test-account-page-');
const t = makeT('AccountPage');
@@ -27,6 +28,7 @@ const t = makeT('AccountPage');
* Creates the account page where a user can manage their profile settings.
*/
export class AccountPage extends Disposable {
private readonly _currentPage = Computed.create(this, urlState().state, (_use, s) => s.account);
private _apiKey = Observable.create<string>(this, '');
private _userObs = Observable.create<FullUser|null>(this, null);
private _isEditingName = Observable.create(this, false);
@@ -37,6 +39,7 @@ export class AccountPage extends Disposable {
constructor(private _appModel: AppModel) {
super();
this._setPageTitle();
this._fetchAll().catch(reportError);
}
@@ -228,6 +231,18 @@ designed to ensure that you're the only person who can access your account, even
testId('username-warning'),
);
}
private _setPageTitle() {
this.autoDispose(subscribe(this._currentPage, (_use, page): string => {
const suffix = getPageTitleSuffix(getGristConfig());
switch (page) {
case undefined:
case 'account': {
return document.title = `Account${suffix}`;
}
}
}));
}
}
/**

View File

@@ -100,10 +100,3 @@ export const dataRow = styled('div', `
align-items: baseline;
gap: 2px;
`);
export const betaTag = styled('span', `
text-transform: uppercase;
vertical-align: super;
font-size: ${vars.xsmallFontSize};
color: ${theme.accentText};
`);

View File

@@ -354,11 +354,6 @@ export function columnFilterMenu(owner: IDisposableOwner, opts: IFilterMenuOptio
gristDoc.behavioralPromptsManager.attachTip('filterButtons', {
popupOptions: {
attach: null,
modifiers: {
flip: {
behavior: ['right', 'top'],
},
},
placement: 'right',
},
}),

View File

@@ -55,6 +55,7 @@ const cssTextArea = styled(textarea, `
border-radius: 3px;
padding: 3px 7px;
min-height: calc(3em * 1.5);
resize: none;
&::placeholder {
color: ${theme.inputPlaceholderFg};

View File

@@ -470,18 +470,17 @@ const cssToggleButton = styled(cssIconButton, `
margin-left: 8px;
background-color: ${theme.rightPanelToggleButtonDisabledBg};
box-shadow: inset 0 0 0 1px ${theme.inputBorder};
cursor: pointer;
&-selected, &-selected:hover {
box-shadow: none;
background-color: ${theme.rightPanelToggleButtonEnabledBg};
--icon-color: ${theme.rightPanelToggleButtonEnabledFg};
}
&-selected:hover {
--icon-color: ${theme.rightPanelToggleButtonEnabledHoverFg};
}
&-disabled, &-disabled:hover {
--icon-color: ${theme.rightPanelToggleButtonDisabledFg};
cursor: not-allowed;
background-color: ${theme.rightPanelToggleButtonDisabledBg};
--icon-color: ${theme.iconDisabled};
}
`);

View File

@@ -293,7 +293,7 @@ export class FloatingPopup extends Disposable {
const body = cssPopup(
{tabIndex: '-1'},
cssPopup.cls('-auto', this._options.autoHeight ?? false),
dom.style('min-height', `${this._minHeight}px`),
dom.style('min-height', use => use(this._isMinimized) ? 'unset' : `${this._minHeight}px`),
cssPopupHeader(
cssBottomHandle(testId('move-handle')),
dom.maybe(use => !use(this._isMinimized), () => {

View File

@@ -1,7 +1,7 @@
import {bigPrimaryButton as gristBigPrimaryButton,
bigPrimaryButtonLink as gristBigPrimaryButtonLink,
textButton as gristTextButton} from 'app/client/ui2018/buttons';
import {colors, mediaXSmall, theme} from 'app/client/ui2018/cssVars';
import {mediaXSmall, theme} from 'app/client/ui2018/cssVars';
import {textInput} from 'app/client/ui/inputs';
import {styled} from 'grainjs';
@@ -61,15 +61,15 @@ export const googleButton = styled('button', `
font-weight: 500;
line-height: 16px;
padding: 16px;
color: ${colors.dark};
background-color: ${colors.lightGrey};
border: 1px solid ${colors.darkGrey};
color: ${theme.loginPageGoogleButtonFg};
background-color: ${theme.loginPageGoogleButtonBg};
border: 1px solid ${theme.loginPageGoogleButtonBorder};
border-radius: 4px;
cursor: pointer;
width: 100%;
&:hover {
background-color: ${colors.mediumGrey};
background-color: ${theme.loginPageGoogleButtonBgHover};
}
`);

View File

@@ -9,6 +9,7 @@ import {find as findInTree, fromTableData, TreeItemRecord, TreeRecord,
TreeTableData} from 'app/client/models/TreeModel';
import {TreeViewComponent} from 'app/client/ui/TreeViewComponent';
import {cssRadioCheckboxOptions, radioCheckboxOption} from 'app/client/ui2018/checkbox';
import {theme} from 'app/client/ui2018/cssVars';
import {cssLink} from 'app/client/ui2018/links';
import {ISaveModalOptions, saveModal} from 'app/client/ui2018/modals';
import {buildCensoredPage, buildPageDom, PageActions} from 'app/client/ui2018/pages';
@@ -175,8 +176,8 @@ const cssWarning = styled('div', `
`);
const cssTableName = styled('div', `
color: black;
background-color: #eee;
color: ${theme.choiceTokenFg};
background-color: ${theme.choiceTokenBg};
padding: 3px 6px;
border-radius: 4px;
`);

View File

@@ -263,7 +263,7 @@ const cssPinnedDocDesc = styled(cssPinnedDocTimestamp, `
const cssImage = styled('img', `
position: relative;
background-color: ${colors.light};
background-color: ${colors.dark};
height: 100%;
width: 100%;
object-fit: scale-down;

View File

@@ -311,7 +311,6 @@ export class RightPanel extends Disposable {
]),
cssLabel(t("TRANSFORM")),
dom.maybe<FieldBuilder|null>(fieldBuilder, builder => builder.buildTransformDom()),
dom.maybe(isMultiSelect, () => disabledSection()),
testId('panel-transform'),
),
this._disableIfReadonly(),

View File

@@ -15,6 +15,7 @@ export const cssLabel = styled('div', `
`);
export const cssHelp = styled('div', `
color: ${theme.lightText};
margin: -8px 16px 12px 16px;
font-style: italic;
font-size: ${vars.xsmallFontSize};

View File

@@ -376,12 +376,11 @@ const cssMenuIconLink = styled('a', `
display: block;
flex: none;
padding: 8px 24px;
--icon-color: ${theme.controlFg};
background-color: ${theme.menuBg};
--icon-color: ${theme.menuItemLinkFg};
&:hover {
background-color: ${theme.menuItemLinkselectedBg};
--icon-color: ${theme.menuItemLinkSelectedFg};
background-color: ${theme.hover};
--icon-color: ${theme.controlHoverFg};
}
`);

View File

@@ -263,7 +263,8 @@ const cssContributeButtonCloseButton = styled(tokenFieldStyles.cssDeleteButton,
const cssCard = styled('div', `
width: 297px;
padding: 24px;
background: #DCF4EB;
color: ${theme.announcementPopupFg};
background: ${theme.announcementPopupBg};
border-radius: 4px;
align-self: flex-start;
position: sticky;
@@ -310,10 +311,10 @@ const cssCloseButton = styled('div', `
padding: 4px;
border-radius: 4px;
cursor: pointer;
--icon-color: ${colors.slate};
--icon-color: ${theme.popupCloseButtonFg};
&:hover {
background-color: ${colors.mediumGreyOpaque};
background-color: ${theme.hover};
}
`);

View File

@@ -13,16 +13,17 @@ import {mediaSmall, theme, vars} from 'app/client/ui2018/cssVars';
import {icon} from 'app/client/ui2018/icons';
import {cssLink} from 'app/client/ui2018/links';
import {loadingSpinner} from 'app/client/ui2018/loaders';
import {commonUrls} from 'app/common/gristUrls';
import {commonUrls, getPageTitleSuffix} from 'app/common/gristUrls';
import {TelemetryPrefsWithSources} from 'app/common/InstallAPI';
import {getGristConfig} from 'app/common/urlUtils';
import {Computed, Disposable, dom, makeTestId, Observable, styled} from 'grainjs';
import {Computed, Disposable, dom, makeTestId, Observable, styled, subscribe} from 'grainjs';
const testId = makeTestId('test-support-grist-page-');
const t = makeT('SupportGristPage');
export class SupportGristPage extends Disposable {
private readonly _currentPage = Computed.create(this, urlState().state, (_use, s) => s.supportGrist);
private readonly _model: TelemetryModel = new TelemetryModelImpl(this._appModel);
private readonly _optInToTelemetry = Computed.create(this, this._model.prefs,
(_use, prefs) => {
@@ -37,6 +38,7 @@ export class SupportGristPage extends Disposable {
constructor(private _appModel: AppModel) {
super();
this._setPageTitle();
this._model.fetchTelemetryPrefs().catch(reportError);
}
@@ -186,6 +188,18 @@ export class SupportGristPage extends Disposable {
testId('sponsorship-section'),
);
}
private _setPageTitle() {
this.autoDispose(subscribe(this._currentPage, (_use, page): string => {
const suffix = getPageTitleSuffix(getGristConfig());
switch (page) {
case undefined:
case 'support-grist': {
return document.title = `Support Grist${suffix}`;
}
}
}));
}
}
function telemetryHelpCenterLink() {

View File

@@ -1,5 +1,5 @@
import {docUrl, urlState} from 'app/client/models/gristUrlState';
import {colors} from 'app/client/ui2018/cssVars';
import {theme} from 'app/client/ui2018/cssVars';
import {Document, Workspace} from 'app/common/UserAPI';
import {dom, makeTestId, styled} from 'grainjs';
import {HomeModel, ViewSettings} from 'app/client/models/HomeModel';
@@ -63,7 +63,7 @@ const cssDocName = styled(css.docName, `
const cssDocRowDetails = styled('div', `
margin: 0 16px;
line-height: 1.6;
color: ${colors.slate};
color: ${theme.lightText};
`);
const cssTemplateDocs = styled('div', `

View File

@@ -2,6 +2,7 @@ import {makeT} from 'app/client/lib/localization';
import {AppModel} from 'app/client/models/AppModel';
import * as css from 'app/client/ui/AccountPageCss';
import {labeledSquareCheckbox} from 'app/client/ui2018/checkbox';
import {prefersDarkModeObs} from 'app/client/ui2018/cssVars';
import {select} from 'app/client/ui2018/menus';
import {ThemeAppearance} from 'app/common/ThemePrefs';
import {Computed, Disposable, dom, makeTestId, styled} from 'grainjs';
@@ -12,21 +13,30 @@ const t = makeT('ThemeConfig');
export class ThemeConfig extends Disposable {
private _themePrefs = this._appModel.themePrefs;
private _appearance = Computed.create(this, this._themePrefs, (_use, prefs) => {
return prefs.appearance;
}).onWrite((value) => this._updateAppearance(value));
private _syncWithOS = Computed.create(this, this._themePrefs, (_use, prefs) => {
return prefs.syncWithOS;
}).onWrite((value) => this._updateSyncWithOS(value));
private _appearance = Computed.create(this,
this._themePrefs,
this._syncWithOS,
prefersDarkModeObs(),
(_use, prefs, syncWithOS, prefersDarkMode) => {
if (syncWithOS) {
return prefersDarkMode ? 'dark' : 'light';
} else {
return prefs.appearance;
}
})
.onWrite((value) => this._updateAppearance(value));
constructor(private _appModel: AppModel) {
super();
}
public buildDom() {
return dom('div',
css.subHeader(t("Appearance "), css.betaTag('Beta')),
css.subHeader(t("Appearance ")),
css.dataRow(
cssAppearanceSelect(
select(
@@ -35,6 +45,9 @@ export class ThemeConfig extends Disposable {
{value: 'light', label: 'Light'},
{value: 'dark', label: 'Dark'},
],
{
disabled: this._syncWithOS,
},
),
testId('appearance'),
),

View File

@@ -263,7 +263,7 @@ const cssFilterMenuWrapper = styled('div', `
border-radius: 3px;
align-items: center;
&-unsaved {
border: 1px solid ${theme.accentBorder};
border: ${theme.controlBorder};
}
& .${cssMenu.className} {
border: none;
@@ -364,11 +364,8 @@ const cssSaveTextButton = styled('div', `
cursor: pointer;
font-size: ${vars.mediumFontSize};
padding: 0px 5px;
border-right: 1px solid ${theme.accentBorder};
&-accent {
color: ${theme.accentText};
}
color: ${theme.controlFg};
border-right: ${theme.controlBorder};
`);
const cssRevertIconButton = styled('div', `

View File

@@ -1,8 +1,8 @@
import {dom, IDomArgs, Observable, styled} from 'grainjs';
// Shadow css settings for member scroll top and bottom.
const SHADOW_TOP = 'inset 0 4px 6px 0 rgba(217,217,217,0.4)';
const SHADOW_BTM = 'inset 0 -4px 6px 0 rgba(217,217,217,0.4)';
const SHADOW_TOP = 'inset 0 4px 6px 0 var(--grist-theme-scroll-shadow, rgba(217,217,217,0.4))';
const SHADOW_BTM = 'inset 0 -4px 6px 0 var(--grist-theme-scroll-shadow, rgba(217,217,217,0.4))';
/**
* Creates a scroll div used in the UserManager and moveDoc menus to display