Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: move theme options out of labs #2340

Open
wants to merge 7 commits into
base: qa
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ export function EmptyGridMessage() {
}

return (
<div className="absolute bottom-4 right-4 flex w-72 flex-col items-center rounded border border-border bg-background p-4 text-center shadow-md">
<div className="absolute bottom-4 right-4 z-10 flex w-72 flex-col items-center rounded border border-border bg-background p-4 text-center shadow-md">
<div className="flex gap-4 pb-8 pt-10">
<div className="flex flex-col items-start gap-2">
<div className="h-2 w-12 bg-foreground/15" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ import { useHeadingSize } from '@/app/gridGL/HTMLGrid/useHeadingSize';
import { HtmlValidations } from '@/app/gridGL/HTMLGrid/validations/HtmlValidations';
import { pixiApp } from '@/app/gridGL/pixiApp/PixiApp';
import { Following } from '@/app/ui/components/Following';
import { ImportProgress } from '@/app/ui/components/ImportProgress';
import { Search } from '@/app/ui/components/Search';
import type { ReactNode } from 'react';
import { useCallback, useEffect, useState } from 'react';

Expand Down Expand Up @@ -88,6 +90,7 @@ export const HTMLGridContainer = (props: Props): ReactNode | null => {
height: `calc(100% - ${topHeading}px)`,
pointerEvents: 'none',
textRendering: 'optimizeLegibility',
zIndex: 1,
}}
>
<div style={{ position: 'relative' }}>
Expand Down Expand Up @@ -118,10 +121,10 @@ export const HTMLGridContainer = (props: Props): ReactNode | null => {
</div>

<GridFileInput />

<Following />

<ImportProgress />
<EmptyGridMessage />
<Search />
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Moved these just to try and put all these elements in the same place. They were in QuadraticGrid before, but ultimately render in the same place. So I'm sticking them here where everything else is.


{/* This is positioned on the grid over the headings and not zoomed. It comes
after the above, so it's above it on the grid. */}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,7 @@ export const SuggestionDropDown = () => {
return (
<div
className={cn(
'border.gray-300 pointer-events-auto absolute cursor-pointer overflow-y-auto border bg-white text-gray-500',
'pointer-events-auto absolute cursor-pointer overflow-y-auto rounded-sm border border-border bg-background text-muted-foreground',
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

CleanShot 2025-02-28 at 10 30 05@2x

Using theme colors here rather than hard-coded colors.

inlineEditorStatus ? 'mt-1' : 'mt-0'
)}
style={{
Expand All @@ -163,7 +163,7 @@ export const SuggestionDropDown = () => {
<div className="block w-full px-1">
{filteredList.map((item, i) => (
<div
className={cn('block w-full whitespace-nowrap px-1 hover:bg-gray-100', i === index ? 'bg-gray-200' : '')}
className={cn('block w-full whitespace-nowrap px-1 hover:bg-accent', i === index ? 'bg-accent' : '')}
key={item}
onClick={() => changeValue(item)}
>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,6 @@ export class HtmlCell {
this.iframe.setAttribute('scrolling', 'no');
this.iframe.style.minWidth = `${CELL_WIDTH}px`;
this.iframe.style.minHeight = `${CELL_HEIGHT}px`;
this.iframe.style.backgroundColor = 'hsl(var(--background))';

this.border = document.createElement('div');
this.border.className = 'w-full h-full absolute top-0 left-0';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ export const HtmlCells = () => {
return (
<div
ref={divRef}
className="dark-mode-hack"
style={{
pointerEvents: 'none',
}}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ export const InlineEditor = () => {
return (
<div
ref={ref}
className="dark-mode-hack"
style={{
position: 'absolute',
display: 'flex',
Expand Down
5 changes: 0 additions & 5 deletions quadratic-client/src/app/gridGL/QuadraticGrid.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,6 @@ import { gridPanModeAtom } from '@/app/atoms/gridPanModeAtom';
import { HTMLGridContainer } from '@/app/gridGL/HTMLGrid/HTMLGridContainer';
import { useKeyboard } from '@/app/gridGL/interaction/keyboard/useKeyboard';
import { pixiApp } from '@/app/gridGL/pixiApp/PixiApp';
import { ImportProgress } from '@/app/ui/components/ImportProgress';
import { Search } from '@/app/ui/components/Search';
import type { MouseEvent } from 'react';
import { useCallback, useState } from 'react';
import { useRecoilCallback } from 'recoil';
Expand Down Expand Up @@ -37,7 +35,6 @@ export default function QuadraticGrid() {
return (
<div
ref={containerRef}
className="dark-mode-hack"
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Moved this from the parent because it was inverting everything under it. This cause HTML-rendered elements like the empty sheet message to invert to white in dark mode:

CleanShot 2025-02-28 at 12 40 25@2x

Instead, we now apply dark-mode-hack to any individual element that should be inverted. Hopefully over time we can strip these out one-by-one and apply proper theme colors.

style={{
position: 'relative',
width: '100%',
Expand All @@ -55,8 +52,6 @@ export default function QuadraticGrid() {
onKeyUp={onKeyUp}
>
<HTMLGridContainer parent={container} />
<ImportProgress />
<Search />
</div>
);
}
1 change: 1 addition & 0 deletions quadratic-client/src/app/gridGL/pixiApp/PixiApp.ts
Original file line number Diff line number Diff line change
Expand Up @@ -254,6 +254,7 @@ export class PixiApp {
if (!this.canvas) return;

this.parent = parent;
this.canvas.classList.add('dark-mode-hack');
parent.appendChild(this.canvas);
this.resize();
this.update.start();
Expand Down
2 changes: 2 additions & 0 deletions quadratic-client/src/app/ui/components/Following.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,8 @@ export const Following = () => {
</div>
<div
style={{
top: 0,
left: 0,
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

dark-mode-hack which uses filter changes stacking contexts in CSS, so this now needs a reference for its positioning since we removed it from the parent.

width: '100%',
height: '100%',
overflow: 'hidden',
Expand Down
11 changes: 5 additions & 6 deletions quadratic-client/src/app/ui/components/ImportProgress.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,22 +14,21 @@ export const ImportProgress = () => {
const abortController = files[currentFileIndex].abortController;

return (
<div className="fixed bottom-16 left-8 z-50 h-[92px] w-[403px] select-none border border-slate-200 bg-white pb-2 pl-4 pr-4 pt-2 tracking-tight shadow-[0_2px_5px_0px_rgba(0,0,0,0.15)]">
<div className="flex justify-between">
<div className="absolute bottom-4 left-4 z-50 w-96 select-none rounded border border-border bg-background pb-2 pl-4 pr-4 pt-2 tracking-tight shadow-lg">
<div className="mb-2 flex items-center justify-between">
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This element had a bunch of hard-coded values. Causing it to not work well in dark mode.

CleanShot 2025-02-28 at 12 46 44@2x

Changed all them to be theme colors.

<div className="min-w-0">
<div className="text-base font-medium">
<div className="font-medium">
Importing file {fileNo} of {totalFiles}
</div>

<div className="overflow-hidden text-ellipsis whitespace-nowrap pb-2 text-sm font-normal text-slate-500">
<div className="overflow-hidden text-ellipsis whitespace-nowrap text-sm font-normal text-muted-foreground">
{name}
</div>
</div>

<Button
variant="ghost"
variant="outline"
size="sm"
className="text-primary hover:text-primary"
disabled={abortController === undefined}
onClick={() => abortController?.abort()}
>
Expand Down
32 changes: 9 additions & 23 deletions quadratic-client/src/app/ui/components/ThemePickerMenu.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,19 +3,12 @@ import { SidebarToggle, SidebarTooltip } from '@/app/ui/QuadraticSidebar';
import { ThemeIcon } from '@/shared/components/Icons';
import { ThemeAccentColors } from '@/shared/components/ThemeAccentColors';
import { ThemeAppearanceModes } from '@/shared/components/ThemeAppearanceModes';
import { useFeatureFlag } from '@/shared/hooks/useFeatureFlag';
import { Popover, PopoverContent, PopoverTrigger } from '@/shared/shadcn/ui/popover';
import { useState } from 'react';

export const ThemePickerMenu = () => {
const [featureFlagThemeAccentColor] = useFeatureFlag('themeAccentColor');
const [featureFlagThemeAppearanceMode] = useFeatureFlag('themeAppearanceMode');
const [showThemeMenu, setShowThemeMenu] = useState(false);

if (!(featureFlagThemeAccentColor || featureFlagThemeAppearanceMode)) {
return null;
}

return (
<Popover open={showThemeMenu} onOpenChange={setShowThemeMenu}>
<SidebarTooltip label="Theme">
Expand All @@ -38,23 +31,16 @@ export const ThemePickerMenu = () => {
<h2 className="text-md font-semibold">Theme customization</h2>
<p className="mb-4 text-xs text-muted-foreground">Pick a style that fits you</p>

{featureFlagThemeAccentColor && (
<>
<h3 className="mb-1 text-xs font-semibold">Accent color</h3>
<div className="grid grid-cols-3 gap-2">
<ThemeAccentColors />
</div>
</>
)}
{featureFlagThemeAppearanceMode && (
<>
<h3 className="mb-1 mt-4 text-xs font-semibold">Appearance</h3>
<h3 className="mb-1 text-xs font-semibold">Accent color</h3>
<div className="grid grid-cols-3 gap-2">
<ThemeAccentColors />
</div>

<h3 className="mb-1 mt-4 text-xs font-semibold">Appearance</h3>

<div className="grid grid-cols-3 gap-2">
<ThemeAppearanceModes />
</div>
</>
)}
<div className="grid grid-cols-3 gap-2">
<ThemeAppearanceModes />
</div>
</PopoverContent>
</Popover>
);
Expand Down
11 changes: 7 additions & 4 deletions quadratic-client/src/dashboard/components/DashboardSidebar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { TeamSwitcher } from '@/dashboard/components/TeamSwitcher';
import { useDashboardRouteLoaderData } from '@/routes/_dashboard';
import { useRootRouteLoaderData } from '@/routes/_root';
import { getActionFileMove } from '@/routes/api.files.$uuid';
import { labFeatures } from '@/routes/labs';
import { Avatar } from '@/shared/components/Avatar';
import {
AddIcon,
Expand Down Expand Up @@ -157,10 +158,12 @@ export function DashboardSidebar({ isLoading }: { isLoading: boolean }) {
</Badge>
</SidebarNavLink>
)}
<SidebarNavLink to="/labs">
<LabsIcon className={classNameIcons} />
Labs
</SidebarNavLink>
{labFeatures.length > 0 && (
<SidebarNavLink to="/labs">
<LabsIcon className={classNameIcons} />
Labs
</SidebarNavLink>
)}
<SidebarNavLink to="/account">
<Avatar src={user?.picture} alt={user?.name}>
{user?.name}
Expand Down
8 changes: 4 additions & 4 deletions quadratic-client/src/dashboard/components/FileDragDrop.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -45,22 +45,22 @@ export function FileDragDrop({ className }: FileDragDropProps) {
<div
id="file-drag-drop"
className={cn(
'fixed left-0 top-0 z-20 flex h-full w-full flex-col items-center justify-center bg-white opacity-90',
'fixed left-0 top-0 z-20 flex h-full w-full flex-col items-center justify-center bg-background opacity-90',
className
)}
onDragEnter={handleDrag}
onDragLeave={handleDrag}
onDragOver={handleDrag}
>
<div
className="relative z-10 h-[90%] w-[90%] select-none rounded-lg border-4 border-dashed border-border bg-white opacity-90"
className="relative z-10 h-[90%] w-[90%] select-none rounded-lg border-4 border-dashed border-border bg-background opacity-90"
onDrop={handleDrop}
onDragLeave={handleDrag}
>
<div className="pointer-events-none flex h-full w-full flex-col items-center justify-center gap-2">
<span className="text-2xl font-bold text-[#020817]">Drop file here</span>
<span className="text-2xl font-bold text-foreground">Drop file here</span>

<span className="pl-4 pr-4 text-center text-base font-medium text-[#6A778B]">
<span className="pl-4 pr-4 text-center text-base font-medium text-muted-foreground">
Start a new spreadsheet by importing a CSV, Parquet, Excel or Grid file(s)
</span>
</div>
Expand Down
25 changes: 22 additions & 3 deletions quadratic-client/src/routes/account.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
import { DashboardHeader } from '@/dashboard/components/DashboardHeader';
import { useRootRouteLoaderData } from '@/routes/_root';
import { ThemeAccentColors } from '@/shared/components/ThemeAccentColors';
import { ThemeAppearanceModes } from '@/shared/components/ThemeAppearanceModes';
import { Type } from '@/shared/components/Type';
import { ROUTES } from '@/shared/constants/routes';
import { Button } from '@/shared/shadcn/ui/button';
import { cn } from '@/shared/shadcn/utils';
import type { ReactNode } from 'react';
import { Form } from 'react-router-dom';

Expand All @@ -12,7 +15,7 @@ export const Component = () => {
return (
<>
<div className="max-w-xl">
<DashboardHeader title="My account" />
<DashboardHeader title="Profile & preferences" />

<Row>
<Type variant="body2" className="font-bold">
Expand All @@ -27,6 +30,22 @@ export const Component = () => {
<Type variant="body2">{user?.email}</Type>
</Row>
<Row>
<Type variant="body2" className="font-bold">
Theme
</Type>
<div className="flex items-center gap-2">
<ThemeAccentColors />
</div>
</Row>
<Row>
<Type variant="body2" className="font-bold">
Appearance
</Type>
<div className="flex items-center gap-2">
<ThemeAppearanceModes />
</div>
</Row>
<Row className="mt-12">
<Form method="post" action={ROUTES.LOGOUT}>
<Button variant="outline" type="submit">
Log out
Expand All @@ -38,9 +57,9 @@ export const Component = () => {
);
};

function Row(props: { children: ReactNode }) {
function Row(props: { children: ReactNode; className?: string }) {
return (
<div className={`mt-4 grid items-center`} style={{ gridTemplateColumns: '160px 1fr' }}>
<div className={cn(`mt-4 grid items-center`, props.className)} style={{ gridTemplateColumns: '160px 1fr' }}>
{props.children}
</div>
);
Expand Down
21 changes: 3 additions & 18 deletions quadratic-client/src/routes/labs.tsx
Original file line number Diff line number Diff line change
@@ -1,33 +1,18 @@
import { DashboardHeader } from '@/dashboard/components/DashboardHeader';

import { ThemeAccentColors } from '@/shared/components/ThemeAccentColors';
import { ThemeAppearanceModes } from '@/shared/components/ThemeAppearanceModes';
import { CONTACT_URL } from '@/shared/constants/urls';
import { useFeatureFlag, type FeatureFlagKey } from '@/shared/hooks/useFeatureFlag';
import { Label } from '@/shared/shadcn/ui/label';
import { Switch } from '@/shared/shadcn/ui/switch';

type LabProps = {
type LabFeature = {
featureFlagKey: FeatureFlagKey;
label: string;
description: string;
Component: React.ComponentType<any>;
};

const labFeatures = [
{
featureFlagKey: 'themeAccentColor',
label: 'Accent color',
description: 'Choose a custom accent color used throughout the app.',
Component: ThemeAccentColors,
},
{
featureFlagKey: 'themeAppearanceMode',
label: 'Appearance',
description: 'Choose light or dark mode (or use your system’s setting).',
Component: ThemeAppearanceModes,
},
] as const;
export const labFeatures: LabFeature[] = [];

export const Component = () => {
return (
Expand Down Expand Up @@ -59,7 +44,7 @@ export const Component = () => {
);
};

function LabToggle({ featureFlagKey, label, description, Component }: LabProps) {
function LabToggle({ featureFlagKey, label, description, Component }: LabFeature) {
const [featureFlag, setFeatureFlag] = useFeatureFlag(featureFlagKey);

return (
Expand Down
2 changes: 1 addition & 1 deletion quadratic-client/src/shared/hooks/useFeatureFlag.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import useLocalStorage from '@/shared/hooks/useLocalStorage';
import mixpanel from 'mixpanel-browser';

const initialState = { themeAppearanceMode: false, themeAccentColor: false };
const initialState = {};
export type FeatureFlagKey = keyof typeof initialState;

export const useFeatureFlag = (key: FeatureFlagKey) => {
Expand Down
11 changes: 1 addition & 10 deletions quadratic-client/src/shared/hooks/useThemeAccentColor.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import { useFeatureFlag } from '@/shared/hooks/useFeatureFlag';
import useLocalStorage from '@/shared/hooks/useLocalStorage';
import { sharedEvents } from '@/shared/sharedEvents';
import { useEffect } from 'react';
Expand All @@ -13,15 +12,7 @@ export const useThemeAccentColor = () => {
};

export const ThemeAccentColorEffects = () => {
const [accentColor, setAccentColor] = useThemeAccentColor();
const [featureFlag] = useFeatureFlag('themeAccentColor');

// If the user turns the feature off, reset it to the default
useEffect(() => {
if (featureFlag === false) {
setAccentColor(DEFAULT_ACCENT_COLOR);
}
}, [featureFlag, setAccentColor]);
const [accentColor] = useThemeAccentColor();

// Update the theme color in the UI
useEffect(() => {
Expand Down
Loading
Loading