feat(misc): add layout for project details view (#21172)
This commit is contained in:
parent
ea3c2426d3
commit
49cff89908
@ -1,4 +1,4 @@
|
||||
import { themeInit } from './theme-resolver';
|
||||
import { themeInit } from '@nx/graph/ui-theme';
|
||||
import { rankDirInit } from './rankdir-resolver';
|
||||
import { RouterProvider } from 'react-router-dom';
|
||||
import { getRouter } from './get-router';
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
import { GraphService } from '@nx/graph/ui-graph';
|
||||
import { selectValueByThemeStatic } from '../theme-resolver';
|
||||
import { getProjectGraphDataService } from '../hooks/get-project-graph-data-service';
|
||||
import { getEnvironmentConfig } from '@nx/graph/shared';
|
||||
import { selectValueByThemeStatic } from '@nx/graph/ui-theme';
|
||||
|
||||
let graphService: GraphService;
|
||||
|
||||
|
||||
@ -7,7 +7,7 @@ import classNames from 'classnames';
|
||||
import { DebuggerPanel } from './ui-components/debugger-panel';
|
||||
import { getGraphService } from './machines/graph.service';
|
||||
import { Outlet, useNavigate, useParams } from 'react-router-dom';
|
||||
import { ThemePanel } from './feature-projects/panels/theme-panel';
|
||||
import { getSystemTheme, Theme, ThemePanel } from '@nx/graph/ui-theme';
|
||||
import { Dropdown } from '@nx/graph/ui-components';
|
||||
import { useCurrentPath } from './hooks/use-current-path';
|
||||
import { ExperimentalFeature } from './ui-components/experimental-feature';
|
||||
@ -31,6 +31,9 @@ export function Shell(): JSX.Element {
|
||||
|
||||
const environment = useEnvironmentConfig();
|
||||
const environmentConfig = useEnvironmentConfig();
|
||||
function onThemeChange(theme: Theme) {
|
||||
graphService.theme = theme === 'system' ? getSystemTheme() : theme;
|
||||
}
|
||||
|
||||
const navigate = useNavigate();
|
||||
const currentPath = useCurrentPath();
|
||||
@ -71,7 +74,7 @@ export function Shell(): JSX.Element {
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className="flex max-h-screen w-full">
|
||||
<div
|
||||
className={`${
|
||||
environmentConfig.environment === 'nx-console'
|
||||
@ -124,7 +127,7 @@ export function Shell(): JSX.Element {
|
||||
<RankdirPanel />
|
||||
</ExperimentalFeature>
|
||||
|
||||
<ThemePanel />
|
||||
<ThemePanel onThemeChange={onThemeChange} />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -202,6 +205,6 @@ export function Shell(): JSX.Element {
|
||||
</Tooltip>
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en" class="h-full w-full overflow-hidden">
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<title>Nx Workspace Project Graph</title>
|
||||
@ -25,9 +25,7 @@
|
||||
</script>
|
||||
</head>
|
||||
|
||||
<body
|
||||
class="h-full w-full overflow-hidden bg-white text-slate-500 dark:bg-slate-900 dark:text-slate-400"
|
||||
>
|
||||
<div class="flex h-full w-full overflow-hidden p-0" id="app"></div>
|
||||
<body class="bg-white text-slate-500 dark:bg-slate-900 dark:text-slate-400">
|
||||
<div class="flex p-0" id="app"></div>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@ -1,8 +1,10 @@
|
||||
/* eslint-disable @nx/enforce-module-boundaries */
|
||||
// nx-ignore-next-line
|
||||
import { ProjectGraphProjectNode } from '@nx/devkit';
|
||||
import { useRouteLoaderData } from 'react-router-dom';
|
||||
import { Link, useRouteLoaderData } from 'react-router-dom';
|
||||
import ProjectDetails from './project-details';
|
||||
import { useEnvironmentConfig, useRouteConstructor } from '@nx/graph/shared';
|
||||
import { ThemePanel } from '@nx/graph/ui-theme';
|
||||
|
||||
export function ProjectDetailsPage() {
|
||||
const { project, sourceMap } = useRouteLoaderData(
|
||||
@ -12,5 +14,49 @@ export function ProjectDetailsPage() {
|
||||
sourceMap: Record<string, string[]>;
|
||||
};
|
||||
|
||||
return ProjectDetails({ project, sourceMap });
|
||||
const environment = useEnvironmentConfig()?.environment;
|
||||
|
||||
const routeConstructor = useRouteConstructor();
|
||||
|
||||
return (
|
||||
<div className="flex flex-col justify-center w-full text-slate-700 dark:text-slate-400">
|
||||
{environment !== 'nx-console' ? (
|
||||
<header className="flex w-full justify-center items-center px-4 py-2 border-b-2 border-slate-900/10 mb-16 dark:border-slate-300/10">
|
||||
<div className="flex flex-grow items-center justify-between max-w-6xl">
|
||||
<svg
|
||||
className="h-10 w-auto text-slate-900 dark:text-white"
|
||||
viewBox="0 0 24 24"
|
||||
fill="currentColor"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<title>Nx</title>
|
||||
<path d="M11.987 14.138l-3.132 4.923-5.193-8.427-.012 8.822H0V4.544h3.691l5.247 8.833.005-3.998 3.044 4.759zm.601-5.761c.024-.048 0-3.784.008-3.833h-3.65c.002.059-.005 3.776-.003 3.833h3.645zm5.634 4.134a2.061 2.061 0 0 0-1.969 1.336 1.963 1.963 0 0 1 2.343-.739c.396.161.917.422 1.33.283a2.1 2.1 0 0 0-1.704-.88zm3.39 1.061c-.375-.13-.8-.277-1.109-.681-.06-.08-.116-.17-.176-.265a2.143 2.143 0 0 0-.533-.642c-.294-.216-.68-.322-1.18-.322a2.482 2.482 0 0 0-2.294 1.536 2.325 2.325 0 0 1 4.002.388.75.75 0 0 0 .836.334c.493-.105.46.36 1.203.518v-.133c-.003-.446-.246-.55-.75-.733zm2.024 1.266a.723.723 0 0 0 .347-.638c-.01-2.957-2.41-5.487-5.37-5.487a5.364 5.364 0 0 0-4.487 2.418c-.01-.026-1.522-2.39-1.538-2.418H8.943l3.463 5.423-3.379 5.32h3.54l1.54-2.366 1.568 2.366h3.541l-3.21-5.052a.7.7 0 0 1-.084-.32 2.69 2.69 0 0 1 2.69-2.691h.001c1.488 0 1.736.89 2.057 1.308.634.826 1.9.464 1.9 1.541a.707.707 0 0 0 1.066.596zm.35.133c-.173.372-.56.338-.755.639-.176.271.114.412.114.412s.337.156.538-.311c.104-.231.14-.488.103-.74z" />
|
||||
</svg>
|
||||
<ul className="flex items-center">
|
||||
<li>
|
||||
<Link
|
||||
to={routeConstructor(
|
||||
`/projects/${encodeURIComponent(project.name)}`,
|
||||
true
|
||||
)}
|
||||
title="View in Graph"
|
||||
>
|
||||
Graph
|
||||
</Link>
|
||||
</li>
|
||||
<li className="ml-4">
|
||||
<ThemePanel />
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</header>
|
||||
) : null}
|
||||
<div className="flex-grow mx-auto w-full max-w-6xl px-8 mb-8">
|
||||
<ProjectDetails
|
||||
project={project}
|
||||
sourceMap={sourceMap}
|
||||
></ProjectDetails>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@ -12,7 +12,6 @@ import {
|
||||
useEnvironmentConfig,
|
||||
useRouteConstructor,
|
||||
} from '@nx/graph/shared';
|
||||
import PropertyRenderer from './property-renderer';
|
||||
import Target from './target';
|
||||
|
||||
export interface ProjectDetailsProps {
|
||||
@ -30,7 +29,12 @@ export function ProjectDetails({
|
||||
const environment = useEnvironmentConfig()?.environment;
|
||||
const externalApiService = getExternalApiService();
|
||||
const navigate = useNavigate();
|
||||
const routeContructor = useRouteConstructor();
|
||||
const routeConstructor = useRouteConstructor();
|
||||
|
||||
const displayType =
|
||||
projectData.projectType &&
|
||||
projectData.projectType?.charAt(0)?.toUpperCase() +
|
||||
projectData.projectType?.slice(1);
|
||||
|
||||
const viewInProjectGraph = () => {
|
||||
if (environment === 'nx-console') {
|
||||
@ -41,25 +45,40 @@ export function ProjectDetails({
|
||||
},
|
||||
});
|
||||
} else {
|
||||
navigate(routeContructor(`/projects/${encodeURIComponent(name)}`, true));
|
||||
navigate(routeConstructor(`/projects/${encodeURIComponent(name)}`, true));
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="m-4 overflow-auto w-full">
|
||||
<h1 className="text-2xl flex items-center gap-2">
|
||||
<>
|
||||
<header className="border-b border-slate-900/10 mb-4 dark:border-slate-300/10">
|
||||
<h1 className="text-6xl flex items-center mb-4 gap-2">
|
||||
{name}{' '}
|
||||
{environment === 'nx-console' ? (
|
||||
<EyeIcon className="h-5 w-5" onClick={viewInProjectGraph}></EyeIcon>
|
||||
) : null}{' '}
|
||||
</h1>
|
||||
<h2 className="text-lg pl-6 mb-3 flex flex-row gap-2">
|
||||
{root}{' '}
|
||||
<div className="p-4">
|
||||
{projectData.tags ? (
|
||||
<p>
|
||||
{projectData.tags?.map((tag) => (
|
||||
<p className="bg-slate-300">{tag}</p>
|
||||
<span className="bg-slate-300 rounded-md p-1 mr-2">{tag}</span>
|
||||
))}
|
||||
</h2>
|
||||
</p>
|
||||
) : null}
|
||||
<p>
|
||||
<span className="font-bold">Root:</span> {root}
|
||||
</p>
|
||||
{displayType ? (
|
||||
<p>
|
||||
<span className="font-bold">Type:</span> {displayType}
|
||||
</p>
|
||||
) : null}
|
||||
</div>
|
||||
</header>
|
||||
<div>
|
||||
<div className="mb-2">
|
||||
<h2 className="text-xl mb-2">Targets</h2>
|
||||
<h2 className="text-3xl mb-2">Targets</h2>
|
||||
<ul>
|
||||
{Object.entries(projectData.targets ?? {}).map(
|
||||
([targetName, target]) => {
|
||||
const props = {
|
||||
@ -68,30 +87,16 @@ export function ProjectDetails({
|
||||
targetConfiguration: target,
|
||||
sourceMap,
|
||||
};
|
||||
return <Target {...props} />;
|
||||
return (
|
||||
<li className="mb-4">
|
||||
<Target {...props} />
|
||||
</li>
|
||||
);
|
||||
}
|
||||
)}
|
||||
</ul>
|
||||
</div>
|
||||
{Object.entries(projectData).map(([key, value]) => {
|
||||
if (
|
||||
key === 'targets' ||
|
||||
key === 'root' ||
|
||||
key === 'name' ||
|
||||
key === '$schema' ||
|
||||
key === 'tags' ||
|
||||
key === 'files' ||
|
||||
key === 'sourceRoot'
|
||||
)
|
||||
return undefined;
|
||||
|
||||
return PropertyRenderer({
|
||||
propertyKey: key,
|
||||
propertyValue: value,
|
||||
sourceMap,
|
||||
});
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@ -120,72 +120,49 @@ export function Target({
|
||||
: true);
|
||||
|
||||
return (
|
||||
<div className="ml-3 mb-3 rounded-md border border-slate-500 relative overflow-hidden">
|
||||
{/* header */}
|
||||
<div className="group hover:bg-slate-800 px-2 cursor-pointer ">
|
||||
<h3
|
||||
className="text-lg font-bold flex items-center gap-2"
|
||||
<div className="rounded-md border border-slate-500 relative overflow-hidden">
|
||||
<header
|
||||
className={`flex space-between group hover:bg-slate-200 dark:hover:bg-slate-800 p-2 cursor-pointer items-center ${
|
||||
!collapsed
|
||||
? 'bg-slate-200 dark:bg-slate-800 border-b-2 border-slate-900/10 dark:border-slate-300/10 '
|
||||
: ''
|
||||
}`}
|
||||
onClick={toggleCollapsed}
|
||||
>
|
||||
{targetName}{' '}
|
||||
<h4 className="text-sm text-slate-600">
|
||||
<h3 className="font-bold mr-2">{targetName}</h3>
|
||||
<p className="text-slate-600 mr-2">
|
||||
{targetConfiguration?.command ??
|
||||
targetConfiguration.options?.command ??
|
||||
targetConfiguration.executor}
|
||||
</h4>
|
||||
<span
|
||||
className={
|
||||
collapsed ? 'hidden group-hover:inline-flex' : 'inline-flex'
|
||||
}
|
||||
>
|
||||
<span
|
||||
className={`inline-flex justify-center rounded-md p-1 hover:bg-slate-100 hover:dark:bg-slate-700
|
||||
}`}
|
||||
>
|
||||
<EyeIcon
|
||||
className="h-4 w-4"
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
viewInTaskGraph();
|
||||
}}
|
||||
></EyeIcon>
|
||||
</span>
|
||||
{environment === 'nx-console' && (
|
||||
<span
|
||||
className={`inline-flex justify-center rounded-md p-1 hover:bg-slate-100 hover:dark:bg-slate-700
|
||||
}`}
|
||||
>
|
||||
<PlayIcon
|
||||
className="h-4 w-4"
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
runTarget();
|
||||
}}
|
||||
/>
|
||||
</span>
|
||||
)}
|
||||
</span>
|
||||
</p>
|
||||
{targetConfiguration.cache && (
|
||||
<span className="rounded-full inline-block text-xs bg-sky-500 px-2 text-slate-50 ml-auto mr-6">
|
||||
<span className="rounded-full inline-block text-xs bg-sky-500 px-2 text-slate-50">
|
||||
Cacheable
|
||||
</span>
|
||||
)}
|
||||
</h3>
|
||||
<div className="absolute top-2 right-3" onClick={toggleCollapsed}>
|
||||
{collapsed ? (
|
||||
<ChevronUpIcon className="h-3 w-3" />
|
||||
) : (
|
||||
<ChevronDownIcon className="h-3 w-3" />
|
||||
<span className="flex items-center ml-auto">
|
||||
<EyeIcon
|
||||
className="h-4 w-4 mr-2 hidden group-hover:inline-block"
|
||||
title="View in Task Graph"
|
||||
onClick={viewInTaskGraph}
|
||||
></EyeIcon>
|
||||
{environment === 'nx-console' && (
|
||||
<PlayIcon className="h-5 w-5" onClick={runTarget} />
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
{collapsed ? (
|
||||
<ChevronDownIcon className="h-3 w-3" />
|
||||
) : (
|
||||
<ChevronUpIcon className="h-3 w-3" />
|
||||
)}
|
||||
</span>
|
||||
</header>
|
||||
{/* body */}
|
||||
{!collapsed && (
|
||||
<div className="pl-5 text-base pb-6 pt-2 ">
|
||||
<div className="p-4 text-base">
|
||||
{targetConfiguration.inputs && (
|
||||
<>
|
||||
<h4 className="font-bold">Inputs</h4>
|
||||
<ul className="list-disc pl-5">
|
||||
<ul className="list-disc pl-5 mb-4">
|
||||
{targetConfiguration.inputs.map((input) => (
|
||||
<li> {input.toString()} </li>
|
||||
))}
|
||||
@ -194,8 +171,8 @@ export function Target({
|
||||
)}
|
||||
{targetConfiguration.outputs && (
|
||||
<>
|
||||
<h4 className="font-bold pt-2">Outputs</h4>
|
||||
<ul className="list-disc pl-5">
|
||||
<h4 className="font-bold">Outputs</h4>
|
||||
<ul className="list-disc pl-5 mb-4">
|
||||
{targetConfiguration.outputs?.map((output) => (
|
||||
<li> {output.toString()} </li>
|
||||
)) ?? <span>no outputs</span>}
|
||||
@ -204,8 +181,8 @@ export function Target({
|
||||
)}
|
||||
{targetConfiguration.dependsOn && (
|
||||
<>
|
||||
<h4 className="font-bold py-2">Depends On</h4>
|
||||
<ul className="list-disc pl-5">
|
||||
<h4 className="font-bold">Depends On</h4>
|
||||
<ul className="list-disc pl-5 mb-4">
|
||||
{targetConfiguration.dependsOn.map((dep) => (
|
||||
<li> {dep.toString()} </li>
|
||||
))}
|
||||
@ -214,7 +191,8 @@ export function Target({
|
||||
)}
|
||||
{shouldRenderOptions ? (
|
||||
<>
|
||||
<h4 className="font-bold py-2">Options</h4>
|
||||
<h4 className="font-bold mb-2">Options</h4>
|
||||
<div className="mb-4">
|
||||
<FadingCollapsible>
|
||||
<Fence
|
||||
language="json"
|
||||
@ -228,6 +206,7 @@ export function Target({
|
||||
{JSON.stringify(targetConfiguration.options, null, 2)}
|
||||
</Fence>
|
||||
</FadingCollapsible>
|
||||
</div>
|
||||
</>
|
||||
) : (
|
||||
''
|
||||
|
||||
12
graph/ui-theme/.babelrc
Normal file
12
graph/ui-theme/.babelrc
Normal file
@ -0,0 +1,12 @@
|
||||
{
|
||||
"presets": [
|
||||
[
|
||||
"@nx/react/babel",
|
||||
{
|
||||
"runtime": "automatic",
|
||||
"useBuiltIns": "usage"
|
||||
}
|
||||
]
|
||||
],
|
||||
"plugins": []
|
||||
}
|
||||
18
graph/ui-theme/.eslintrc.json
Normal file
18
graph/ui-theme/.eslintrc.json
Normal file
@ -0,0 +1,18 @@
|
||||
{
|
||||
"extends": ["plugin:@nx/react", "../../.eslintrc.json"],
|
||||
"ignorePatterns": ["!**/*"],
|
||||
"overrides": [
|
||||
{
|
||||
"files": ["*.ts", "*.tsx", "*.js", "*.jsx"],
|
||||
"rules": {}
|
||||
},
|
||||
{
|
||||
"files": ["*.ts", "*.tsx"],
|
||||
"rules": {}
|
||||
},
|
||||
{
|
||||
"files": ["*.js", "*.jsx"],
|
||||
"rules": {}
|
||||
}
|
||||
]
|
||||
}
|
||||
19
graph/ui-theme/.storybook/main.ts
Normal file
19
graph/ui-theme/.storybook/main.ts
Normal file
@ -0,0 +1,19 @@
|
||||
import type { StorybookConfig } from '@storybook/react-webpack5';
|
||||
|
||||
const config: StorybookConfig = {
|
||||
stories: ['../src/lib/**/*.stories.@(mdx|js|jsx|ts|tsx)'],
|
||||
addons: ['@storybook/addon-essentials', '@nx/react/plugins/storybook'],
|
||||
framework: {
|
||||
name: '@storybook/react-webpack5',
|
||||
options: {},
|
||||
},
|
||||
docs: {
|
||||
autodocs: true,
|
||||
},
|
||||
};
|
||||
|
||||
export default config;
|
||||
|
||||
// To customize your Vite configuration you can use the viteFinal field.
|
||||
// Check https://storybook.js.org/docs/react/builders/vite#configuration
|
||||
// and https://nx.dev/recipes/storybook/custom-builder-configs
|
||||
1
graph/ui-theme/.storybook/preview.ts
Normal file
1
graph/ui-theme/.storybook/preview.ts
Normal file
@ -0,0 +1 @@
|
||||
import './tailwind-imports.css';
|
||||
3
graph/ui-theme/.storybook/tailwind-imports.css
Normal file
3
graph/ui-theme/.storybook/tailwind-imports.css
Normal file
@ -0,0 +1,3 @@
|
||||
@tailwind base;
|
||||
@tailwind components;
|
||||
@tailwind utilities;
|
||||
7
graph/ui-theme/README.md
Normal file
7
graph/ui-theme/README.md
Normal file
@ -0,0 +1,7 @@
|
||||
# ui-theme
|
||||
|
||||
This library was generated with [Nx](https://nx.dev).
|
||||
|
||||
## Running unit tests
|
||||
|
||||
Run `nx test ui-theme` to execute the unit tests via [Jest](https://jestjs.io).
|
||||
8
graph/ui-theme/postcss.config.js
Normal file
8
graph/ui-theme/postcss.config.js
Normal file
@ -0,0 +1,8 @@
|
||||
module.exports = {
|
||||
plugins: {
|
||||
tailwindcss: {
|
||||
config: './graph/ui-theme/tailwind.config.js',
|
||||
},
|
||||
autoprefixer: {},
|
||||
},
|
||||
};
|
||||
37
graph/ui-theme/project.json
Normal file
37
graph/ui-theme/project.json
Normal file
@ -0,0 +1,37 @@
|
||||
{
|
||||
"name": "ui-theme",
|
||||
"$schema": "../../node_modules/nx/schemas/project-schema.json",
|
||||
"sourceRoot": "graph/ui-theme/src",
|
||||
"projectType": "library",
|
||||
"tags": [],
|
||||
"targets": {
|
||||
"lint": {
|
||||
"executor": "@nx/eslint:lint"
|
||||
},
|
||||
"storybook": {
|
||||
"executor": "@nx/storybook:storybook",
|
||||
"options": {
|
||||
"port": 4400,
|
||||
"configDir": "graph/ui-theme/.storybook"
|
||||
},
|
||||
"configurations": {
|
||||
"ci": {
|
||||
"quiet": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"build-storybook": {
|
||||
"executor": "@nx/storybook:build",
|
||||
"outputs": ["{options.outputDir}"],
|
||||
"options": {
|
||||
"outputDir": "dist/storybook/ui-theme",
|
||||
"configDir": "graph/ui-theme/.storybook"
|
||||
},
|
||||
"configurations": {
|
||||
"ci": {
|
||||
"quiet": true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
2
graph/ui-theme/src/index.ts
Normal file
2
graph/ui-theme/src/index.ts
Normal file
@ -0,0 +1,2 @@
|
||||
export * from './lib/theme-panel';
|
||||
export * from './lib/theme-resolver';
|
||||
@ -3,7 +3,16 @@ import { ThemePanel } from './theme-panel';
|
||||
|
||||
const meta: Meta<typeof ThemePanel> = {
|
||||
component: ThemePanel,
|
||||
title: 'Project Graph/ThemePanel',
|
||||
decorators: [
|
||||
(Story) => (
|
||||
<div className="bg-white dark:bg-slate-800 block h-auto w-auto border-2 px-8 py-4">
|
||||
<div className="flex justify-end">
|
||||
<Story className="justify-items-end" />
|
||||
</div>
|
||||
</div>
|
||||
),
|
||||
],
|
||||
title: 'ThemePanel',
|
||||
};
|
||||
|
||||
export default meta;
|
||||
@ -6,19 +6,23 @@ import {
|
||||
} from '@heroicons/react/24/outline';
|
||||
import classNames from 'classnames';
|
||||
import { Fragment, useEffect, useState } from 'react';
|
||||
import {
|
||||
localStorageThemeKey,
|
||||
Theme,
|
||||
themeResolver,
|
||||
} from '../../theme-resolver';
|
||||
import { localStorageThemeKey, Theme, themeResolver } from './theme-resolver';
|
||||
|
||||
export function ThemePanel(): JSX.Element {
|
||||
export function ThemePanel({
|
||||
onThemeChange,
|
||||
}: {
|
||||
onThemeChange?: (theme: Theme) => void;
|
||||
}): JSX.Element {
|
||||
const [theme, setTheme] = useState(
|
||||
(localStorage.getItem(localStorageThemeKey) as Theme) || 'system'
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
themeResolver(theme);
|
||||
|
||||
if (onThemeChange) {
|
||||
onThemeChange(theme);
|
||||
}
|
||||
}, [theme]);
|
||||
|
||||
return (
|
||||
@ -1,5 +1,3 @@
|
||||
import { getGraphService } from './machines/graph.service';
|
||||
|
||||
const htmlEl = document.documentElement;
|
||||
export const localStorageThemeKey = 'nx-dep-graph-theme';
|
||||
export type Theme = 'light' | 'dark' | 'system';
|
||||
@ -27,6 +25,11 @@ export function themeInit() {
|
||||
themeResolver(theme);
|
||||
}
|
||||
|
||||
export function getSystemTheme() {
|
||||
const darkMedia = window.matchMedia('(prefers-color-scheme: dark)');
|
||||
return darkMedia.matches ? 'dark' : 'light';
|
||||
}
|
||||
|
||||
export function themeResolver(theme: Theme) {
|
||||
if (!('matchMedia' in window)) {
|
||||
return;
|
||||
@ -46,8 +49,6 @@ export function themeResolver(theme: Theme) {
|
||||
}
|
||||
|
||||
localStorage.setItem(localStorageThemeKey, theme);
|
||||
|
||||
getGraphService().theme = currentTheme;
|
||||
}
|
||||
|
||||
export function selectValueByThemeDynamic<T>(
|
||||
45
graph/ui-theme/tailwind.config.js
Normal file
45
graph/ui-theme/tailwind.config.js
Normal file
@ -0,0 +1,45 @@
|
||||
const path = require('path');
|
||||
|
||||
// nx-ignore-next-line
|
||||
const { createGlobPatternsForDependencies } = require('@nx/react/tailwind');
|
||||
|
||||
module.exports = {
|
||||
content: [
|
||||
path.join(__dirname, 'src/**/*.{js,ts,jsx,tsx,html}'),
|
||||
...createGlobPatternsForDependencies(__dirname),
|
||||
],
|
||||
darkMode: 'class', // or 'media' or 'class'
|
||||
theme: {
|
||||
extend: {
|
||||
typography: {
|
||||
DEFAULT: {
|
||||
css: {
|
||||
'code::before': {
|
||||
content: '',
|
||||
},
|
||||
'code::after': {
|
||||
content: '',
|
||||
},
|
||||
'blockquote p:first-of-type::before': {
|
||||
content: '',
|
||||
},
|
||||
'blockquote p:last-of-type::after': {
|
||||
content: '',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
variants: {
|
||||
extend: {
|
||||
translate: ['group-hover'],
|
||||
},
|
||||
},
|
||||
plugins: [
|
||||
require('@tailwindcss/typography'),
|
||||
require('@tailwindcss/forms')({
|
||||
strategy: 'class',
|
||||
}),
|
||||
],
|
||||
};
|
||||
24
graph/ui-theme/tsconfig.json
Normal file
24
graph/ui-theme/tsconfig.json
Normal file
@ -0,0 +1,24 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"jsx": "react-jsx",
|
||||
"allowJs": false,
|
||||
"esModuleInterop": false,
|
||||
"allowSyntheticDefaultImports": true,
|
||||
"strict": true,
|
||||
"lib": ["DOM", "es2022"]
|
||||
},
|
||||
"files": [],
|
||||
"include": [],
|
||||
"references": [
|
||||
{
|
||||
"path": "./tsconfig.lib.json"
|
||||
},
|
||||
{
|
||||
"path": "./tsconfig.spec.json"
|
||||
},
|
||||
{
|
||||
"path": "./tsconfig.storybook.json"
|
||||
}
|
||||
],
|
||||
"extends": "../../tsconfig.base.json"
|
||||
}
|
||||
27
graph/ui-theme/tsconfig.lib.json
Normal file
27
graph/ui-theme/tsconfig.lib.json
Normal file
@ -0,0 +1,27 @@
|
||||
{
|
||||
"extends": "./tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"outDir": "../../dist/out-tsc",
|
||||
"types": [
|
||||
"node",
|
||||
"@nx/react/typings/cssmodule.d.ts",
|
||||
"@nx/react/typings/image.d.ts"
|
||||
]
|
||||
},
|
||||
"exclude": [
|
||||
"jest.config.ts",
|
||||
"src/**/*.spec.ts",
|
||||
"src/**/*.test.ts",
|
||||
"src/**/*.spec.tsx",
|
||||
"src/**/*.test.tsx",
|
||||
"src/**/*.spec.js",
|
||||
"src/**/*.test.js",
|
||||
"src/**/*.spec.jsx",
|
||||
"src/**/*.test.jsx",
|
||||
"**/*.stories.ts",
|
||||
"**/*.stories.js",
|
||||
"**/*.stories.jsx",
|
||||
"**/*.stories.tsx"
|
||||
],
|
||||
"include": ["src/**/*.js", "src/**/*.jsx", "src/**/*.ts", "src/**/*.tsx"]
|
||||
}
|
||||
31
graph/ui-theme/tsconfig.storybook.json
Normal file
31
graph/ui-theme/tsconfig.storybook.json
Normal file
@ -0,0 +1,31 @@
|
||||
{
|
||||
"extends": "./tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"emitDecoratorMetadata": true,
|
||||
"outDir": ""
|
||||
},
|
||||
"files": [
|
||||
"../../node_modules/@nx/react/typings/styled-jsx.d.ts",
|
||||
"../../node_modules/@nx/react/typings/cssmodule.d.ts",
|
||||
"../../node_modules/@nx/react/typings/image.d.ts"
|
||||
],
|
||||
"exclude": [
|
||||
"src/**/*.spec.ts",
|
||||
"src/**/*.test.ts",
|
||||
"src/**/*.spec.js",
|
||||
"src/**/*.test.js",
|
||||
"src/**/*.spec.tsx",
|
||||
"src/**/*.test.tsx",
|
||||
"src/**/*.spec.jsx",
|
||||
"src/**/*.test.js"
|
||||
],
|
||||
"include": [
|
||||
"src/**/*.stories.ts",
|
||||
"src/**/*.stories.js",
|
||||
"src/**/*.stories.jsx",
|
||||
"src/**/*.stories.tsx",
|
||||
"src/**/*.stories.mdx",
|
||||
".storybook/*.js",
|
||||
".storybook/*.ts"
|
||||
]
|
||||
}
|
||||
@ -4,7 +4,8 @@
|
||||
"allowJs": false,
|
||||
"esModuleInterop": false,
|
||||
"allowSyntheticDefaultImports": true,
|
||||
"strict": true
|
||||
"strict": true,
|
||||
"lib": ["DOM", "es2022"]
|
||||
},
|
||||
"files": [],
|
||||
"include": [],
|
||||
|
||||
@ -39,6 +39,7 @@
|
||||
"@nx/graph/shared": ["graph/shared/src/index.ts"],
|
||||
"@nx/graph/ui-components": ["graph/ui-components/src/index.ts"],
|
||||
"@nx/graph/ui-graph": ["graph/ui-graph/src/index.ts"],
|
||||
"@nx/graph/ui-theme": ["graph/ui-theme/src/index.ts"],
|
||||
"@nx/graph/ui-tooltips": ["graph/ui-tooltips/src/index.ts"],
|
||||
"@nx/jest": ["packages/jest"],
|
||||
"@nx/jest/*": ["packages/jest/*"],
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user