Updated CSS class naming convention
This commit is contained in:
parent
0fdd7ad632
commit
7cee514acb
78 changed files with 384 additions and 462 deletions
|
|
@ -68,9 +68,10 @@ Type | Case | Example
|
|||
Folders | kebab-case | `virtual-drive`
|
||||
`.ts` files | camelCase | `virtualRoot.ts`
|
||||
`.tsx` files | PascalCase | `Desktop.tsx`
|
||||
`.css` files & files in `public` dir | kebab-case | `global.css`
|
||||
`.css` files & static assets | kebab-case | `global.css`
|
||||
Local `.module.css` files | PascalCase | `Desktop.module.css`
|
||||
Global `.module.css` files | kebab-case | `utils.module.css`
|
||||
CSS class names | PascalCase | ```.WindowsView```
|
||||
Variables | camelCase | ```const fooBar = true;```
|
||||
Global constant variables | MACRO_CASE | ```export const NAME = "ProzillaOS";```
|
||||
Classes | PascalCase | ```class WindowsManager { }```
|
||||
|
|
|
|||
|
|
@ -9,13 +9,13 @@
|
|||
<link rel="canonical" href="https://os.prozilla.dev/">
|
||||
|
||||
<!-- Favicon -->
|
||||
<link rel="icon" href="https://os.prozilla.dev/favicon.ico?v=2" sizes="any">
|
||||
<link rel="icon" type="image/x-icon" sizes="any" href="https://os.prozilla.dev/favicon.ico?v=2">
|
||||
<link rel="icon" type="image/png" sizes="48x48" href="/favicon-48.png?v=2">
|
||||
<link rel="icon" type="image/png" sizes="32x32" href="/favicon-32.png?v=2">
|
||||
<link rel="icon" type="image/png" sizes="16x16" href="/favicon-16.png?v=2">
|
||||
<link rel="icon" type="image/png" sizes="192x192" href="/favicon-192.png?v=2">
|
||||
<link rel="shortcut icon" type="image/svg+xml" href="/icon.svg?v=2"/>
|
||||
<link rel="apple-touch-icon" href="/favicon-192.png?v=2">
|
||||
<link rel="apple-touch-icon" sizes="180x180" href="/apple-touch-icon.png?v=2">
|
||||
<link rel="mask-icon" href="/icon.svg?v=2" color="#36b29e"/>
|
||||
<meta name="msapplication-TileColor" content="#0d1114"/>
|
||||
<meta name="theme-color" content="#0d1114"/>
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@
|
|||
"repository": "https://github.com/Prozilla/ProzillaOS",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"start": "vite --port 3000",
|
||||
"start": "vite --port 3000 --host",
|
||||
"build": "tsc && vite build",
|
||||
"serve": "vite preview",
|
||||
"predeploy": "npm run build",
|
||||
|
|
|
|||
BIN
public/apple-touch-icon.png
Normal file
BIN
public/apple-touch-icon.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 17 KiB |
|
|
@ -16,10 +16,10 @@
|
|||
background-color: var(--hover-color);
|
||||
}
|
||||
|
||||
.Button-link {
|
||||
.ButtonLink {
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.Button-link > svg {
|
||||
.ButtonLink > svg {
|
||||
margin-left: 0.5rem;
|
||||
}
|
||||
|
|
@ -17,7 +17,7 @@ export function Button(props: ButtonProps) {
|
|||
className = `${styles.Button} ${className}`;
|
||||
|
||||
if (href != null) {
|
||||
className = `${styles["Button-link"]} ${className}`;
|
||||
className = `${styles.ButtonLink} ${className}`;
|
||||
|
||||
return (<a
|
||||
href={href}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
.Container {
|
||||
.DropdownButton {
|
||||
position: relative;
|
||||
height: 100%;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,13 +3,7 @@ import styles from "./DropdownButton.module.css";
|
|||
import OutsideClickListener from "../../../hooks/_utils/outsideClick";
|
||||
import { formatShortcut } from "../../../features/_utils/string.utils";
|
||||
|
||||
/**
|
||||
* @param {object} props
|
||||
* @param {string} props.label
|
||||
* @param {Object<string, Function>} props.options
|
||||
* @param {Object<string, string[]>} props.shortcuts
|
||||
*/
|
||||
export function DropdownButton({ label, options, shortcuts }) {
|
||||
export function DropdownButton({ label, options, shortcuts }: { label: string; options: { [s: string]: Function; }; shortcuts: { [s: string]: string[]; }; }) {
|
||||
const [open, setOpen] = useState(false);
|
||||
const [tabIndex, setTabIndex] = useState(-1);
|
||||
|
||||
|
|
@ -19,7 +13,7 @@ export function DropdownButton({ label, options, shortcuts }) {
|
|||
|
||||
return (
|
||||
<OutsideClickListener onOutsideClick={() => { setOpen(false); }}>
|
||||
<div className={styles.Container}>
|
||||
<div className={styles.DropdownButton}>
|
||||
<button className={styles.Button} tabIndex={0} onClick={() => { setOpen(!open); }}>
|
||||
{label}
|
||||
</button>
|
||||
|
|
|
|||
|
|
@ -1,10 +1,10 @@
|
|||
.Container {
|
||||
.ProgressBar {
|
||||
position: relative;
|
||||
width: 15rem;
|
||||
max-width: 100%;
|
||||
min-height: 2rem;
|
||||
max-height: 100%;
|
||||
background-color: var(--background-color-3);
|
||||
background-color: var(--background-color-4);
|
||||
}
|
||||
|
||||
.Fill {
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ interface ProgressBarProps {
|
|||
|
||||
export function ProgressBar({ fillPercentage, fillColor, backgroundColor, align = "left", className = "" }: ProgressBarProps) {
|
||||
return (
|
||||
<div className={`${styles.Container} ${className}`} style={{ backgroundColor: backgroundColor }}>
|
||||
<div className={`${styles.ProgressBar} ${className}`} style={{ backgroundColor: backgroundColor }}>
|
||||
<div
|
||||
className={`${styles.Fill} ${align}`}
|
||||
style={{ backgroundColor: fillColor, "--fill": `${clamp(fillPercentage, 0.1, 100)}%` } as CSSProperties}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
.Container {
|
||||
.Actions {
|
||||
/* These variables describe the position of the container relative to top left corner of its parent */
|
||||
--left: 0;
|
||||
--top: 0;
|
||||
|
|
@ -12,25 +12,25 @@
|
|||
transition: opacity 100ms ease-out;
|
||||
}
|
||||
|
||||
.Container.Uninitiated {
|
||||
.Actions.Uninitiated {
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
.Container.Align-left {
|
||||
.Actions.AlignLeft {
|
||||
--left: 1;
|
||||
|
||||
left: unset;
|
||||
right: 0;
|
||||
}
|
||||
|
||||
.Container.Align-top {
|
||||
.Actions.AlignTop {
|
||||
--top: 1;
|
||||
|
||||
top: unset;
|
||||
bottom: 0;
|
||||
}
|
||||
|
||||
.Context-menu.Container {
|
||||
.ContextMenu.Actions {
|
||||
--border-radius: var(--border-radius-1);
|
||||
--padding: 0.375rem;
|
||||
|
||||
|
|
@ -42,8 +42,8 @@
|
|||
background-color: var(--background-color-1) !important;
|
||||
}
|
||||
|
||||
.Context-menu .Button,
|
||||
.Context-menu .Dropdown {
|
||||
.ContextMenu .Button,
|
||||
.ContextMenu .Dropdown {
|
||||
display: flex;
|
||||
gap: 0.75rem;
|
||||
justify-content: space-between;
|
||||
|
|
@ -59,26 +59,26 @@
|
|||
cursor: pointer;
|
||||
}
|
||||
|
||||
.Context-menu .Button:hover,
|
||||
.Context-menu .Button:focus-visible,
|
||||
.Context-menu .Dropdown:hover,
|
||||
.Context-menu .Dropdown:focus-visible {
|
||||
.ContextMenu .Button:hover,
|
||||
.ContextMenu .Button:focus-visible,
|
||||
.ContextMenu .Dropdown:hover,
|
||||
.ContextMenu .Dropdown:focus-visible {
|
||||
background-color: color-mix(in srgb, var(--background-color-0) 75%, transparent);
|
||||
}
|
||||
|
||||
.Context-menu .Label {
|
||||
.ContextMenu .Label {
|
||||
display: flex;
|
||||
gap: 0.5rem;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.Context-menu .Label p,
|
||||
.Context-menu .Shortcut {
|
||||
.ContextMenu .Label p,
|
||||
.ContextMenu .Shortcut {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.Context-menu .Icon {
|
||||
.ContextMenu .Icon {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
|
|
@ -86,40 +86,40 @@
|
|||
height: 0.875rem;
|
||||
}
|
||||
|
||||
.Context-menu .Icon > svg {
|
||||
.ContextMenu .Icon > svg {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: contain;
|
||||
}
|
||||
|
||||
.Context-menu .Image-icon {
|
||||
.ContextMenu .ImageIcon {
|
||||
position: absolute;
|
||||
width: 1rem;
|
||||
height: auto;
|
||||
aspect-ratio: 1;
|
||||
}
|
||||
|
||||
.Context-menu .Image-icon div {
|
||||
.ContextMenu .ImageIcon div {
|
||||
display: flex;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.Context-menu .Image-icon div > svg {
|
||||
.ContextMenu .ImageIcon div > svg {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: contain;
|
||||
}
|
||||
|
||||
.Context-menu .Shortcut {
|
||||
.ContextMenu .Shortcut {
|
||||
color: var(--foreground-color-1);
|
||||
}
|
||||
|
||||
.Context-menu .Dropdown {
|
||||
.ContextMenu .Dropdown {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.Context-menu .Dropdown .Dropdown-content {
|
||||
.ContextMenu .Dropdown .DropdownContent {
|
||||
opacity: 1;
|
||||
position: absolute;
|
||||
top: calc(var(--padding) * -1);
|
||||
|
|
@ -132,12 +132,12 @@
|
|||
cursor: auto;
|
||||
}
|
||||
|
||||
.Context-menu .Dropdown:not(.Active) .Dropdown-content {
|
||||
.ContextMenu .Dropdown:not(.Active) .DropdownContent {
|
||||
opacity: 0;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.Context-menu .Divider {
|
||||
.ContextMenu .Divider {
|
||||
width: calc(100% - 0.5rem);
|
||||
height: 2px;
|
||||
border-radius: var(--border-radius-99);
|
||||
|
|
@ -174,11 +174,11 @@
|
|||
height: 100%;
|
||||
}
|
||||
|
||||
.Header-menu .Dropdown-arrow {
|
||||
.Header-menu .DropdownArrow {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.Header-menu .Dropdown-content {
|
||||
.Header-menu .DropdownContent {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
position: absolute;
|
||||
|
|
@ -190,7 +190,7 @@
|
|||
border-bottom-right-radius: 0.5rem;
|
||||
}
|
||||
|
||||
.Header-menu .Dropdown:not(.Active) .Dropdown-content {
|
||||
.Header-menu .Dropdown:not(.Active) .DropdownContent {
|
||||
opacity: 0;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,12 +2,7 @@ import { Children, cloneElement, isValidElement, ReactElement, ReactNode, Ref }
|
|||
import { useShortcuts } from "../../hooks/_utils/keyboard";
|
||||
import styles from "./Actions.module.css";
|
||||
import { useScreenBounds } from "../../hooks/_utils/screen";
|
||||
|
||||
export const STYLES = {
|
||||
CONTEXT_MENU: styles["Context-menu"],
|
||||
SHORTCUTS_LISTENER: styles["Shortcuts-listener"],
|
||||
HEADER_MENU: styles["Header-menu"]
|
||||
};
|
||||
import { STYLES } from "../../config/actions.config";
|
||||
|
||||
export interface ActionProps {
|
||||
actionId?: string;
|
||||
|
|
@ -84,13 +79,13 @@ export function Actions({ children, className, onAnyTrigger, triggerParams, avoi
|
|||
if (isListener)
|
||||
return iterateOverChildren(children) as ReactElement;
|
||||
|
||||
const classNames = [styles.Container];
|
||||
const classNames = [styles.Actions];
|
||||
if (className != null)
|
||||
classNames.push(className);
|
||||
if (alignLeft)
|
||||
classNames.push(styles["Align-left"]);
|
||||
classNames.push(styles.AlignLeft);
|
||||
if (alignTop)
|
||||
classNames.push(styles["Align-top"]);
|
||||
classNames.push(styles.AlignTop);
|
||||
if (!initiated)
|
||||
classNames.push(styles.Uninitiated);
|
||||
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ export const ClickAction = memo(({ actionId, label, shortcut, onTrigger, icon }:
|
|||
<span className={styles.Label}>
|
||||
{icon && <div className={styles.Icon}>
|
||||
{typeof icon == "string"
|
||||
? <ImagePreview source={icon} className={styles["Image-icon"]}/>
|
||||
? <ImagePreview source={icon} className={styles.ImageIcon}/>
|
||||
: <FontAwesomeIcon icon={icon as unknown as IconProp}/>
|
||||
}
|
||||
</div>}
|
||||
|
|
|
|||
|
|
@ -32,8 +32,8 @@ export function DropdownAction({ label, icon, children, showOnHover = true }: Dr
|
|||
{icon && <div className={styles.Icon}><FontAwesomeIcon icon={icon as IconDefinition}/></div>}
|
||||
<p>{label}</p>
|
||||
</span>
|
||||
<div className={styles["Dropdown-arrow"]}><FontAwesomeIcon icon={faCaretRight}/></div>
|
||||
<div className={styles["Dropdown-content"]}>
|
||||
<div className={styles.DropdownArrow}><FontAwesomeIcon icon={faCaretRight}/></div>
|
||||
<div className={styles.DropdownContent}>
|
||||
{children}
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
.Container {
|
||||
.HeaderMenu {
|
||||
display: flex;
|
||||
width: 100%;
|
||||
height: 1.5rem;
|
||||
|
|
|
|||
|
|
@ -1,9 +1,10 @@
|
|||
import styles from "./HeaderMenu.module.css";
|
||||
import { ActionsProps, Actions, STYLES } from "../../../actions/Actions";
|
||||
import { ActionsProps, Actions } from "../../../actions/Actions";
|
||||
import { STYLES } from "../../../../config/actions.config";
|
||||
|
||||
|
||||
export function HeaderMenu({ children, ...props }: ActionsProps) {
|
||||
return <div className={styles.Container}>
|
||||
return <div className={styles.HeaderMenu}>
|
||||
<Actions className={STYLES.HEADER_MENU} {...props}>
|
||||
{children}
|
||||
</Actions>
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
.Container {
|
||||
.WebView {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
|
|
@ -6,7 +6,7 @@
|
|||
height: 100%;
|
||||
}
|
||||
|
||||
.Web-view {
|
||||
.WebView > iframe {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
border: none;
|
||||
|
|
|
|||
|
|
@ -35,12 +35,11 @@ export const WebView: FC<WebViewProps> = forwardRef<HTMLIFrameElement>(({ source
|
|||
setHovered(false);
|
||||
};
|
||||
|
||||
return <div className={styles.Container} onMouseOver={onMouseOver} onMouseOut={onMouseOut}>
|
||||
return <div className={styles.WebView} onMouseOver={onMouseOver} onMouseOut={onMouseOut}>
|
||||
<iframe
|
||||
ref={ref}
|
||||
src={source}
|
||||
title={props.title ?? "Web view"}
|
||||
className={styles["Web-view"]}
|
||||
referrerPolicy="no-referrer"
|
||||
sandbox="allow-downloads allow-forms allow-modals allow-pointer-lock allow-popups allow-presentation allow-same-origin allow-scripts"
|
||||
{...props}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
.Container {
|
||||
.Browser {
|
||||
--header-height: 3.5rem;
|
||||
--nav-bar-height: 2.25rem;
|
||||
|
||||
|
|
@ -16,7 +16,7 @@
|
|||
background-color: var(--background-color-0);
|
||||
}
|
||||
|
||||
.Nav-bar {
|
||||
.NavBar {
|
||||
display: flex;
|
||||
gap: 1rem;
|
||||
justify-content: flex-start;
|
||||
|
|
@ -26,7 +26,7 @@
|
|||
padding: 1.25rem;
|
||||
}
|
||||
|
||||
.Icon-button {
|
||||
.IconButton {
|
||||
--color: var(--foreground-color-0);
|
||||
|
||||
position: relative;
|
||||
|
|
@ -43,7 +43,7 @@
|
|||
cursor: pointer;
|
||||
}
|
||||
|
||||
.Icon-button::after {
|
||||
.IconButton::after {
|
||||
content: "";
|
||||
position: absolute;
|
||||
top: 0;
|
||||
|
|
@ -57,26 +57,26 @@
|
|||
transition: all 200ms ease-in-out;
|
||||
}
|
||||
|
||||
.Icon-button:hover::after,
|
||||
.Icon-button:focus-visible::after {
|
||||
.IconButton:hover::after,
|
||||
.IconButton:focus-visible::after {
|
||||
background-color: rgba(255, 255, 255, 10%);
|
||||
transform: scale(175%);
|
||||
}
|
||||
|
||||
.Icon-button:disabled {
|
||||
.IconButton:disabled {
|
||||
--color: var(--foreground-color-2);
|
||||
}
|
||||
|
||||
.Icon-button svg {
|
||||
.IconButton svg {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.Icon-button svg path {
|
||||
.IconButton svg path {
|
||||
fill: var(--color);
|
||||
transition: fill 100ms ease-in-out;
|
||||
}
|
||||
|
||||
.Search-bar {
|
||||
.SearchBar {
|
||||
flex: 1;
|
||||
padding: 0.25rem 0.5rem;
|
||||
background-color: var(--background-color-2);
|
||||
|
|
|
|||
|
|
@ -60,13 +60,13 @@ export function Browser({ startUrl, focus }: BrowserProps) {
|
|||
}
|
||||
};
|
||||
|
||||
return (<div className={styles.Container}>
|
||||
return (<div className={styles.Browser}>
|
||||
<div className={styles.Header}>
|
||||
<div className={styles["Nav-bar"]}>
|
||||
<div className={styles.NavBar}>
|
||||
<button
|
||||
title="Back"
|
||||
tabIndex={0}
|
||||
className={styles["Icon-button"]}
|
||||
className={styles.IconButton}
|
||||
onClick={() => { undo(); }}
|
||||
disabled={!undoAvailable}
|
||||
>
|
||||
|
|
@ -75,7 +75,7 @@ export function Browser({ startUrl, focus }: BrowserProps) {
|
|||
<button
|
||||
title="Forward"
|
||||
tabIndex={0}
|
||||
className={styles["Icon-button"]}
|
||||
className={styles.IconButton}
|
||||
onClick={() => { redo(); }}
|
||||
disabled={!redoAvailable}
|
||||
>
|
||||
|
|
@ -84,7 +84,7 @@ export function Browser({ startUrl, focus }: BrowserProps) {
|
|||
<button
|
||||
title="Reload"
|
||||
tabIndex={0}
|
||||
className={styles["Icon-button"]}
|
||||
className={styles.IconButton}
|
||||
onClick={reload}
|
||||
>
|
||||
<FontAwesomeIcon icon={faRotateRight}/>
|
||||
|
|
@ -92,7 +92,7 @@ export function Browser({ startUrl, focus }: BrowserProps) {
|
|||
<button
|
||||
title="Home"
|
||||
tabIndex={0}
|
||||
className={styles["Icon-button"]}
|
||||
className={styles.IconButton}
|
||||
onClick={() => { updateUrl(HOME_URL); }}
|
||||
>
|
||||
<FontAwesomeIcon icon={faHome}/>
|
||||
|
|
@ -101,13 +101,13 @@ export function Browser({ startUrl, focus }: BrowserProps) {
|
|||
value={input}
|
||||
type="text"
|
||||
aria-label="Search bar"
|
||||
className={styles["Search-bar"]}
|
||||
className={styles.SearchBar}
|
||||
tabIndex={0}
|
||||
onChange={onInputChange as unknown as ChangeEventHandler}
|
||||
onKeyDown={onKeyDown as unknown as KeyboardEventHandler}
|
||||
/>
|
||||
</div>
|
||||
<div className={styles["Bookmarks"]}>
|
||||
<div className={styles.Bookmarks}>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
.Container {
|
||||
.Calculator {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
height: 100%;
|
||||
|
|
@ -39,7 +39,7 @@
|
|||
padding: 0.5rem;
|
||||
}
|
||||
|
||||
.Input-row {
|
||||
.InputRow {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
gap: var(--button-gap);
|
||||
|
|
@ -51,17 +51,17 @@
|
|||
font-size: 1.5rem;
|
||||
}
|
||||
|
||||
.Input-row:first-of-type .Button {
|
||||
.InputRow:first-of-type .Button {
|
||||
--normal-color: var(--background-color-1);
|
||||
--hover-color: var(--background-color-2);
|
||||
}
|
||||
|
||||
.Input-row .Button:last-of-type {
|
||||
.InputRow .Button:last-of-type {
|
||||
--text-color: var(--background-color-0);
|
||||
--normal-color: var(--blue-0);
|
||||
--hover-color: var(--blue-b);
|
||||
--hover-color: var(--blue-1);
|
||||
}
|
||||
|
||||
.Button-large {
|
||||
.ButtonLarge {
|
||||
min-width: calc(50% - var(--button-gap) / 2);
|
||||
}
|
||||
|
|
@ -152,38 +152,38 @@ export function Calculator({ active }: WindowProps) {
|
|||
if (operation != null)
|
||||
calculation = `${firstNumber} ${operation} ${secondNumber != null ? secondNumber + " =" : ""}`;
|
||||
|
||||
return (<div className={styles.Container}>
|
||||
return (<div className={styles.Calculator}>
|
||||
<div className={styles.Output}>
|
||||
<p className={styles.Calculation}>{calculation}</p>
|
||||
<p className={styles.Preview}>{input ?? firstNumber}</p>
|
||||
</div>
|
||||
<div className={styles.Input}>
|
||||
<div className={styles["Input-row"]}>
|
||||
<div className={styles.InputRow}>
|
||||
<Button className={styles.Button} onClick={reset}>C</Button>
|
||||
<Button className={styles.Button} onClick={() => { addInput("-"); }}>+/-</Button>
|
||||
<Button className={styles.Button} onClick={() => { addInput("%"); }}>%</Button>
|
||||
<Button className={styles.Button} onClick={() => { changeOperation("÷"); }}>÷</Button>
|
||||
</div>
|
||||
<div className={styles["Input-row"]}>
|
||||
<div className={styles.InputRow}>
|
||||
<Button className={styles.Button} onClick={() => { addInput("7"); }}>7</Button>
|
||||
<Button className={styles.Button} onClick={() => { addInput("8"); }}>8</Button>
|
||||
<Button className={styles.Button} onClick={() => { addInput("9"); }}>9</Button>
|
||||
<Button className={styles.Button} onClick={() => { changeOperation("×"); }}>×</Button>
|
||||
</div>
|
||||
<div className={styles["Input-row"]}>
|
||||
<div className={styles.InputRow}>
|
||||
<Button className={styles.Button} onClick={() => { addInput("4"); }}>4</Button>
|
||||
<Button className={styles.Button} onClick={() => { addInput("5"); }}>5</Button>
|
||||
<Button className={styles.Button} onClick={() => { addInput("6"); }}>6</Button>
|
||||
<Button className={styles.Button} onClick={() => { changeOperation("-"); }}>-</Button>
|
||||
</div>
|
||||
<div className={styles["Input-row"]}>
|
||||
<div className={styles.InputRow}>
|
||||
<Button className={styles.Button} onClick={() => { addInput("1"); }}>1</Button>
|
||||
<Button className={styles.Button} onClick={() => { addInput("2"); }}>2</Button>
|
||||
<Button className={styles.Button} onClick={() => { addInput("3"); }}>3</Button>
|
||||
<Button className={styles.Button} onClick={() => { changeOperation("+"); }}>+</Button>
|
||||
</div>
|
||||
<div className={styles["Input-row"]}>
|
||||
<Button className={`${styles.Button} ${styles["Button-large"]}`} onClick={() => { addInput("0"); }}>0</Button>
|
||||
<div className={styles.InputRow}>
|
||||
<Button className={`${styles.Button} ${styles.ButtonLarge}`} onClick={() => { addInput("0"); }}>0</Button>
|
||||
<Button className={styles.Button} onClick={() => { addInput("."); }}>.</Button>
|
||||
<Button className={styles.Button} onClick={() => { calculate(); }}>=</Button>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
.Container {
|
||||
.FileExplorer {
|
||||
--header-height: 3.5rem;
|
||||
--sidebar-width: 10rem;
|
||||
--footer-height: 1.75rem;
|
||||
|
|
@ -20,7 +20,7 @@
|
|||
background-color: var(--background-color-0);
|
||||
}
|
||||
|
||||
.Icon-button {
|
||||
.IconButton {
|
||||
--color: var(--foreground-color-0);
|
||||
|
||||
position: relative;
|
||||
|
|
@ -34,7 +34,7 @@
|
|||
cursor: pointer;
|
||||
}
|
||||
|
||||
.Icon-button::after {
|
||||
.IconButton::after {
|
||||
content: "";
|
||||
position: absolute;
|
||||
top: 0;
|
||||
|
|
@ -48,25 +48,25 @@
|
|||
transition: all 200ms ease-in-out;
|
||||
}
|
||||
|
||||
.Icon-button:hover::after, .Icon-button:focus-visible::after {
|
||||
.IconButton:hover::after, .IconButton:focus-visible::after {
|
||||
background-color: rgba(255, 255, 255, 10%);
|
||||
transform: scale(150%);
|
||||
}
|
||||
|
||||
.Icon-button:disabled {
|
||||
--color: var(--foreground-color-2);
|
||||
.IconButton:disabled {
|
||||
opacity: 0.75;
|
||||
}
|
||||
|
||||
.Icon-button svg {
|
||||
.IconButton svg {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.Icon-button svg path {
|
||||
.IconButton svg path {
|
||||
fill: var(--color);
|
||||
transition: fill 100ms ease-in-out;
|
||||
}
|
||||
|
||||
.Path-input {
|
||||
.PathInput {
|
||||
flex: 1;
|
||||
padding: 0.25rem 0.5rem;
|
||||
background-color: var(--background-color-2);
|
||||
|
|
@ -99,7 +99,7 @@
|
|||
overflow: hidden;
|
||||
}
|
||||
|
||||
.Nav-button {
|
||||
.NavButton {
|
||||
display: flex;
|
||||
gap: 0.5rem;
|
||||
align-items: center;
|
||||
|
|
@ -113,11 +113,11 @@
|
|||
transition: background-color 100ms ease-in-out;
|
||||
}
|
||||
|
||||
.Nav-button:hover, .Nav-button:focus-visible {
|
||||
.NavButton:hover, .NavButton:focus-visible {
|
||||
background-color: color-mix(in srgb, var(--background-color-0) 75%, transparent);
|
||||
}
|
||||
|
||||
.Nav-button svg {
|
||||
.NavButton svg {
|
||||
height: 1.35rem;
|
||||
aspect-ratio: 1;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -176,12 +176,12 @@ export function FileExplorer({ startPath, selectorMode, Footer, onSelectionChang
|
|||
const itemCount = currentDirectory.getItemCount(showHidden);
|
||||
|
||||
return (
|
||||
<div className={!isSelector ? styles.Container : `${styles.Container} ${styles.Selector}`}>
|
||||
<div className={!isSelector ? styles.FileExplorer : `${styles.FileExplorer} ${styles.Selector}`}>
|
||||
<div className={styles.Header}>
|
||||
<button
|
||||
title="Back"
|
||||
tabIndex={0}
|
||||
className={styles["Icon-button"]}
|
||||
className={styles.IconButton}
|
||||
onClick={() => { undo(); }}
|
||||
disabled={!undoAvailable}
|
||||
>
|
||||
|
|
@ -190,7 +190,7 @@ export function FileExplorer({ startPath, selectorMode, Footer, onSelectionChang
|
|||
<button
|
||||
title="Forward"
|
||||
tabIndex={0}
|
||||
className={styles["Icon-button"]}
|
||||
className={styles.IconButton}
|
||||
onClick={() => { redo(); }}
|
||||
disabled={!redoAvailable}
|
||||
>
|
||||
|
|
@ -199,7 +199,7 @@ export function FileExplorer({ startPath, selectorMode, Footer, onSelectionChang
|
|||
<button
|
||||
title="Up"
|
||||
tabIndex={0}
|
||||
className={styles["Icon-button"]}
|
||||
className={styles.IconButton}
|
||||
onClick={() => { changeDirectory(".."); }}
|
||||
disabled={currentDirectory.isRoot}
|
||||
>
|
||||
|
|
@ -208,7 +208,7 @@ export function FileExplorer({ startPath, selectorMode, Footer, onSelectionChang
|
|||
<button
|
||||
title="New"
|
||||
tabIndex={0}
|
||||
className={styles["Icon-button"]}
|
||||
className={styles.IconButton}
|
||||
onClick={() => {
|
||||
// openWindowedModal({
|
||||
// title: "Error",
|
||||
|
|
@ -235,17 +235,17 @@ export function FileExplorer({ startPath, selectorMode, Footer, onSelectionChang
|
|||
value={path}
|
||||
type="text"
|
||||
aria-label="Path"
|
||||
className={styles["Path-input"]}
|
||||
className={styles.PathInput}
|
||||
tabIndex={0}
|
||||
onChange={onPathChange as unknown as ChangeEventHandler}
|
||||
onKeyDown={onKeyDown as unknown as KeyboardEventHandler}
|
||||
placeholder="Enter a path..."
|
||||
/>
|
||||
<ImportButton directory={currentDirectory}/>
|
||||
<button title="Search" tabIndex={0} className={styles["Icon-button"]}>
|
||||
<button title="Search" tabIndex={0} className={styles.IconButton}>
|
||||
<FontAwesomeIcon icon={faSearch}/>
|
||||
</button>
|
||||
<button title="Settings" tabIndex={0} className={styles["Icon-button"]}>
|
||||
<button title="Settings" tabIndex={0} className={styles.IconButton}>
|
||||
<FontAwesomeIcon icon={faCog}/>
|
||||
</button>
|
||||
</div>
|
||||
|
|
@ -281,14 +281,14 @@ export function FileExplorer({ startPath, selectorMode, Footer, onSelectionChang
|
|||
</div>
|
||||
{!isSelector
|
||||
? <span className={styles.Footer}>
|
||||
<p className={utilStyles["Text-light"]}>
|
||||
<p className={utilStyles.TextLight}>
|
||||
{itemCount === 1
|
||||
? itemCount + " item"
|
||||
: itemCount + " items"
|
||||
}
|
||||
</p>
|
||||
</span>
|
||||
: <div className={`${styles.Footer} ${styles["Selector-footer"]}`}>
|
||||
: <div className={styles.Footer}>
|
||||
<Footer/>
|
||||
</div>
|
||||
}
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@ export default function ImportButton({ directory }: ImportButtonProps): ReactEle
|
|||
});
|
||||
};
|
||||
|
||||
return <label title="Import" tabIndex={0} className={styles["Icon-button"]}>
|
||||
return <label title="Import" tabIndex={0} className={styles.IconButton}>
|
||||
<input
|
||||
type="file"
|
||||
id="import"
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ export function QuickAccessButton({ onClick, icon, name }) {
|
|||
return (
|
||||
<button
|
||||
tabIndex={0}
|
||||
className={`${styles["Nav-button"]} ${utilStyles["Text-semibold"]}`}
|
||||
className={`${styles.NavButton} ${utilStyles.TextSemibold}`}
|
||||
onClick={onClick}
|
||||
>
|
||||
<FontAwesomeIcon icon={icon}/>
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
.Container {
|
||||
.DirectoryList {
|
||||
--scale: 1rem;
|
||||
|
||||
position: relative;
|
||||
|
|
@ -6,7 +6,7 @@
|
|||
height: 100%;
|
||||
}
|
||||
|
||||
.File-button, .Folder-button {
|
||||
.FileButton, .FolderButton {
|
||||
--gap: 0.25rem;
|
||||
|
||||
display: flex;
|
||||
|
|
@ -25,43 +25,43 @@
|
|||
transition: background-color 100ms ease-in-out;
|
||||
}
|
||||
|
||||
.File-button[data-selected=true],
|
||||
.Folder-button[data-selected=true] {
|
||||
.FileButton[data-selected=true],
|
||||
.FolderButton[data-selected=true] {
|
||||
background-color: color-mix(in srgb, var(--background-color-0) 40%, transparent) !important;
|
||||
}
|
||||
|
||||
.File-button:hover,
|
||||
.Folder-button:hover,
|
||||
.File-button:focus-visible,
|
||||
.Folder-button:focus-visible {
|
||||
.FileButton:hover,
|
||||
.FolderButton:hover,
|
||||
.FileButton:focus-visible,
|
||||
.FolderButton:focus-visible {
|
||||
background-color: color-mix(in srgb, var(--background-color-0) 20%, transparent);
|
||||
}
|
||||
|
||||
.File-button p, .Folder-button p {
|
||||
.FileButton p, .FolderButton p {
|
||||
max-width: 100%;
|
||||
margin: 0;
|
||||
word-wrap: break-word;
|
||||
}
|
||||
|
||||
.File-icon, .Folder-icon {
|
||||
.FileIcon, .FolderIcon {
|
||||
max-height: calc(100% - 1rem - var(--gap));
|
||||
border-radius: inherit;
|
||||
}
|
||||
|
||||
.File-icon div, .Folder-icon div {
|
||||
.FileIcon div, .FolderIcon div {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
border-radius: inherit;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.File-icon svg, .Folder-icon svg {
|
||||
.FileIcon svg, .FolderIcon svg {
|
||||
width: 50%;
|
||||
height: auto;
|
||||
aspect-ratio: 1;
|
||||
}
|
||||
|
||||
.Selection-rect {
|
||||
.SelectionRect {
|
||||
opacity: 25%;
|
||||
position: absolute;
|
||||
border-radius: var(--border-radius-0);
|
||||
|
|
|
|||
|
|
@ -129,9 +129,9 @@ export function DirectoryList({ directory, showHidden = false, folderClassName,
|
|||
return { top: y, left: x, width, height };
|
||||
};
|
||||
|
||||
const classNames = [styles.Container];
|
||||
const folderClassNames = [styles["Folder-button"]];
|
||||
const fileClassNames = [styles["File-button"]];
|
||||
const classNames = [styles.DirectoryList];
|
||||
const folderClassNames = [styles.FolderButton];
|
||||
const fileClassNames = [styles.FileButton];
|
||||
|
||||
if (className)
|
||||
classNames.push(className);
|
||||
|
|
@ -148,7 +148,7 @@ export function DirectoryList({ directory, showHidden = false, folderClassName,
|
|||
{...props}
|
||||
>
|
||||
{rectSelectStart != null && rectSelectEnd != null
|
||||
? <div className={styles["Selection-rect"]} style={getRectSelectStyle()}/>
|
||||
? <div className={styles.SelectionRect} style={getRectSelectStyle()}/>
|
||||
: null
|
||||
}
|
||||
{directory?.getSubFolders(showHidden)?.map((folder) =>
|
||||
|
|
@ -167,7 +167,7 @@ export function DirectoryList({ directory, showHidden = false, folderClassName,
|
|||
onOpenFolder?.(event, folder);
|
||||
}}
|
||||
>
|
||||
<div className={styles["Folder-icon"]}>
|
||||
<div className={styles.FolderIcon}>
|
||||
<ImagePreview source={folder.getIconUrl()} onError={() => { folder.setIconUrl(null); }}/>
|
||||
</div>
|
||||
<p>{folder.name}</p>
|
||||
|
|
@ -189,7 +189,7 @@ export function DirectoryList({ directory, showHidden = false, folderClassName,
|
|||
onOpenFile?.(event, file);
|
||||
}}
|
||||
>
|
||||
<div className={styles["File-icon"]}>
|
||||
<div className={styles.FileIcon}>
|
||||
<ImagePreview source={file.getIconUrl()} onError={() => { file.setIconUrl(null); }}/>
|
||||
</div>
|
||||
<p>{file.id}</p>
|
||||
|
|
|
|||
|
|
@ -1,16 +1,16 @@
|
|||
.Image-preview {
|
||||
.ImagePreview {
|
||||
height: 100%;
|
||||
overflow: hidden;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.Image-preview > * {
|
||||
.ImagePreview > * {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: contain;
|
||||
}
|
||||
|
||||
.Image-preview > img {
|
||||
.ImagePreview > img {
|
||||
height: auto;
|
||||
max-height: 100%;
|
||||
width: auto;
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ export function ImagePreview({ source, className, onError, ...props }: ImagePrev
|
|||
onError?.();
|
||||
};
|
||||
|
||||
const classNames = [styles["Image-preview"]];
|
||||
const classNames = [styles.ImagePreview];
|
||||
if (className != null)
|
||||
classNames.push(className);
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
.Container {
|
||||
.CircuitView {
|
||||
display: flex;
|
||||
width: 100%;
|
||||
flex-grow: 1;
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@ export function CircuitView() {
|
|||
<ClickAction label="NOT gate" onTrigger={() => { circuit.addChip(ChipsManager.CHIPS.NOT); }}/>
|
||||
</DropdownAction>
|
||||
</HeaderMenu>
|
||||
<div className={styles.Container}>
|
||||
<div className={styles.CircuitView}>
|
||||
<canvas ref={canvasRef} className={styles.Canvas}/>
|
||||
</div>
|
||||
</>;
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
.Container {
|
||||
.LogicSim {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
width: 100%;
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ import { CircuitView } from "./CircuitView";
|
|||
import styles from "./LogicSim.module.css";
|
||||
|
||||
export function LogicSim() {
|
||||
return <div className={styles.Container}>
|
||||
return <div className={styles.LogicSim}>
|
||||
<CircuitView/>
|
||||
</div>;
|
||||
}
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
.Container {
|
||||
.MediaViewer {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
|
|
@ -7,7 +7,7 @@
|
|||
padding: 2rem;
|
||||
}
|
||||
|
||||
.Container img {
|
||||
.MediaViewer img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: contain;
|
||||
|
|
|
|||
|
|
@ -34,7 +34,7 @@ export function MediaViewer({ file, close, setTitle }: MediaViewerProps) {
|
|||
return (<p>File failed to load.</p>);
|
||||
|
||||
return (
|
||||
<div className={styles.Container}>
|
||||
<div className={styles.MediaViewer}>
|
||||
<img src={file.source} alt={file.id} draggable="false"/>
|
||||
</div>
|
||||
);
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
.Container {
|
||||
.Settings {
|
||||
--tabs-width: 10rem;
|
||||
|
||||
flex: 1;
|
||||
|
|
@ -23,7 +23,7 @@
|
|||
overflow: hidden;
|
||||
}
|
||||
|
||||
.Tab-button {
|
||||
.TabButton {
|
||||
display: flex;
|
||||
gap: 0.5rem;
|
||||
align-items: center;
|
||||
|
|
@ -34,25 +34,25 @@
|
|||
font-size: 0.875rem;
|
||||
}
|
||||
|
||||
.Tab-button.Active-tab {
|
||||
.TabButton.ActiveTab {
|
||||
background-color: var(--background-color-0);
|
||||
}
|
||||
|
||||
.Tab-button:not(.Active-tab):hover,
|
||||
.Tab-button:not(.Active-tab):focus-visible {
|
||||
.TabButton:not(.ActiveTab):hover,
|
||||
.TabButton:not(.ActiveTab):focus-visible {
|
||||
background-color: color-mix(in srgb, var(--background-color-0) 50%, transparent);
|
||||
}
|
||||
|
||||
.Tab-button > svg {
|
||||
.TabButton > svg {
|
||||
height: 1.35rem;
|
||||
aspect-ratio: 1;
|
||||
}
|
||||
|
||||
.Tab-button > p {
|
||||
.TabButton > p {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.Tab-panel {
|
||||
.TabPanel {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
|
@ -63,7 +63,7 @@
|
|||
overflow: auto;
|
||||
}
|
||||
|
||||
.Tab-panel:not(.Active-panel) {
|
||||
.TabPanel:not(.ActivePanel) {
|
||||
display: none;
|
||||
}
|
||||
|
||||
|
|
@ -77,15 +77,15 @@
|
|||
padding-bottom: 1rem;
|
||||
}
|
||||
|
||||
.Option-list {
|
||||
.OptionList {
|
||||
gap: 0.5rem;
|
||||
}
|
||||
|
||||
.Option-list .Option {
|
||||
.OptionList .Option {
|
||||
padding-bottom: 0;
|
||||
}
|
||||
|
||||
.Option-horizontal {
|
||||
.OptionHorizontal {
|
||||
flex-direction: row;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
|
@ -105,28 +105,28 @@
|
|||
display: flex;
|
||||
}
|
||||
|
||||
.Image-select {
|
||||
.ImageSelect {
|
||||
min-width: 10rem;
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
.Image-select > input {
|
||||
.ImageSelect > input {
|
||||
position: absolute;
|
||||
opacity: 0;
|
||||
width: 0;
|
||||
height: 0;
|
||||
}
|
||||
|
||||
.Image-select > input:hover + img,
|
||||
.Image-select > input:focus-visible + img {
|
||||
.ImageSelect > input:hover + img,
|
||||
.ImageSelect > input:focus-visible + img {
|
||||
filter: brightness(110%);
|
||||
}
|
||||
|
||||
.Image-select > input:checked + img {
|
||||
.ImageSelect > input:checked + img {
|
||||
outline: 0.25em solid var(--foreground-color-0);
|
||||
}
|
||||
|
||||
.Image-select > img {
|
||||
.ImageSelect > img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
border-radius: var(--border-radius-1);
|
||||
|
|
@ -134,14 +134,14 @@
|
|||
cursor: pointer;
|
||||
}
|
||||
|
||||
.Button-group {
|
||||
.ButtonGroup {
|
||||
display: flex;
|
||||
gap: 1rem;
|
||||
flex-wrap: wrap;
|
||||
margin: 0.75rem 0;
|
||||
}
|
||||
|
||||
.Button-group .Button {
|
||||
.ButtonGroup .Button {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
|
|
@ -154,13 +154,13 @@
|
|||
border-radius: var(--border-radius-1);
|
||||
}
|
||||
|
||||
.Button-red {
|
||||
.ButtonDanger {
|
||||
--text-color: var(--black-1) !important;
|
||||
--normal-color: var(--red-0) !important;
|
||||
--hover-color: var(--red-1) !important;
|
||||
}
|
||||
|
||||
.Icon-button {
|
||||
.IconButton {
|
||||
--color: var(--foreground-color-0);
|
||||
|
||||
position: relative;
|
||||
|
|
@ -174,7 +174,7 @@
|
|||
cursor: pointer;
|
||||
}
|
||||
|
||||
.Icon-button::after {
|
||||
.IconButton::after {
|
||||
content: "";
|
||||
position: absolute;
|
||||
top: 0;
|
||||
|
|
@ -188,34 +188,34 @@
|
|||
transition: all 200ms ease-in-out;
|
||||
}
|
||||
|
||||
.Icon-button:hover::after, .Icon-button:focus-visible::after {
|
||||
.IconButton:hover::after, .IconButton:focus-visible::after {
|
||||
background-color: rgba(255, 255, 255, 10%);
|
||||
transform: scale(150%);
|
||||
}
|
||||
|
||||
.Icon-button:disabled {
|
||||
.IconButton:disabled {
|
||||
--color: var(--foreground-color-2);
|
||||
}
|
||||
|
||||
.Icon-button svg {
|
||||
.IconButton svg {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.Icon-button svg path {
|
||||
.IconButton svg path {
|
||||
fill: var(--color);
|
||||
transition: fill 100ms ease-in-out;
|
||||
}
|
||||
|
||||
.Progress-bar-container {
|
||||
.ProgressBarContainer {
|
||||
width: 100%;
|
||||
max-width: 35rem;
|
||||
}
|
||||
|
||||
.Progress-bar {
|
||||
.ProgressBar {
|
||||
width: 100% !important;
|
||||
}
|
||||
|
||||
.Progress-bar-labels {
|
||||
.ProgressBarLabels {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
width: 100%;
|
||||
|
|
|
|||
|
|
@ -17,38 +17,38 @@ export function Settings({ tab }: SettingsProps) {
|
|||
return (
|
||||
<Tabs
|
||||
defaultIndex={tab ?? 0}
|
||||
className={styles.Container}
|
||||
selectedTabClassName={styles["Active-tab"]}
|
||||
selectedTabPanelClassName={styles["Active-panel"]}
|
||||
className={styles.Settings}
|
||||
selectedTabClassName={styles.ActiveTab}
|
||||
selectedTabPanelClassName={styles.ActivePanel}
|
||||
>
|
||||
<TabList className={styles.Tabs}>
|
||||
<Tab className={styles["Tab-button"]} tabIndex="0">
|
||||
<Tab className={styles.TabButton} tabIndex="0">
|
||||
<FontAwesomeIcon icon={faShapes}/>
|
||||
<p className={utilStyles["Text-semibold"]}>Apps</p>
|
||||
<p className={utilStyles.TextSemibold}>Apps</p>
|
||||
</Tab>
|
||||
<Tab className={styles["Tab-button"]} tabIndex="0">
|
||||
<Tab className={styles.TabButton} tabIndex="0">
|
||||
<FontAwesomeIcon icon={faPalette}/>
|
||||
<p className={utilStyles["Text-semibold"]}>Appearance</p>
|
||||
<p className={utilStyles.TextSemibold}>Appearance</p>
|
||||
</Tab>
|
||||
<Tab className={styles["Tab-button"]} tabIndex="0">
|
||||
<Tab className={styles.TabButton} tabIndex="0">
|
||||
<FontAwesomeIcon icon={faHardDrive}/>
|
||||
<p className={utilStyles["Text-semibold"]}>Storage</p>
|
||||
<p className={utilStyles.TextSemibold}>Storage</p>
|
||||
</Tab>
|
||||
<Tab className={styles["Tab-button"]} tabIndex="0">
|
||||
<Tab className={styles.TabButton} tabIndex="0">
|
||||
<FontAwesomeIcon icon={faCircleInfo}/>
|
||||
<p className={utilStyles["Text-semibold"]}>About</p>
|
||||
<p className={utilStyles.TextSemibold}>About</p>
|
||||
</Tab>
|
||||
</TabList>
|
||||
<TabPanel className={styles["Tab-panel"]}>
|
||||
<TabPanel className={styles.TabPanel}>
|
||||
<AppsSettings/>
|
||||
</TabPanel>
|
||||
<TabPanel className={styles["Tab-panel"]}>
|
||||
<TabPanel className={styles.TabPanel}>
|
||||
<AppearanceSettings/>
|
||||
</TabPanel>
|
||||
<TabPanel className={styles["Tab-panel"]}>
|
||||
<TabPanel className={styles.TabPanel}>
|
||||
<StorageTab/>
|
||||
</TabPanel>
|
||||
<TabPanel className={styles["Tab-panel"]}>
|
||||
<TabPanel className={styles.TabPanel}>
|
||||
<AboutSettings/>
|
||||
</TabPanel>
|
||||
</Tabs>
|
||||
|
|
|
|||
|
|
@ -11,12 +11,12 @@ export function AboutSettings() {
|
|||
const virtualRoot = useVirtualRoot();
|
||||
|
||||
return (<>
|
||||
<div className={styles["Option"]}>
|
||||
<p className={styles["Label"]}>About {NAME}</p>
|
||||
<p className={utilStyles["Text-light"]}>{NAME} is a web-based operating system inspired by Ubuntu Linux and Windows made with React.js by Prozilla.</p>
|
||||
<div className={styles["Button-group"]}>
|
||||
<div className={styles.Option}>
|
||||
<p className={styles.Label}>About {NAME}</p>
|
||||
<p className={utilStyles.TextLight}>{NAME} is a web-based operating system inspired by Ubuntu Linux and Windows made with React.js by Prozilla.</p>
|
||||
<div className={styles.ButtonGroup}>
|
||||
<Button
|
||||
className={`${styles.Button} ${utilStyles["Text-bold"]}`}
|
||||
className={`${styles.Button} ${utilStyles.TextBold}`}
|
||||
onClick={(event: Event) => {
|
||||
event.preventDefault();
|
||||
windowsManager.open("text-editor", {
|
||||
|
|
@ -29,7 +29,7 @@ export function AboutSettings() {
|
|||
Open info.md
|
||||
</Button>
|
||||
<Button
|
||||
className={`${styles.Button} ${utilStyles["Text-bold"]}`}
|
||||
className={`${styles.Button} ${utilStyles.TextBold}`}
|
||||
href="https://github.com/Prozilla/ProzillaOS"
|
||||
>
|
||||
View source
|
||||
|
|
|
|||
|
|
@ -41,28 +41,28 @@ export function AppOption({ app, pins, setPins: _setPins }: AppOptionProps) {
|
|||
</Actions>
|
||||
});
|
||||
|
||||
return <div className={`${styles["Option"]} ${styles["Option-horizontal"]}`}>
|
||||
<span className={styles["Label"]}>
|
||||
<ImagePreview className={styles["Icon"]} source={AppsManager.getAppIconUrl(app.id)}/>
|
||||
return <div className={`${styles.Option} ${styles.OptionHorizontal}`}>
|
||||
<span className={styles.Label}>
|
||||
<ImagePreview className={styles.Icon} source={AppsManager.getAppIconUrl(app.id)}/>
|
||||
{app.name}
|
||||
</span>
|
||||
<button className={styles["Icon-button"]} onClick={onContextMenu}>
|
||||
<button className={styles.IconButton} onClick={onContextMenu}>
|
||||
<FontAwesomeIcon icon={faEllipsisVertical}/>
|
||||
</button>
|
||||
{/* <div className={styles["Button-group"]}>
|
||||
<Button
|
||||
className={`${styles.Button} ${utilStyles["Text-bold"]}`}
|
||||
className={`${styles.Button} ${utilStyles.TextBold}`}
|
||||
onClick={() => windowsManager.open(id)}
|
||||
>
|
||||
Launch
|
||||
</Button>
|
||||
<Button
|
||||
className={`${styles.Button} ${styles["Button-red"]} ${utilStyles["Text-bold"]}`}
|
||||
className={`${styles.Button} ${styles["Button-red"]} ${utilStyles.TextBold}`}
|
||||
>
|
||||
Uninstall
|
||||
</Button>
|
||||
<Button
|
||||
className={`${styles.Button} ${utilStyles["Text-bold"]}`}
|
||||
className={`${styles.Button} ${utilStyles.TextBold}`}
|
||||
onClick={() => {
|
||||
const newPins = [...pins];
|
||||
if (isPinned) {
|
||||
|
|
|
|||
|
|
@ -40,20 +40,20 @@ export function AppearanceSettings() {
|
|||
};
|
||||
|
||||
return (<>
|
||||
<div className={styles["Option"]}>
|
||||
<p className={styles["Label"]}>Theme</p>
|
||||
<div className={styles["Input"]}>
|
||||
<select className={styles["Dropdown"]} aria-label="theme" value={theme} onChange={onThemeChange as unknown as ChangeEventHandler}>
|
||||
<div className={styles.Option}>
|
||||
<p className={styles.Label}>Theme</p>
|
||||
<div className={styles.Input}>
|
||||
<select className={styles.Dropdown} aria-label="theme" value={theme} onChange={onThemeChange as unknown as ChangeEventHandler}>
|
||||
{Object.entries(THEMES).map(([key, value]) =>
|
||||
<option key={key} value={key}>{value}</option>
|
||||
)}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div className={styles["Option"]}>
|
||||
<p className={styles["Label"]}>Wallpaper</p>
|
||||
<div className={styles.Option}>
|
||||
<p className={styles.Label}>Wallpaper</p>
|
||||
<Button
|
||||
className={`${styles.Button} ${utilStyles["Text-bold"]}`}
|
||||
className={`${styles.Button} ${utilStyles.TextBold}`}
|
||||
onClick={() => {
|
||||
openWindowedModal({
|
||||
size: DEFAULT_FILE_SELECTOR_SIZE,
|
||||
|
|
@ -70,9 +70,9 @@ export function AppearanceSettings() {
|
|||
>
|
||||
Browse
|
||||
</Button>
|
||||
<div className={styles["Input"]}>
|
||||
<div className={styles.Input}>
|
||||
{(virtualRoot.navigate(WALLPAPERS_PATH) as VirtualFolder)?.getFiles()?.reverse().map(({ id, source }) =>
|
||||
<label className={styles["Image-select"]} key={id}>
|
||||
<label className={styles.ImageSelect} key={id}>
|
||||
<input
|
||||
type="radio"
|
||||
value={source}
|
||||
|
|
|
|||
|
|
@ -16,8 +16,8 @@ export function AppsSettings() {
|
|||
});
|
||||
}, [settingsManager]);
|
||||
|
||||
return <div className={`${styles["Option"]} ${styles["Option-list"]}`}>
|
||||
<p className={styles["Label"]}>Apps</p>
|
||||
return <div className={`${styles.Option} ${styles.OptionList}`}>
|
||||
<p className={styles.Label}>Apps</p>
|
||||
{AppsManager.APPS.sort((a, b) =>
|
||||
a.name.toLowerCase().localeCompare(b.name.toLowerCase())
|
||||
).map((app) =>
|
||||
|
|
|
|||
|
|
@ -17,18 +17,18 @@ export function StorageTab() {
|
|||
const freeKB = maxKB - usedKB;
|
||||
|
||||
return (<>
|
||||
<div className={`${styles["Option"]} ${styles["Progress-bar-container"]}`}>
|
||||
<p className={styles["Label"]}>Virtual Drive ({round(maxKB, 1)} KB)</p>
|
||||
<ProgressBar fillPercentage={usedKB / maxKB * 100} className={styles["Progress-bar"]}/>
|
||||
<span className={styles["Progress-bar-labels"]}>
|
||||
<p className={utilStyles["Text-light"]}>{round(usedKB, 1)} KB used</p>
|
||||
<p className={utilStyles["Text-light"]}>{round(freeKB, 1)} KB free</p>
|
||||
<div className={`${styles.Option} ${styles.ProgressBarContainer}`}>
|
||||
<p className={styles.Label}>Virtual Drive ({round(maxKB, 1)} KB)</p>
|
||||
<ProgressBar fillPercentage={usedKB / maxKB * 100} className={styles.ProgressBar}/>
|
||||
<span className={styles.ProgressBarLabels}>
|
||||
<p className={utilStyles.TextLight}>{round(usedKB, 1)} KB used</p>
|
||||
<p className={utilStyles.TextLight}>{round(freeKB, 1)} KB free</p>
|
||||
</span>
|
||||
</div>
|
||||
<div className={styles["Option"]}>
|
||||
<p className={styles["Label"]}>Manage data</p>
|
||||
<div className={styles.Option}>
|
||||
<p className={styles.Label}>Manage data</p>
|
||||
<Button
|
||||
className={`${styles.Button} ${styles["Button-red"]} ${utilStyles["Text-bold"]}`}
|
||||
className={`${styles.Button} ${styles.ButtonDanger} ${utilStyles.TextBold}`}
|
||||
onClick={() => { virtualRoot.reset?.(); }}
|
||||
>
|
||||
Reset
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
.Container {
|
||||
.TextEditor {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
width: 100%;
|
||||
|
|
@ -6,10 +6,10 @@
|
|||
text-align: start;
|
||||
}
|
||||
|
||||
.Container p,
|
||||
.Container div,
|
||||
.Container span,
|
||||
.Container textarea {
|
||||
.TextEditor p,
|
||||
.TextEditor div,
|
||||
.TextEditor span,
|
||||
.TextEditor textarea {
|
||||
font-size: 1em;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -126,7 +126,7 @@ export function TextEditor({ file, setTitle, setIconUrl, close, mode, app, modal
|
|||
}
|
||||
|
||||
return (
|
||||
<div className={styles.Container} style={{ fontSize: zoom }}>
|
||||
<div className={styles.TextEditor} style={{ fontSize: zoom }}>
|
||||
<HeaderMenu>
|
||||
<DropdownAction label="File" showOnHover={false}>
|
||||
<ClickAction label="New" onTrigger={() => { newText(); }} shortcut={["Control", "e"]}/>
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
.Container {
|
||||
.Desktop {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
|
|
|
|||
|
|
@ -134,7 +134,7 @@ export const Desktop = memo(() => {
|
|||
return (<>
|
||||
<ShortcutsListener/>
|
||||
<div
|
||||
className={styles.Container}
|
||||
className={styles.Desktop}
|
||||
onContextMenu={onContextMenu}
|
||||
>
|
||||
{showIcons && <DirectoryList
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
.Container {
|
||||
.ModalView {
|
||||
--position-x: 0;
|
||||
--position-y: 0;
|
||||
|
||||
|
|
@ -7,7 +7,7 @@
|
|||
left: calc(var(--position-x) * 1px);
|
||||
}
|
||||
|
||||
.Container > * {
|
||||
.ModalView > * {
|
||||
background: var(--background-color-0);
|
||||
border-radius: var(--border-radius-1);
|
||||
box-shadow: var(--window-box-shadow);
|
||||
|
|
|
|||
|
|
@ -33,7 +33,7 @@ export const ModalView: FC<ModalProps> = memo(({ modal }) => {
|
|||
}, [modal]);
|
||||
|
||||
const Container = () => (<div
|
||||
className={styles.Container}
|
||||
className={styles.ModalView}
|
||||
style={{ "--position-x": modal.position.x, "--position-y": modal.position.y } as CSSProperties}
|
||||
>
|
||||
<modal.element modal={modal} {...modal.props}/>
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
.Container {
|
||||
.ModalsView {
|
||||
position: relative;
|
||||
z-index: 11;
|
||||
}
|
||||
|
|
@ -23,7 +23,7 @@ export const ModalsView = memo(() => {
|
|||
modalsManager.containerRef = ref;
|
||||
}, [modalsManager, ref]);
|
||||
|
||||
return <div ref={ref} className={styles.Container}>
|
||||
return <div ref={ref} className={styles.ModalsView}>
|
||||
{sortedModals?.map((modal) =>
|
||||
<ModalView key={modal.id} modal={modal}/>
|
||||
)}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
.Container {
|
||||
.WindowedModal {
|
||||
--header-height: 2.5rem;
|
||||
--header-button-hover-color: rgba(255, 255, 255, 5%);
|
||||
|
||||
|
|
|
|||
|
|
@ -51,7 +51,7 @@ export function WindowedModal({ modal, params, children, ...props }: ModalProps)
|
|||
nodeRef={nodeRef}
|
||||
>
|
||||
<div
|
||||
className={styles.Container}
|
||||
className={styles.WindowedModal}
|
||||
ref={nodeRef}
|
||||
style={{
|
||||
width: modal.size.x,
|
||||
|
|
@ -63,7 +63,7 @@ export function WindowedModal({ modal, params, children, ...props }: ModalProps)
|
|||
className={styles["Window-icon"]}
|
||||
src={iconUrl}
|
||||
/>
|
||||
<p className={utilStyles["Text-semibold"]}>{title}</p>
|
||||
<p className={utilStyles.TextSemibold}>{title}</p>
|
||||
<button aria-label="Close" className={`${styles["Header-button"]} ${styles["Exit-button"]}`} tabIndex={0}
|
||||
onClick={() => { modal.close(); }}>
|
||||
<FontAwesomeIcon icon={faXmark}/>
|
||||
|
|
|
|||
|
|
@ -1,86 +1,4 @@
|
|||
.Container {
|
||||
--header-height: 2.5rem;
|
||||
--header-button-hover-color: rgba(255, 255, 255, 5%);
|
||||
|
||||
position: absolute;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
min-width: 300px;
|
||||
min-height: 150px;
|
||||
background-color: var(--background-color-2) !important;
|
||||
resize: both;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.Header {
|
||||
--dialog-icon-size: 1.5rem;
|
||||
--dialog-icon-margin: 0.75rem;
|
||||
|
||||
display: flex;
|
||||
align-items: center;
|
||||
height: var(--header-height);
|
||||
padding: 0.25rem;
|
||||
padding-left: var(--dialog-icon-margin);
|
||||
padding-right: 0;
|
||||
background-color: var(--background-color-1);
|
||||
cursor: grab;
|
||||
}
|
||||
|
||||
.Dialog-icon,
|
||||
.Dialog-icon > div,
|
||||
.Dialog-icon > div > svg {
|
||||
height: 100%;
|
||||
width: auto;
|
||||
}
|
||||
|
||||
.Dialog-icon {
|
||||
height: var(--dialog-icon-size);
|
||||
margin-right: calc(var(--dialog-icon-margin) - 0.1rem);
|
||||
}
|
||||
|
||||
.Dialog-icon > div {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.Header > p {
|
||||
user-select: none;
|
||||
width: auto;
|
||||
margin: 0;
|
||||
margin-right: auto;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.Header-button {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
height: var(--header-height);
|
||||
margin: 0;
|
||||
padding: 0.75rem;
|
||||
color: var(--foreground-color-0);
|
||||
background: none;
|
||||
cursor: pointer;
|
||||
border: none;
|
||||
outline: none;
|
||||
aspect-ratio: 1;
|
||||
}
|
||||
|
||||
.Header-button > svg {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.Exit-button {
|
||||
--header-button-hover-color: var(--red-0);
|
||||
}
|
||||
|
||||
.Header-button:hover, .Header-button:focus-visible {
|
||||
background-color: var(--header-button-hover-color);
|
||||
}
|
||||
|
||||
.Dialog-content {
|
||||
.DialogContent {
|
||||
position: relative;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
|
@ -91,7 +9,7 @@
|
|||
overflow: hidden;
|
||||
}
|
||||
|
||||
.Dialog-content button {
|
||||
.DialogContent button {
|
||||
margin-bottom: 0.75rem;
|
||||
padding: 0.5rem 1rem;
|
||||
width: fit-content;
|
||||
|
|
@ -104,6 +22,6 @@
|
|||
cursor: pointer;
|
||||
}
|
||||
|
||||
.Dialog-content button:hover, .Dialog-content button:focus-visible {
|
||||
.DialogContent button:hover, .DialogContent button:focus-visible {
|
||||
background-color: var(--background-color-1);
|
||||
}
|
||||
|
|
@ -16,7 +16,7 @@ export function DialogBox({ modal, params, children, ...props }: ModalProps) {
|
|||
};
|
||||
|
||||
return <WindowedModal modal={modal} params={params} onClick={onClick} {...props}>
|
||||
<div className={styles["Dialog-content"]}>
|
||||
<div className={styles.DialogContent}>
|
||||
{children}
|
||||
</div>
|
||||
</WindowedModal>;
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
.Container {
|
||||
.FileProperties {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: flex-start;
|
||||
|
|
@ -65,7 +65,7 @@
|
|||
text-indent: -2rem;
|
||||
}
|
||||
|
||||
.App-icon {
|
||||
.AppIcon {
|
||||
display: inline-block;
|
||||
width: 2rem;
|
||||
height: 2rem;
|
||||
|
|
@ -74,14 +74,14 @@
|
|||
margin-right: 0.25rem;
|
||||
}
|
||||
|
||||
.App-icon div {
|
||||
.AppIcon div {
|
||||
position: relative;
|
||||
width: inherit;
|
||||
height: inherit;
|
||||
object-fit: contain;
|
||||
}
|
||||
|
||||
.App-icon svg {
|
||||
.AppIcon svg {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
|
|
|
|||
|
|
@ -14,26 +14,26 @@ interface FilePropetiesProps extends ModalProps {
|
|||
export function FileProperties({ modal, params, file, ...props }: FilePropetiesProps) {
|
||||
const associatedApp = AppsManager.getAppByFileExtension(file.extension);
|
||||
|
||||
return <WindowedModal className={styles.Container} modal={modal} params={params} {...props}>
|
||||
<span className={styles["Section"]}>
|
||||
<ImagePreview className={styles["Icon"]} source={file.getIconUrl()}/>
|
||||
<p className={`${styles["Line"]} ${utilStyles["Text-bold"]}`}>{file.id}</p>
|
||||
return <WindowedModal className={styles.FileProperties} modal={modal} params={params} {...props}>
|
||||
<span className={styles.Section}>
|
||||
<ImagePreview className={styles.Icon} source={file.getIconUrl()}/>
|
||||
<p className={`${styles.Line} ${utilStyles.TextBold}`}>{file.id}</p>
|
||||
</span>
|
||||
<span className={styles["Section"]}>
|
||||
<p className={styles["Line"]}>Type: {file.getType()}</p>
|
||||
<span className={styles["Line"]}>
|
||||
<span className={styles.Section}>
|
||||
<p className={styles.Line}>Type: {file.getType()}</p>
|
||||
<span className={styles.Line}>
|
||||
Opens with:
|
||||
<ImagePreview className={styles["App-icon"]} source={AppsManager.getAppIconUrl(associatedApp.id)}/>
|
||||
<ImagePreview className={styles.AppIcon} source={AppsManager.getAppIconUrl(associatedApp.id)}/>
|
||||
{associatedApp.name}
|
||||
</span>
|
||||
</span>
|
||||
<span className={styles["Section"]}>
|
||||
<p className={styles["Line"]}>Location: {file.path}</p>
|
||||
<p className={styles["Line"]}>Size: {StorageManager.getByteSize(file.source ?? file.content)} bytes</p>
|
||||
<p className={styles["Line"]}>Size on drive: {StorageManager.getByteSize(file.toString())} bytes</p>
|
||||
<span className={styles.Section}>
|
||||
<p className={styles.Line}>Location: {file.path}</p>
|
||||
<p className={styles.Line}>Size: {StorageManager.getByteSize(file.source ?? file.content)} bytes</p>
|
||||
<p className={styles.Line}>Size on drive: {StorageManager.getByteSize(file.toString())} bytes</p>
|
||||
</span>
|
||||
<span className={styles["Section"]}>
|
||||
<p className={styles["Line"]}>Attributes: {file.isProtected ? "Protected" : "N/A"}</p>
|
||||
<span className={styles.Section}>
|
||||
<p className={styles.Line}>Attributes: {file.isProtected ? "Protected" : "N/A"}</p>
|
||||
</span>
|
||||
</WindowedModal>;
|
||||
}
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
.Container {
|
||||
.Share {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: space-between;
|
||||
|
|
@ -8,14 +8,14 @@
|
|||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.Container > div {
|
||||
.Share > div {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: flex-start;
|
||||
align-items: flex-start;
|
||||
}
|
||||
|
||||
.Container > div:last-child {
|
||||
.Share > div:last-child {
|
||||
gap: 0.5rem;
|
||||
flex-direction: row;
|
||||
justify-content: space-between;
|
||||
|
|
|
|||
|
|
@ -82,7 +82,7 @@ export function Share({ modal, params, ...props }: ModalProps) {
|
|||
});
|
||||
};
|
||||
|
||||
return <WindowedModal className={styles.Container} modal={modal} params={{
|
||||
return <WindowedModal className={styles.Share} modal={modal} params={{
|
||||
...params,
|
||||
title: "Share",
|
||||
iconUrl: ModalsManager.getModalIconUrl("share"),
|
||||
|
|
@ -122,9 +122,9 @@ export function Share({ modal, params, ...props }: ModalProps) {
|
|||
</form>
|
||||
</div>
|
||||
<div>
|
||||
<p className={`${styles.Url} ${utilStyles["Text-light"]}`}>{url}</p>
|
||||
<p className={`${styles.Url} ${utilStyles.TextLight}`}>{url}</p>
|
||||
<Button
|
||||
className={`${styles.Button} ${utilStyles["Text-bold"]}`}
|
||||
className={`${styles.Button} ${utilStyles.TextBold}`}
|
||||
onClick={() => {
|
||||
copyToClipboard(url, () => {
|
||||
alert({
|
||||
|
|
|
|||
|
|
@ -48,25 +48,25 @@
|
|||
background-color: var(--taskbar-button-hover-color);
|
||||
}
|
||||
|
||||
.Home-container,
|
||||
.Search-container {
|
||||
.HomeContainer,
|
||||
.SearchContainer {
|
||||
position: relative;
|
||||
padding: 0 !important;
|
||||
}
|
||||
|
||||
.Home-button * {
|
||||
.HomeButton * {
|
||||
fill: var(--foreground-color-0);
|
||||
filter: none;
|
||||
}
|
||||
|
||||
.Menu-icons,
|
||||
.App-icons-inner {
|
||||
.MenuIcons,
|
||||
.AppIcons {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.App-icons {
|
||||
.AppIconsContainer {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
height: auto;
|
||||
|
|
@ -74,7 +74,7 @@
|
|||
pointer-events: none;
|
||||
}
|
||||
|
||||
.App-icons-inner {
|
||||
.AppIcons {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
|
|
@ -86,30 +86,30 @@
|
|||
z-index: -1;
|
||||
}
|
||||
|
||||
.App-icons-inner::-webkit-scrollbar {
|
||||
.AppIcons::-webkit-scrollbar {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.App-icons-inner > *,
|
||||
.Menu-button {
|
||||
.AppIcons > *,
|
||||
.MenuButton {
|
||||
height: 100%;
|
||||
padding: 0.75rem;
|
||||
}
|
||||
|
||||
.App-icons-inner > * > svg,
|
||||
.Menu-button > svg {
|
||||
.AppIcons > * > svg,
|
||||
.MenuButton > svg {
|
||||
height: 1.25rem;
|
||||
}
|
||||
|
||||
.App-icons-inner div,
|
||||
.App-icons-inner div > svg,
|
||||
.Menu-icons div,
|
||||
.Menu-icons div > svg {
|
||||
.AppIcons div,
|
||||
.AppIcons div > svg,
|
||||
.MenuIcons div,
|
||||
.MenuIcons div > svg {
|
||||
height: 100%;
|
||||
width: auto;
|
||||
}
|
||||
|
||||
.Util-icons {
|
||||
.UtilIcons {
|
||||
display: flex;
|
||||
gap: 0;
|
||||
justify-content: flex-end;
|
||||
|
|
@ -120,22 +120,22 @@
|
|||
z-index: -1;
|
||||
}
|
||||
|
||||
.Util-icons > div {
|
||||
.UtilIcons > div {
|
||||
height: 100%;
|
||||
width: min-content;
|
||||
z-index: -1;
|
||||
}
|
||||
|
||||
.Util-icons > button,
|
||||
.Util-icons > div > button {
|
||||
.UtilIcons > button,
|
||||
.UtilIcons > div > button {
|
||||
height: 100%;
|
||||
width: min-content;
|
||||
margin: 0;
|
||||
padding: 0.4rem;
|
||||
}
|
||||
|
||||
.Util-icons > button > svg,
|
||||
.Util-icons > div > button > svg {
|
||||
.UtilIcons > button > svg,
|
||||
.UtilIcons > div > button > svg {
|
||||
height: 1rem;
|
||||
width: 1rem;
|
||||
aspect-ratio: 1;
|
||||
|
|
@ -149,7 +149,7 @@
|
|||
margin-left: 1rem;
|
||||
}
|
||||
|
||||
.Menu-outer {
|
||||
.MenuContainer {
|
||||
position: absolute;
|
||||
right: 0;
|
||||
bottom: 100%;
|
||||
|
|
@ -157,11 +157,11 @@
|
|||
overflow: hidden;
|
||||
}
|
||||
|
||||
.Menu-outer:not(.Active) {
|
||||
.MenuContainer:not(.Active) {
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.Menu-inner {
|
||||
.Menu {
|
||||
opacity: 1;
|
||||
display: flex;
|
||||
border-top-left-radius: var(--border-radius-1);
|
||||
|
|
@ -173,13 +173,13 @@
|
|||
resize: horizontal;
|
||||
}
|
||||
|
||||
.Menu-outer:not(.Active) .Menu-inner {
|
||||
.MenuContainer:not(.Active) .Menu {
|
||||
opacity: 0;
|
||||
transform: translateY(100px);
|
||||
}
|
||||
|
||||
.Menu-inner::after,
|
||||
.Menu-outer::after {
|
||||
.Menu::after,
|
||||
.MenuContainer::after {
|
||||
content: "";
|
||||
position: absolute;
|
||||
top: 0;
|
||||
|
|
@ -190,20 +190,20 @@
|
|||
pointer-events: none;
|
||||
}
|
||||
|
||||
.Menu-inner::after {
|
||||
.Menu::after {
|
||||
opacity: var(--taskbar-menu-opacity);
|
||||
background-color: var(--taskbar-menu-color);
|
||||
z-index: -2;
|
||||
}
|
||||
|
||||
.Menu-outer::after {
|
||||
.MenuContainer::after {
|
||||
opacity: 1;
|
||||
transition: opacity 200ms ease-in-out, top 200ms ease-in-out;
|
||||
backdrop-filter: var(--taskbar-filter);
|
||||
z-index: -3;
|
||||
}
|
||||
|
||||
.Menu-outer:not(.Active)::after {
|
||||
.MenuContainer:not(.Active)::after {
|
||||
opacity: 0;
|
||||
top: 100px;
|
||||
}
|
||||
|
|
@ -129,20 +129,20 @@ export const Taskbar = memo(() => {
|
|||
return (<>
|
||||
<div
|
||||
style={{ "--taskbar-height": `${TASKBAR_HEIGHT}px`, zIndex } as CSSProperties}
|
||||
className={styles["Taskbar"]}
|
||||
className={styles.Taskbar}
|
||||
data-allow-context-menu={true}
|
||||
onContextMenu={(event) => {
|
||||
if ((event.target as HTMLElement).getAttribute("data-allow-context-menu"))
|
||||
onContextMenu(event);
|
||||
}}
|
||||
>
|
||||
<div className={styles["Menu-icons"]}>
|
||||
<div className={styles["Home-container"]}>
|
||||
<div className={styles.MenuIcons}>
|
||||
<div className={styles.HomeContainer}>
|
||||
<OutsideClickListener onOutsideClick={() => { updateShowHome(false); }}>
|
||||
<button
|
||||
title="Home"
|
||||
tabIndex={0}
|
||||
className={`${styles["Menu-button"]} ${styles["Home-button"]}`}
|
||||
className={`${styles.MenuButton} ${styles.HomeButton}`}
|
||||
onClick={() => { updateShowHome(!showHome); }}
|
||||
>
|
||||
<ReactSVG src={"/icon.svg"}/>
|
||||
|
|
@ -150,12 +150,12 @@ export const Taskbar = memo(() => {
|
|||
<HomeMenu active={showHome} setActive={updateShowHome} search={search}/>
|
||||
</OutsideClickListener>
|
||||
</div>
|
||||
<div className={styles["Search-container"]}>
|
||||
<div className={styles.SearchContainer}>
|
||||
<OutsideClickListener onOutsideClick={() => { updateShowSearch(false); }}>
|
||||
<button
|
||||
title="Search"
|
||||
tabIndex={0}
|
||||
className={`${styles["Menu-button"]} ${styles["Search-button"]}`}
|
||||
className={styles.MenuButton}
|
||||
onClick={() => { updateShowSearch(!showSearch); }}
|
||||
>
|
||||
<FontAwesomeIcon icon={faSearch}/>
|
||||
|
|
@ -170,9 +170,9 @@ export const Taskbar = memo(() => {
|
|||
</OutsideClickListener>
|
||||
</div>
|
||||
</div>
|
||||
<div className={styles["App-icons"]} data-allow-context-menu={true} style={{ boxShadow }}>
|
||||
<div className={styles.AppIconsContainer} data-allow-context-menu={true} style={{ boxShadow }}>
|
||||
<div
|
||||
className={styles["App-icons-inner"]}
|
||||
className={styles.AppIcons}
|
||||
data-allow-context-menu={true}
|
||||
onScroll={onUpdate as unknown as UIEventHandler}
|
||||
onResize={onUpdate as unknown as ReactEventHandler}
|
||||
|
|
@ -181,7 +181,7 @@ export const Taskbar = memo(() => {
|
|||
{apps}
|
||||
</div>
|
||||
</div>
|
||||
<div className={styles["Util-icons"]}>
|
||||
<div className={styles.UtilIcons}>
|
||||
<Battery showUtilMenu={showUtilMenu} hideUtilMenus={hideUtilMenus}/>
|
||||
<Network showUtilMenu={showUtilMenu} hideUtilMenus={hideUtilMenus}/>
|
||||
<Volume showUtilMenu={showUtilMenu} hideUtilMenus={hideUtilMenus}/>
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
.App-list {
|
||||
.AppList {
|
||||
--scrollbar-color: rgba(0, 0, 0, 25%);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
|
@ -8,7 +8,7 @@
|
|||
z-index: 0;
|
||||
}
|
||||
|
||||
.App-button {
|
||||
.AppButton {
|
||||
display: flex;
|
||||
gap: 1rem;
|
||||
width: 100%;
|
||||
|
|
@ -16,18 +16,18 @@
|
|||
border-radius: var(--border-radius-1);
|
||||
}
|
||||
|
||||
.App-button > div,
|
||||
.App-button > div > div,
|
||||
.App-button > div > div > svg {
|
||||
.AppButton > div,
|
||||
.AppButton > div > div,
|
||||
.AppButton > div > div > svg {
|
||||
width: 2rem;
|
||||
height: 2rem;
|
||||
}
|
||||
|
||||
.App-button svg {
|
||||
.AppButton svg {
|
||||
filter: var(--svg-drop-shadow-0);
|
||||
}
|
||||
|
||||
.App-button > p, .App-button > h2 {
|
||||
.AppButton > p, .AppButton > h2 {
|
||||
margin: 0;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
|
@ -1,9 +1,9 @@
|
|||
.Container-outer {
|
||||
.HomeMenuContainer {
|
||||
right: unset;
|
||||
left: 0;
|
||||
}
|
||||
|
||||
.Container-inner {
|
||||
.HomeMenu {
|
||||
min-width: 16rem;
|
||||
max-width: 32rem;
|
||||
border-bottom-left-radius: 0;
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@ export function HomeMenu({ active, setActive, search }: HomeMenuProps) {
|
|||
setTabIndex(active ? 0 : -1);
|
||||
}, [active]);
|
||||
|
||||
const classNames = [styles["Container-outer"], taskbarStyles["Menu-outer"]];
|
||||
const classNames = [styles.HomeMenuContainer, taskbarStyles.MenuContainer];
|
||||
if (active)
|
||||
classNames.push(taskbarStyles.Active);
|
||||
|
||||
|
|
@ -62,7 +62,7 @@ export function HomeMenu({ active, setActive, search }: HomeMenuProps) {
|
|||
|
||||
return (
|
||||
<div className={classNames.join(" ")}>
|
||||
<div className={`${styles["Container-inner"]} ${taskbarStyles["Menu-inner"]}`}>
|
||||
<div className={`${styles.HomeMenu} ${taskbarStyles.Menu}`}>
|
||||
<div className={styles.Buttons}>
|
||||
<button title="Shut Down" tabIndex={tabIndex} onClick={() => { closeViewport(true); }}>
|
||||
<FontAwesomeIcon icon={faPowerOff}/>
|
||||
|
|
@ -97,12 +97,12 @@ export function HomeMenu({ active, setActive, search }: HomeMenuProps) {
|
|||
</button>
|
||||
</div>
|
||||
<div className={styles.Apps}>
|
||||
<h1 className={utilStyles["Text-bold"]}>{NAME}</h1>
|
||||
<div className={appStyles["App-list"]}>
|
||||
<h1 className={utilStyles.TextBold}>{NAME}</h1>
|
||||
<div className={appStyles.AppList}>
|
||||
{AppsManager.APPS.map(({ name, id }) =>
|
||||
<button
|
||||
key={id}
|
||||
className={appStyles["App-button"]}
|
||||
className={appStyles.AppButton}
|
||||
tabIndex={tabIndex}
|
||||
onClick={() => {
|
||||
setActive(false);
|
||||
|
|
@ -111,7 +111,7 @@ export function HomeMenu({ active, setActive, search }: HomeMenuProps) {
|
|||
title={name}
|
||||
>
|
||||
<ReactSVG src={AppsManager.getAppIconUrl(id)}/>
|
||||
<h2 className={utilStyles["Text-regular"]}>{name}</h2>
|
||||
<h2 className={utilStyles.TextRegular}>{name}</h2>
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
.Container-outer {
|
||||
.SearchMenuContainer {
|
||||
position: absolute;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
|
@ -9,7 +9,7 @@
|
|||
overflow: hidden;
|
||||
}
|
||||
|
||||
.Container-inner {
|
||||
.SearchMenu {
|
||||
opacity: 1;
|
||||
display: flex;
|
||||
gap: 0.5rem;
|
||||
|
|
@ -27,7 +27,7 @@
|
|||
resize: horizontal;
|
||||
}
|
||||
|
||||
.Container-inner::after {
|
||||
.SearchMenu::after {
|
||||
opacity: var(--taskbar-menu-opacity);
|
||||
content: "";
|
||||
position: absolute;
|
||||
|
|
@ -39,16 +39,16 @@
|
|||
z-index: -2;
|
||||
}
|
||||
|
||||
.Container-outer:not(.Active) {
|
||||
.SearchMenuContainer:not(.Active) {
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.Container-outer:not(.Active) .Container-inner {
|
||||
.SearchMenuContainer:not(.Active) .SearchMenu {
|
||||
opacity: 0;
|
||||
transform: translateY(100px);
|
||||
}
|
||||
|
||||
.Container-inner > div {
|
||||
.SearchMenu > div {
|
||||
margin-top: auto;
|
||||
}
|
||||
|
||||
|
|
@ -64,6 +64,6 @@
|
|||
font-size: inherit;
|
||||
}
|
||||
|
||||
.Container-inner > div > button:first-child {
|
||||
.SearchMenu > div > button:first-child {
|
||||
background-color: var(--taskbar-button-hover-color);
|
||||
}
|
||||
|
|
@ -44,7 +44,7 @@ export function SearchMenu({ active, setActive, searchQuery, setSearchQuery, inp
|
|||
setSearchQuery(value);
|
||||
};
|
||||
|
||||
const classNames = [styles["Container-outer"]];
|
||||
const classNames = [styles.SearchMenuContainer];
|
||||
if (active && apps)
|
||||
classNames.push(styles.Active);
|
||||
|
||||
|
|
@ -66,7 +66,7 @@ export function SearchMenu({ active, setActive, searchQuery, setSearchQuery, inp
|
|||
|
||||
return (
|
||||
<div className={classNames.join(" ")}>
|
||||
<div className={styles["Container-inner"]}>
|
||||
<div className={styles.SearchMenu}>
|
||||
<input
|
||||
ref={inputRef}
|
||||
className={styles.Input}
|
||||
|
|
@ -77,11 +77,11 @@ export function SearchMenu({ active, setActive, searchQuery, setSearchQuery, inp
|
|||
spellCheck={false}
|
||||
placeholder="Search..."
|
||||
/>
|
||||
<div className={appStyles["App-list"]}>
|
||||
<div className={appStyles.AppList}>
|
||||
{apps?.map(({ name, id }) =>
|
||||
<button
|
||||
key={id}
|
||||
className={appStyles["App-button"]}
|
||||
className={appStyles.AppButton}
|
||||
tabIndex={tabIndex}
|
||||
onClick={() => {
|
||||
setActive(false);
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
.Container-outer {
|
||||
.UtilMenuContainer {
|
||||
position: absolute;
|
||||
right: 0;
|
||||
bottom: 100%;
|
||||
|
|
@ -6,7 +6,7 @@
|
|||
overflow: hidden;
|
||||
}
|
||||
|
||||
.Container-inner {
|
||||
.UtilMenu {
|
||||
opacity: 1;
|
||||
display: flex;
|
||||
border-top-left-radius: var(--border-radius-1);
|
||||
|
|
@ -19,7 +19,7 @@
|
|||
resize: horizontal;
|
||||
}
|
||||
|
||||
.Container-inner::after {
|
||||
.UtilMenu::after {
|
||||
opacity: var(--taskbar-menu-opacity);
|
||||
content: "";
|
||||
position: absolute;
|
||||
|
|
@ -31,11 +31,11 @@
|
|||
z-index: -2;
|
||||
}
|
||||
|
||||
.Container-outer:not(.Active) {
|
||||
.UtilMenuContainer:not(.Active) {
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.Container-outer:not(.Active) .Container-inner {
|
||||
.UtilMenuContainer:not(.Active) .UtilMenu {
|
||||
opacity: 0;
|
||||
transform: translateY(100px);
|
||||
}
|
||||
|
|
@ -9,14 +9,14 @@ interface UtilMenuProps {
|
|||
}
|
||||
|
||||
export function UtilMenu({ active, setActive: _setActive, className, children }: UtilMenuProps) {
|
||||
const classNames = [styles["Container-outer"]];
|
||||
const classNames = [styles.UtilMenuContainer];
|
||||
if (active)
|
||||
classNames.push(styles.Active);
|
||||
if (className != null)
|
||||
classNames.push(className);
|
||||
|
||||
return (<div className={classNames.join(" ")}>
|
||||
<div className={styles["Container-inner"]}>
|
||||
<div className={styles.UtilMenu}>
|
||||
{children}
|
||||
</div>
|
||||
</div>);
|
||||
|
|
|
|||
|
|
@ -172,7 +172,7 @@ export const WindowView: FC<WindowProps> = memo(({ id, app, size, position, onIn
|
|||
className={styles["Window-icon"]}
|
||||
src={iconUrl}
|
||||
/>
|
||||
<p className={utilStyles["Text-semibold"]}>{title}</p>
|
||||
<p className={utilStyles.TextSemibold}>{title}</p>
|
||||
<button aria-label="Minimize" className={styles["Header-button"]} tabIndex={0} id="minimize-window"
|
||||
onClick={toggleMinimized as MouseEventHandler}
|
||||
>
|
||||
|
|
|
|||
7
src/config/actions.config.ts
Normal file
7
src/config/actions.config.ts
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
import styles from "../components/actions/Actions.module.css";
|
||||
|
||||
export const STYLES = {
|
||||
CONTEXT_MENU: styles.ContextMenu,
|
||||
SHORTCUTS_LISTENER: styles["Shortcuts-listener"],
|
||||
HEADER_MENU: styles["Header-menu"]
|
||||
};
|
||||
15
src/features/_utils/classNames.utils.ts
Normal file
15
src/features/_utils/classNames.utils.ts
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
export function classNames(...args: string[]) {
|
||||
let className = "";
|
||||
|
||||
for (let i = 0; i < args.length; i++) {
|
||||
const value = args[i];
|
||||
|
||||
if (typeof value === "string") {
|
||||
className += value + " ";
|
||||
} else if (Array.isArray(value)) {
|
||||
className += classNames(...value as string[]) + " ";
|
||||
}
|
||||
}
|
||||
|
||||
return className.trim();
|
||||
}
|
||||
13
src/features/_utils/time.utils.ts
Normal file
13
src/features/_utils/time.utils.ts
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
import { formatRelativeTime } from "./date.utils";
|
||||
|
||||
export class TimeManager {
|
||||
static startDate: Date;
|
||||
|
||||
static reset() {
|
||||
TimeManager.startDate = new Date();
|
||||
}
|
||||
|
||||
static getUptime(precision = 2) {
|
||||
return formatRelativeTime(TimeManager.startDate, precision, false);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,8 +1,7 @@
|
|||
import { APPS } from "../../../../config/apps.config";
|
||||
import { ANSI } from "../../../../config/apps/terminal.config";
|
||||
import { ANSI_ASCII_LOGO, ANSI_LOGO_COLOR, NAME } from "../../../../config/branding.config";
|
||||
import { START_DATE } from "../../../../index";
|
||||
import { formatRelativeTime } from "../../../_utils/date.utils";
|
||||
import { TimeManager } from "../../../_utils/time.utils";
|
||||
import AppsManager from "../../appsManager";
|
||||
import Command from "../command";
|
||||
|
||||
|
|
@ -36,7 +35,7 @@ export const neofetch = new Command()
|
|||
`${ANSI.fg.cyan + username + ANSI.reset}@${ANSI.fg.cyan + hostname + ANSI.reset}`,
|
||||
"-".repeat(rightColumnWidth),
|
||||
formatLine("os", NAME),
|
||||
formatLine("uptime", formatRelativeTime(START_DATE, 2, false)),
|
||||
formatLine("uptime", TimeManager.getUptime(2)),
|
||||
formatLine("resolution", window.innerWidth + "x" + window.innerHeight),
|
||||
formatLine("theme", "default"),
|
||||
formatLine("icons", "Font Awesome"),
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
import { START_DATE } from "../../../../index";
|
||||
import { formatRelativeTime } from "../../../_utils/date.utils";
|
||||
import { TimeManager } from "../../../_utils/time.utils";
|
||||
import Command from "../command";
|
||||
|
||||
|
||||
|
|
@ -8,5 +7,5 @@ export const uptime = new Command()
|
|||
purpose: "Display the current uptime of the system"
|
||||
})
|
||||
.setExecute(() => {
|
||||
return `Uptime: ${formatRelativeTime(START_DATE, 2, false)}`;
|
||||
return `Uptime: ${TimeManager.getUptime(2)}`;
|
||||
});
|
||||
|
|
@ -1,9 +1,10 @@
|
|||
import { FC, MouseEvent, useCallback } from "react";
|
||||
import Vector2 from "../../features/math/vector2";
|
||||
import Modal from "../../features/modals/modal";
|
||||
import { ActionsProps, STYLES } from "../../components/actions/Actions";
|
||||
import { ActionsProps } from "../../components/actions/Actions";
|
||||
import { useModalsManager } from "./modalsManagerContext";
|
||||
import { ModalProps } from "../../components/modals/ModalView";
|
||||
import { STYLES } from "../../config/actions.config";
|
||||
|
||||
interface UseContextMenuParams {
|
||||
Actions: FC<ActionsProps>;
|
||||
|
|
|
|||
|
|
@ -2,11 +2,11 @@ import React from "react";
|
|||
import ReactDOM from "react-dom/client";
|
||||
import "./styles/global.css";
|
||||
import App from "./App";
|
||||
import reportWebVitals from "./reportWebVitals";
|
||||
import { ASCII_LOGO, NAME } from "./config/branding.config";
|
||||
import { TrackingManager } from "./features/tracking/trackingManager";
|
||||
import { TimeManager } from "./features/_utils/time.utils";
|
||||
|
||||
export const START_DATE = new Date();
|
||||
TimeManager.reset();
|
||||
|
||||
TrackingManager.initialize();
|
||||
|
||||
|
|
@ -20,9 +20,4 @@ root.render(<React.StrictMode>
|
|||
const asciiLogoWidth = ASCII_LOGO.split("\n")[1].length;
|
||||
const welcomeMessage = `Welcome to ${NAME}`;
|
||||
const space = "\n\n" + " ".repeat(Math.ceil((asciiLogoWidth - welcomeMessage.length) / 2));
|
||||
console.info(ASCII_LOGO + space + welcomeMessage);
|
||||
|
||||
// If you want to start measuring performance in your app, pass a function
|
||||
// to log results (for example: reportWebVitals(console.log))
|
||||
// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
|
||||
reportWebVitals(() => {});
|
||||
console.info(ASCII_LOGO + space + welcomeMessage);
|
||||
|
|
@ -1,15 +0,0 @@
|
|||
import { ReportHandler } from "web-vitals";
|
||||
|
||||
const reportWebVitals = (onPerfEntry: ReportHandler) => {
|
||||
if (onPerfEntry && onPerfEntry instanceof Function) {
|
||||
void import("web-vitals").then(({ getCLS, getFID, getFCP, getLCP, getTTFB }) => {
|
||||
getCLS(onPerfEntry);
|
||||
getFID(onPerfEntry);
|
||||
getFCP(onPerfEntry);
|
||||
getLCP(onPerfEntry);
|
||||
getTTFB(onPerfEntry);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
export default reportWebVitals;
|
||||
|
|
@ -1,22 +1,22 @@
|
|||
.Text-regular {
|
||||
.TextRegular {
|
||||
font-size: 1em;
|
||||
font-weight: 400;
|
||||
letter-spacing: normal;
|
||||
}
|
||||
|
||||
.Text-light {
|
||||
.TextLight {
|
||||
color: var(--foreground-color-1);
|
||||
font-size: 0.875em;
|
||||
font-weight: 400;
|
||||
letter-spacing: normal;
|
||||
}
|
||||
|
||||
.Text-semibold {
|
||||
.TextSemibold {
|
||||
font-weight: 500;
|
||||
letter-spacing: normal;
|
||||
}
|
||||
|
||||
.Text-bold {
|
||||
.TextBold {
|
||||
font-weight: 600;
|
||||
letter-spacing: normal;
|
||||
}
|
||||
Loading…
Reference in a new issue