Skip to content

Commit

Permalink
[dashboard] new workspace with options
Browse files Browse the repository at this point in the history
  • Loading branch information
svenefftinge committed Dec 20, 2022
1 parent 9ca833a commit 03ba412
Show file tree
Hide file tree
Showing 14 changed files with 617 additions and 169 deletions.
153 changes: 153 additions & 0 deletions components/dashboard/src/components/DropDown2.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,153 @@
/**
* Copyright (c) 2022 Gitpod GmbH. All rights reserved.
* Licensed under the GNU Affero General Public License (AGPL).
* See License.AGPL.txt in the project root for license information.
*/

import React, { FunctionComponent, useMemo, useState } from "react";
import Arrow from "./Arrow";

export interface DropDown2Element {
id: string;
element: JSX.Element;
isSelectable?: boolean;
}

export interface DropDown2Props {
getElements: (searchString: string) => DropDown2Element[];
searchPlaceholder?: string;
disableSearch?: boolean;
onSelectionChange: (id: string) => void;
}

export const DropDown2: FunctionComponent<DropDown2Props> = (props) => {
const [showDropDown, setShowDropDown] = useState<boolean>(false);
const onSelected = useMemo(
() => (elementId: string) => {
props.onSelectionChange(elementId);
setShowDropDown(false);
},
[props],
);
const [search, setSearch] = useState<string>("");
const filteredOptions = props.getElements(search);
const [selectedElementTemp, setSelectedElementTemp] = useState<string | undefined>(filteredOptions[0]?.id);

const onKeyDown = useMemo(
() => (e: React.KeyboardEvent) => {
if (!showDropDown) {
return;
}
if (e.key === "ArrowDown") {
e.preventDefault();
let idx = filteredOptions.findIndex((e) => e.id === selectedElementTemp);
while (idx++ < filteredOptions.length - 1) {
const candidate = filteredOptions[idx];
if (candidate.isSelectable) {
setSelectedElementTemp(candidate.id);
return;
}
}
return;
}
if (e.key === "ArrowUp") {
e.preventDefault();
let idx = filteredOptions.findIndex((e) => e.id === selectedElementTemp);
while (idx-- > 0) {
const candidate = filteredOptions[idx];
if (candidate.isSelectable) {
setSelectedElementTemp(candidate.id);
return;
}
}
return;
}
if (e.key === "Escape") {
setShowDropDown(false);
e.preventDefault();
}
if (e.key === "Enter" && selectedElementTemp && filteredOptions.some((e) => e.id === selectedElementTemp)) {
e.preventDefault();
props.onSelectionChange(selectedElementTemp);
setShowDropDown(false);
}
},
[filteredOptions, props, selectedElementTemp, showDropDown],
);

const onBlur = useMemo(
() => (e: React.FocusEvent) => {
setShowDropDown(false);
},
[setShowDropDown],
);

const doShowDropDown = useMemo(() => () => setShowDropDown(true), []);
return (
<div onKeyDown={onKeyDown} onBlur={onBlur} className="relative flex flex-col">
<div
className={
"h-16 rounded-lg bg-gray-100 dark:bg-gray-800 flex items-center px-2 " +
(!showDropDown && " hover:bg-gray-200 dark:hover:bg-gray-700 cursor-pointer")
}
onClick={doShowDropDown}
>
{props.children}
<div className="flex-grow" />
<div className="mr-2">
<Arrow direction={showDropDown ? "up" : "down"} />
</div>
</div>
{showDropDown && (
<div className="absolute w-full top-10 bg-gray-100 dark:bg-gray-900 max-h-72 overflow-auto rounded-lg mt-3 z-50 p-2">
{!props.disableSearch ? (
<div className="h-12">
<input
type="text"
autoFocus
className="w-full focus rounded-lg"
placeholder={props.searchPlaceholder}
value={search}
onChange={(e) => setSearch(e.target.value)}
/>
</div>
) : (
<div className="text-gray-500 pt-2 ml-2">{props.searchPlaceholder}</div>
)}
<ul>
{filteredOptions.length > 0 ? (
filteredOptions.map((element) => {
let selectionClasses = `dark:bg-gray-900 cursor-pointer`;
if (element.id === selectedElementTemp) {
selectionClasses = `bg-gray-200 dark:bg-gray-700 cursor-pointer`;
}
if (!element.isSelectable) {
selectionClasses = ``;
}
return (
<li
key={element.id}
className={"h-16 rounded-lg flex items-center px-2 " + selectionClasses}
onMouseDown={() => {
if (element.isSelectable) {
setSelectedElementTemp(element.id);
onSelected(element.id);
}
}}
onMouseOver={() => setSelectedElementTemp(element.id)}
>
{element.element}
</li>
);
})
) : (
<li key="no-elements" className={"rounded-md "}>
<div className="h-12 pl-8 py-3 text-gray-800 dark:text-gray-200">No results</div>
</li>
)}
</ul>
</div>
)}
</div>
);
};
2 changes: 1 addition & 1 deletion components/dashboard/src/components/Modal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@ type ModalBodyProps = {
export const ModalBody = ({ children, hideDivider = false }: ModalBodyProps) => {
return (
<div
className={cn("overflow-y-auto border-gray-200 dark:border-gray-800 -mx-6 px-6 ", {
className={cn("border-gray-200 dark:border-gray-800 -mx-6 px-6 ", {
"border-t border-b mt-2 py-4": !hideDivider,
})}
>
Expand Down
Loading

0 comments on commit 03ba412

Please sign in to comment.