(core) Add new home page cards

Summary:
New cards on the home page link to useful resources like the welcome
video, tutorial, webinars, and the Help Center. They are shown by
default to new and exisiting users, and may be hidden via a toggle.

Test Plan: Browser tests.

Reviewers: jarek

Reviewed By: jarek

Differential Revision: https://phab.getgrist.com/D4340
This commit is contained in:
George Gevoian
2024-09-12 13:10:55 -04:00
parent 839bf63b9f
commit da6c39aa50
34 changed files with 1055 additions and 999 deletions

View File

@@ -33,6 +33,8 @@ export interface UserPrefs extends Prefs {
dismissedWelcomePopups?: DismissedReminder[];
// Localization support.
locale?: string;
// If only documents should be shown on the All Documents page.
onlyShowDocuments?: boolean;
}
// A collection of preferences related to a combination of user and org.
@@ -112,9 +114,9 @@ export const DismissedPopup = StringUnion(
'supportGrist', // nudge to opt in to telemetry
'publishForm', // confirmation for publishing a form
'unpublishForm', // confirmation for unpublishing a form
'onboardingCards', // onboarding cards shown on the doc menu
/* Deprecated */
'onboardingCards', // onboarding cards shown on the doc menu
'tutorialFirstCard', // first card of the tutorial
);
export type DismissedPopup = typeof DismissedPopup.type;

View File

@@ -90,6 +90,7 @@ export const ThemeColors = t.iface([], {
"modal-backdrop-close-button-fg": "string",
"modal-backdrop-close-button-hover-fg": "string",
"popup-bg": "string",
"popup-secondary-bg": "string",
"popup-shadow-inner": "string",
"popup-shadow-outer": "string",
"popup-close-button-fg": "string",

View File

@@ -106,6 +106,7 @@ export interface ThemeColors {
/* Popups */
'popup-bg': string;
'popup-secondary-bg': string;
'popup-shadow-inner': string;
'popup-shadow-outer': string;
'popup-close-button-fg': string;

View File

@@ -367,7 +367,7 @@ export interface UserAPI {
getOrg(orgId: number|string): Promise<Organization>;
getOrgWorkspaces(orgId: number|string, includeSupport?: boolean): Promise<Workspace[]>;
getOrgUsageSummary(orgId: number|string): Promise<OrgUsageSummary>;
getTemplates(onlyFeatured?: boolean): Promise<Workspace[]>;
getTemplates(): Promise<Workspace[]>;
getTemplate(docId: string): Promise<Document>;
getDoc(docId: string): Promise<Document>;
newOrg(props: Partial<OrganizationProperties>): Promise<number>;
@@ -584,8 +584,8 @@ export class UserAPIImpl extends BaseAPI implements UserAPI {
return this.requestJson(`${this._url}/api/orgs/${orgId}/usage`, { method: 'GET' });
}
public async getTemplates(onlyFeatured: boolean = false): Promise<Workspace[]> {
return this.requestJson(`${this._url}/api/templates?onlyFeatured=${onlyFeatured ? 1 : 0}`, { method: 'GET' });
public async getTemplates(): Promise<Workspace[]> {
return this.requestJson(`${this._url}/api/templates`, { method: 'GET' });
}
public async getTemplate(docId: string): Promise<Document> {

View File

@@ -96,6 +96,7 @@ export const commonUrls = {
plans: "https://www.getgrist.com/pricing",
contact: "https://www.getgrist.com/contact",
templates: 'https://www.getgrist.com/templates',
webinars: getWebinarsUrl(),
community: 'https://community.getgrist.com',
functions: 'https://support.getgrist.com/functions',
formulaSheet: 'https://support.getgrist.com/formula-cheat-sheet',
@@ -703,6 +704,9 @@ export interface GristLoadConfig {
// Url for "contact support" button on Grist's "not found" error page
contactSupportUrl?: string;
// Url for webinars.
webinarsUrl?: string;
// When set, this directs the client to encode org information in path, not in domain.
pathOnly?: boolean;
@@ -907,7 +911,7 @@ export function getKnownOrg(): string|null {
export function getHelpCenterUrl(): string {
const defaultUrl = "https://support.getgrist.com";
if(isClient()) {
if (isClient()) {
const gristConfig: GristLoadConfig = (window as any).gristConfig;
return gristConfig && gristConfig.helpCenterUrl || defaultUrl;
} else {
@@ -916,7 +920,7 @@ export function getHelpCenterUrl(): string {
}
export function getTermsOfServiceUrl(): string|undefined {
if(isClient()) {
if (isClient()) {
const gristConfig: GristLoadConfig = (window as any).gristConfig;
return gristConfig && gristConfig.termsOfServiceUrl || undefined;
} else {
@@ -926,7 +930,7 @@ export function getTermsOfServiceUrl(): string|undefined {
export function getFreeCoachingCallUrl(): string {
const defaultUrl = "https://calendly.com/grist-team/grist-free-coaching-call";
if(isClient()) {
if (isClient()) {
const gristConfig: GristLoadConfig = (window as any).gristConfig;
return gristConfig && gristConfig.freeCoachingCallUrl || defaultUrl;
} else {
@@ -935,8 +939,8 @@ export function getFreeCoachingCallUrl(): string {
}
export function getContactSupportUrl(): string {
const defaultUrl = "https://www.getgrist.com/contact/";
if(isClient()) {
const defaultUrl = "https://www.getgrist.com/contact";
if (isClient()) {
const gristConfig: GristLoadConfig = (window as any).gristConfig;
return gristConfig && gristConfig.contactSupportUrl || defaultUrl;
} else {
@@ -944,6 +948,16 @@ export function getContactSupportUrl(): string {
}
}
export function getWebinarsUrl(): string {
const defaultUrl = "https://www.getgrist.com/webinars";
if (isClient()) {
const gristConfig: GristLoadConfig = (window as any).gristConfig;
return gristConfig && gristConfig.webinarsUrl || defaultUrl;
} else {
return process.env.GRIST_WEBINARS_URL || defaultUrl;
}
}
/**
* Like getKnownOrg, but respects singleOrg/GRIST_SINGLE_ORG strictly.
* The main difference in behavior would be for orgs with custom domains

View File

@@ -85,6 +85,7 @@ export const GristDark: ThemeColors = {
/* Popups */
'popup-bg': '#32323F',
'popup-secondary-bg': '#262633',
'popup-shadow-inner': '#000000',
'popup-shadow-outer': '#000000',
'popup-close-button-fg': '#A4A4B1',

View File

@@ -85,6 +85,7 @@ export const GristLight: ThemeColors = {
/* Popups */
'popup-bg': 'white',
'popup-secondary-bg': '#F7F7F7',
'popup-shadow-inner': 'rgba(31, 37, 50, 0.31)',
'popup-shadow-outer': 'rgba(76, 86, 103, 0.24)',
'popup-close-button-fg': '#929299',