mirror of
https://github.com/gristlabs/grist-core.git
synced 2026-03-02 04:09:24 +00:00
(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:
@@ -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}`;
|
||||
}
|
||||
}
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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};
|
||||
`);
|
||||
|
||||
@@ -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',
|
||||
},
|
||||
}),
|
||||
|
||||
@@ -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};
|
||||
|
||||
@@ -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};
|
||||
}
|
||||
`);
|
||||
|
||||
|
||||
@@ -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), () => {
|
||||
|
||||
@@ -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};
|
||||
}
|
||||
`);
|
||||
|
||||
|
||||
@@ -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;
|
||||
`);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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(),
|
||||
|
||||
@@ -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};
|
||||
|
||||
@@ -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};
|
||||
}
|
||||
`);
|
||||
|
||||
|
||||
@@ -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};
|
||||
}
|
||||
`);
|
||||
|
||||
|
||||
@@ -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() {
|
||||
|
||||
@@ -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', `
|
||||
|
||||
@@ -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'),
|
||||
),
|
||||
|
||||
@@ -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', `
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user