wip
9
.editorconfig
Normal file
@ -0,0 +1,9 @@
|
||||
root = true
|
||||
|
||||
[*]
|
||||
indent_style = tab
|
||||
indent_size = 2
|
||||
end_of_line = lf
|
||||
charset = utf-8
|
||||
trim_trailing_whitespace = true
|
||||
insert_final_newline = true
|
@ -1,3 +1,3 @@
|
||||
{
|
||||
"extends": "next/core-web-vitals"
|
||||
"extends": "next/core-web-vitals"
|
||||
}
|
||||
|
1
.prettierignore
Normal file
@ -0,0 +1 @@
|
||||
src-tauri
|
11
.prettierrc.json
Normal file
@ -0,0 +1,11 @@
|
||||
{
|
||||
"printWidth": 120,
|
||||
"tabWidth": 2,
|
||||
"useTabs": true,
|
||||
"semi": true,
|
||||
"singleQuote": true,
|
||||
"trailingComma": "all",
|
||||
"bracketSpacing": true,
|
||||
"jsxBracketSameLine": false,
|
||||
"arrowParens": "avoid"
|
||||
}
|
@ -1,4 +1,6 @@
|
||||
/** @type {import('next').NextConfig} */
|
||||
const nextConfig = {}
|
||||
const nextConfig = {
|
||||
output: 'export',
|
||||
};
|
||||
|
||||
module.exports = nextConfig
|
||||
module.exports = nextConfig;
|
||||
|
61
package.json
@ -1,27 +1,38 @@
|
||||
{
|
||||
"name": "vrc-creator-companion-tauri",
|
||||
"version": "0.1.0",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"dev": "next dev",
|
||||
"build": "next build",
|
||||
"start": "next start",
|
||||
"lint": "next lint"
|
||||
},
|
||||
"dependencies": {
|
||||
"react": "^18",
|
||||
"react-dom": "^18",
|
||||
"next": "14.0.4"
|
||||
},
|
||||
"devDependencies": {
|
||||
"typescript": "^5",
|
||||
"@types/node": "^20",
|
||||
"@types/react": "^18",
|
||||
"@types/react-dom": "^18",
|
||||
"autoprefixer": "^10.0.1",
|
||||
"postcss": "^8",
|
||||
"tailwindcss": "^3.3.0",
|
||||
"eslint": "^8",
|
||||
"eslint-config-next": "14.0.4"
|
||||
}
|
||||
"name": "vrc-creator-companion-tauri",
|
||||
"version": "0.1.0",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"dev": "next dev",
|
||||
"build": "next build",
|
||||
"start": "next start",
|
||||
"lint": "next lint",
|
||||
"prettier": "prettier --write .",
|
||||
"tauri": "tauri dev"
|
||||
},
|
||||
"dependencies": {
|
||||
"@emotion/css": "^11.11.2",
|
||||
"@emotion/react": "^11.11.1",
|
||||
"@fluentui/react-components": "^9.43.2",
|
||||
"@fluentui/react-icons": "^2.0.224",
|
||||
"@fluentui/react-theme": "^9.1.16",
|
||||
"classnames": "^2.3.2",
|
||||
"eslint-config-prettier": "^9.1.0",
|
||||
"next": "14.0.4",
|
||||
"prettier": "^3.1.1",
|
||||
"react": "^18",
|
||||
"react-dom": "^18"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@tauri-apps/cli": "^1.5.8",
|
||||
"@types/node": "^20",
|
||||
"@types/react": "^18",
|
||||
"@types/react-dom": "^18",
|
||||
"autoprefixer": "^10.0.1",
|
||||
"eslint": "^8",
|
||||
"eslint-config-next": "14.0.4",
|
||||
"postcss": "^8",
|
||||
"tailwindcss": "^3.3.0",
|
||||
"typescript": "^5"
|
||||
}
|
||||
}
|
||||
|
1958
pnpm-lock.yaml
generated
@ -1,6 +1,6 @@
|
||||
module.exports = {
|
||||
plugins: {
|
||||
tailwindcss: {},
|
||||
autoprefixer: {},
|
||||
},
|
||||
}
|
||||
plugins: {
|
||||
tailwindcss: {},
|
||||
autoprefixer: {},
|
||||
},
|
||||
};
|
||||
|
3
src-tauri/.gitignore
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
# Generated by Cargo
|
||||
# will have compiled files and executables
|
||||
/target/
|
3720
src-tauri/Cargo.lock
generated
Normal file
26
src-tauri/Cargo.toml
Normal file
@ -0,0 +1,26 @@
|
||||
[package]
|
||||
name = "app"
|
||||
version = "0.1.0"
|
||||
description = "A Tauri App"
|
||||
authors = ["you"]
|
||||
license = ""
|
||||
repository = ""
|
||||
default-run = "app"
|
||||
edition = "2021"
|
||||
rust-version = "1.60"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[build-dependencies]
|
||||
tauri-build = { version = "1.5.0", features = [] }
|
||||
|
||||
[dependencies]
|
||||
serde_json = "1.0"
|
||||
serde = { version = "1.0", features = ["derive"] }
|
||||
tauri = { version = "1.5.3", features = [] }
|
||||
|
||||
[features]
|
||||
# this feature is used for production builds or when `devPath` points to the filesystem and the built-in dev server is disabled.
|
||||
# If you use cargo directly instead of tauri's cli you can use this feature flag to switch between tauri's `dev` and `build` modes.
|
||||
# DO NOT REMOVE!!
|
||||
custom-protocol = [ "tauri/custom-protocol" ]
|
3
src-tauri/build.rs
Normal file
@ -0,0 +1,3 @@
|
||||
fn main() {
|
||||
tauri_build::build()
|
||||
}
|
BIN
src-tauri/icons/128x128.png
Normal file
After Width: | Height: | Size: 11 KiB |
BIN
src-tauri/icons/128x128@2x.png
Normal file
After Width: | Height: | Size: 23 KiB |
BIN
src-tauri/icons/32x32.png
Normal file
After Width: | Height: | Size: 2.2 KiB |
BIN
src-tauri/icons/Square107x107Logo.png
Normal file
After Width: | Height: | Size: 9.0 KiB |
BIN
src-tauri/icons/Square142x142Logo.png
Normal file
After Width: | Height: | Size: 12 KiB |
BIN
src-tauri/icons/Square150x150Logo.png
Normal file
After Width: | Height: | Size: 13 KiB |
BIN
src-tauri/icons/Square284x284Logo.png
Normal file
After Width: | Height: | Size: 25 KiB |
BIN
src-tauri/icons/Square30x30Logo.png
Normal file
After Width: | Height: | Size: 2.0 KiB |
BIN
src-tauri/icons/Square310x310Logo.png
Normal file
After Width: | Height: | Size: 28 KiB |
BIN
src-tauri/icons/Square44x44Logo.png
Normal file
After Width: | Height: | Size: 3.3 KiB |
BIN
src-tauri/icons/Square71x71Logo.png
Normal file
After Width: | Height: | Size: 5.9 KiB |
BIN
src-tauri/icons/Square89x89Logo.png
Normal file
After Width: | Height: | Size: 7.4 KiB |
BIN
src-tauri/icons/StoreLogo.png
Normal file
After Width: | Height: | Size: 3.9 KiB |
BIN
src-tauri/icons/icon.icns
Normal file
BIN
src-tauri/icons/icon.ico
Normal file
After Width: | Height: | Size: 37 KiB |
BIN
src-tauri/icons/icon.png
Normal file
After Width: | Height: | Size: 49 KiB |
8
src-tauri/src/main.rs
Normal file
@ -0,0 +1,8 @@
|
||||
// Prevents additional console window on Windows in release, DO NOT REMOVE!!
|
||||
#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")]
|
||||
|
||||
fn main() {
|
||||
tauri::Builder::default()
|
||||
.run(tauri::generate_context!())
|
||||
.expect("error while running tauri application");
|
||||
}
|
66
src-tauri/tauri.conf.json
Normal file
@ -0,0 +1,66 @@
|
||||
{
|
||||
"$schema": "../node_modules/@tauri-apps/cli/schema.json",
|
||||
"build": {
|
||||
"beforeBuildCommand": "npm run build",
|
||||
"beforeDevCommand": "npm run dev",
|
||||
"devPath": "http://localhost:3000",
|
||||
"distDir": "../out"
|
||||
},
|
||||
"package": {
|
||||
"productName": "vrc-creator-companion-tauri",
|
||||
"version": "0.1.0"
|
||||
},
|
||||
"tauri": {
|
||||
"allowlist": {
|
||||
"all": false
|
||||
},
|
||||
"bundle": {
|
||||
"active": true,
|
||||
"category": "DeveloperTool",
|
||||
"copyright": "",
|
||||
"deb": {
|
||||
"depends": []
|
||||
},
|
||||
"externalBin": [],
|
||||
"icon": [
|
||||
"icons/32x32.png",
|
||||
"icons/128x128.png",
|
||||
"icons/128x128@2x.png",
|
||||
"icons/icon.icns",
|
||||
"icons/icon.ico"
|
||||
],
|
||||
"identifier": "com.tauri.dev",
|
||||
"longDescription": "",
|
||||
"macOS": {
|
||||
"entitlements": null,
|
||||
"exceptionDomain": "",
|
||||
"frameworks": [],
|
||||
"providerShortName": null,
|
||||
"signingIdentity": null
|
||||
},
|
||||
"resources": [],
|
||||
"shortDescription": "",
|
||||
"targets": "all",
|
||||
"windows": {
|
||||
"certificateThumbprint": null,
|
||||
"digestAlgorithm": "sha256",
|
||||
"timestampUrl": ""
|
||||
}
|
||||
},
|
||||
"security": {
|
||||
"csp": null
|
||||
},
|
||||
"updater": {
|
||||
"active": false
|
||||
},
|
||||
"windows": [
|
||||
{
|
||||
"fullscreen": false,
|
||||
"height": 600,
|
||||
"resizable": true,
|
||||
"title": "vrc-creator-companion-tauri",
|
||||
"width": 800
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
63
src/app/components/sidebar.tsx
Normal file
@ -0,0 +1,63 @@
|
||||
'use client';
|
||||
|
||||
import { Button } from '@fluentui/react-components';
|
||||
import { SettingsRegular, ArrowCircleUpRegular, BookQuestionMarkRegular, ToolboxRegular, DocumentBulletListRegular, AppFolderRegular, AppFolderFilled } from '@fluentui/react-icons';
|
||||
|
||||
import { makeStyles } from '@fluentui/react-components';
|
||||
import { tokens } from '@fluentui/react-theme';
|
||||
|
||||
const useStyles = makeStyles({
|
||||
root: {
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
justifyContent: 'space-between',
|
||||
height: '100vh',
|
||||
paddingLeft: '6px',
|
||||
paddingRight: '6px',
|
||||
paddingTop: '6px',
|
||||
paddingBottom: '6px',
|
||||
width: '150px',
|
||||
backgroundColor: tokens.colorNeutralBackground3
|
||||
},
|
||||
wrapper: {
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
rowGap: '12px',
|
||||
},
|
||||
button: {
|
||||
justifyContent: 'flex-start',
|
||||
},
|
||||
});
|
||||
|
||||
export default function Sidebar() {
|
||||
const classes = useStyles();
|
||||
|
||||
return (
|
||||
<div>
|
||||
<div className={classes.root}>
|
||||
<div className={classes.wrapper}>
|
||||
<Button className={classes.button} icon={<AppFolderFilled />} size="large" appearance="outline">
|
||||
Projects
|
||||
</Button>
|
||||
<Button className={classes.button} icon={<BookQuestionMarkRegular />} size="large" appearance="subtle">
|
||||
Learn
|
||||
</Button>
|
||||
<Button className={classes.button} icon={<ToolboxRegular />} size="large" appearance="subtle">
|
||||
Tools
|
||||
</Button>
|
||||
</div>
|
||||
<div className={classes.wrapper}>
|
||||
<Button className={classes.button} icon={<ArrowCircleUpRegular />} size="large" appearance="primary">
|
||||
Update
|
||||
</Button>
|
||||
<Button className={classes.button} icon={<DocumentBulletListRegular />} size="large" appearance="subtle">
|
||||
Logs
|
||||
</Button>
|
||||
<Button className={classes.button} icon={<SettingsRegular />} size="large" appearance="subtle">
|
||||
Settings
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
@ -2,26 +2,21 @@
|
||||
@tailwind components;
|
||||
@tailwind utilities;
|
||||
|
||||
:root {
|
||||
--foreground-rgb: 0, 0, 0;
|
||||
--background-start-rgb: 214, 219, 220;
|
||||
--background-end-rgb: 255, 255, 255;
|
||||
/* :root {
|
||||
--foreground-rgb: 0, 0, 0;
|
||||
--background-start-rgb: 214, 219, 220;
|
||||
--background-end-rgb: 255, 255, 255;
|
||||
}
|
||||
|
||||
@media (prefers-color-scheme: dark) {
|
||||
:root {
|
||||
--foreground-rgb: 255, 255, 255;
|
||||
--background-start-rgb: 0, 0, 0;
|
||||
--background-end-rgb: 0, 0, 0;
|
||||
}
|
||||
:root {
|
||||
--foreground-rgb: 255, 255, 255;
|
||||
--background-start-rgb: 0, 0, 0;
|
||||
--background-end-rgb: 0, 0, 0;
|
||||
}
|
||||
}
|
||||
|
||||
body {
|
||||
color: rgb(var(--foreground-rgb));
|
||||
background: linear-gradient(
|
||||
to bottom,
|
||||
transparent,
|
||||
rgb(var(--background-end-rgb))
|
||||
)
|
||||
rgb(var(--background-start-rgb));
|
||||
}
|
||||
color: rgb(var(--foreground-rgb));
|
||||
background: linear-gradient(to bottom, transparent, rgb(var(--background-end-rgb))) rgb(var(--background-start-rgb));
|
||||
} */
|
||||
|
@ -1,22 +1,30 @@
|
||||
import type { Metadata } from 'next'
|
||||
import { Inter } from 'next/font/google'
|
||||
import './globals.css'
|
||||
import type { Metadata } from 'next';
|
||||
import { Inter } from 'next/font/google';
|
||||
import './globals.css';
|
||||
import classnames from 'classnames';
|
||||
import { FluentProvider, makeStyles, teamsDarkTheme, teamsLightTheme } from '@fluentui/react-components';
|
||||
import Sidebar from './components/sidebar';
|
||||
|
||||
const inter = Inter({ subsets: ['latin'] })
|
||||
import { Providers } from './providers';
|
||||
|
||||
const inter = Inter({ subsets: ['latin'] });
|
||||
|
||||
export const metadata: Metadata = {
|
||||
title: 'Create Next App',
|
||||
description: 'Generated by create next app',
|
||||
}
|
||||
title: 'Create Next App',
|
||||
description: 'Generated by create next app',
|
||||
};
|
||||
|
||||
export default function RootLayout({
|
||||
children,
|
||||
}: {
|
||||
children: React.ReactNode
|
||||
}) {
|
||||
return (
|
||||
<html lang="en">
|
||||
<body className={inter.className}>{children}</body>
|
||||
</html>
|
||||
)
|
||||
export default function RootLayout({ children }: { children: React.ReactNode }) {
|
||||
return (
|
||||
<html lang="en">
|
||||
<body className={classnames(inter.className)}>
|
||||
<Providers>
|
||||
<aside className="w-[150px]">
|
||||
<Sidebar />
|
||||
</aside>
|
||||
{children}
|
||||
</Providers>
|
||||
</body>
|
||||
</html>
|
||||
);
|
||||
}
|
||||
|
440
src/app/page.tsx
@ -1,113 +1,335 @@
|
||||
import Image from 'next/image'
|
||||
'use client';
|
||||
|
||||
import {
|
||||
Button,
|
||||
Title1,
|
||||
makeStyles,
|
||||
tokens,
|
||||
Tooltip,
|
||||
Input,
|
||||
SplitButton,
|
||||
Body1Stronger,
|
||||
Caption1,
|
||||
shorthands,
|
||||
Menu,
|
||||
MenuItem,
|
||||
MenuList,
|
||||
MenuPopover,
|
||||
MenuTrigger,
|
||||
Body1,
|
||||
} from '@fluentui/react-components';
|
||||
import {
|
||||
ArrowSyncRegular,
|
||||
SearchRegular,
|
||||
AppsListFilled,
|
||||
StarFilled,
|
||||
EarthRegular,
|
||||
EarthLeafRegular,
|
||||
GlobeRegular,
|
||||
MoreHorizontalFilled,
|
||||
ArrowCircleUpRegular,
|
||||
Globe24Regular,
|
||||
ArrowSync24Regular,
|
||||
Search24Regular,
|
||||
PersonCircle24Regular,
|
||||
QuestionCircle24Regular,
|
||||
Star24Filled,
|
||||
Star16Filled,
|
||||
} from '@fluentui/react-icons';
|
||||
|
||||
import Image from 'next/image';
|
||||
|
||||
import {
|
||||
FolderRegular,
|
||||
EditRegular,
|
||||
OpenRegular,
|
||||
DocumentRegular,
|
||||
PeopleRegular,
|
||||
DocumentPdfRegular,
|
||||
VideoRegular,
|
||||
} from '@fluentui/react-icons';
|
||||
import {
|
||||
PresenceBadgeStatus,
|
||||
Avatar,
|
||||
DataGridBody,
|
||||
DataGridRow,
|
||||
DataGrid,
|
||||
DataGridHeader,
|
||||
DataGridHeaderCell,
|
||||
DataGridCell,
|
||||
TableCellLayout,
|
||||
TableColumnDefinition,
|
||||
createTableColumn,
|
||||
} from '@fluentui/react-components';
|
||||
import { ArrowCircleUpFilled } from '@fluentui/react-icons/lib/fonts';
|
||||
|
||||
type FileCell = {
|
||||
label: string;
|
||||
path: string;
|
||||
};
|
||||
|
||||
type LastUpdatedCell = {
|
||||
label: string;
|
||||
timestamp: number;
|
||||
};
|
||||
|
||||
enum ProjectType {
|
||||
World = 'World',
|
||||
Avatar = 'Avatar',
|
||||
Unknown = 'Unknown',
|
||||
}
|
||||
|
||||
type Item = {
|
||||
stared: boolean;
|
||||
file: FileCell;
|
||||
projectType: ProjectType;
|
||||
unity: string;
|
||||
lastUpdated: LastUpdatedCell;
|
||||
};
|
||||
|
||||
const items: Item[] = [
|
||||
{
|
||||
stared: false,
|
||||
file: { label: 'My home', path: 'G:\\Unity\\My home' },
|
||||
projectType: ProjectType.World,
|
||||
unity: '2020.3.14f1',
|
||||
lastUpdated: { label: '7h ago', timestamp: 1 },
|
||||
},
|
||||
{
|
||||
stared: false,
|
||||
file: { label: 'Mint-Usually', path: 'G:\\Unity\\Mint-Usually' },
|
||||
projectType: ProjectType.Avatar,
|
||||
unity: '2020.3.14f1',
|
||||
lastUpdated: { label: 'Yesterday at 1:45 PM', timestamp: 2 },
|
||||
},
|
||||
];
|
||||
|
||||
const columns: TableColumnDefinition<Item>[] = [
|
||||
createTableColumn<Item>({
|
||||
columnId: 'star',
|
||||
compare: (a, b) => {
|
||||
return a.stared === b.stared ? 0 : a.stared ? -1 : 1;
|
||||
},
|
||||
renderHeaderCell: () => {
|
||||
return <Star16Filled />;
|
||||
},
|
||||
renderCell: item => {
|
||||
return (
|
||||
<TableCellLayout truncate>
|
||||
<Button icon={<Star24Filled />} appearance="transparent" />
|
||||
</TableCellLayout>
|
||||
);
|
||||
},
|
||||
}),
|
||||
createTableColumn<Item>({
|
||||
columnId: 'projectName',
|
||||
compare: (a, b) => {
|
||||
return a.file.label.localeCompare(b.file.label);
|
||||
},
|
||||
renderHeaderCell: () => {
|
||||
return <Body1Stronger>Project Name</Body1Stronger>;
|
||||
},
|
||||
renderCell: item => {
|
||||
return (
|
||||
<TableCellLayout truncate>
|
||||
<div className="flex flex-col">
|
||||
<Body1Stronger>{item.file.label}</Body1Stronger>
|
||||
<Caption1>{item.file.path}</Caption1>
|
||||
</div>
|
||||
</TableCellLayout>
|
||||
);
|
||||
},
|
||||
}),
|
||||
createTableColumn<Item>({
|
||||
columnId: 'projectType',
|
||||
renderHeaderCell: () => {
|
||||
return <Body1Stronger>Project Type</Body1Stronger>;
|
||||
},
|
||||
renderCell: item => {
|
||||
return (
|
||||
// eslint-disable-next-line react/jsx-no-undef
|
||||
<TableCellLayout
|
||||
truncate
|
||||
media={
|
||||
item.projectType === ProjectType.World ? (
|
||||
<Globe24Regular />
|
||||
) : item.projectType === ProjectType.Avatar ? (
|
||||
<PersonCircle24Regular />
|
||||
) : (
|
||||
<QuestionCircle24Regular />
|
||||
)
|
||||
}
|
||||
>
|
||||
{item.projectType}
|
||||
</TableCellLayout>
|
||||
);
|
||||
},
|
||||
}),
|
||||
createTableColumn<Item>({
|
||||
columnId: 'unity',
|
||||
compare: (a, b) => {
|
||||
return a.unity.localeCompare(b.unity);
|
||||
},
|
||||
renderHeaderCell: () => {
|
||||
return <Body1Stronger>Unity</Body1Stronger>;
|
||||
},
|
||||
renderCell: item => {
|
||||
return (
|
||||
<TableCellLayout truncate>
|
||||
<Tooltip content="Unity Version Upgrade Available" relationship="description">
|
||||
<Button
|
||||
appearance="outline"
|
||||
icon={<ArrowCircleUpRegular color={tokens.colorPaletteGreenForeground1} />}
|
||||
color={tokens.colorPaletteGreenForeground1}
|
||||
style={{
|
||||
borderColor: tokens.colorPaletteGreenForeground1,
|
||||
}}
|
||||
>
|
||||
<Body1Stronger>{item.unity}</Body1Stronger>
|
||||
</Button>
|
||||
</Tooltip>
|
||||
</TableCellLayout>
|
||||
);
|
||||
},
|
||||
}),
|
||||
createTableColumn<Item>({
|
||||
columnId: 'lastModified',
|
||||
compare: (a, b) => {
|
||||
return a.lastUpdated.timestamp - b.lastUpdated.timestamp;
|
||||
},
|
||||
renderHeaderCell: () => {
|
||||
return <Body1Stronger truncate>Last Modified</Body1Stronger>;
|
||||
},
|
||||
|
||||
renderCell: item => {
|
||||
return item.lastUpdated.label;
|
||||
},
|
||||
}),
|
||||
createTableColumn<Item>({
|
||||
columnId: 'buttons',
|
||||
renderHeaderCell: () => {
|
||||
return '';
|
||||
},
|
||||
renderCell: item => {
|
||||
return (
|
||||
<TableCellLayout className="flex">
|
||||
<Button appearance="primary">Open Project</Button>
|
||||
<Button appearance="outline">Manage Project</Button>
|
||||
<Menu>
|
||||
<MenuTrigger disableButtonEnhancement>
|
||||
<Button icon={<MoreHorizontalFilled />} appearance="subtle" />
|
||||
</MenuTrigger>
|
||||
|
||||
<MenuPopover>
|
||||
<MenuList>
|
||||
<MenuItem>Open Project Folder</MenuItem>
|
||||
<MenuItem>Create Backup</MenuItem>
|
||||
<MenuItem>Remove Project</MenuItem>
|
||||
</MenuList>
|
||||
</MenuPopover>
|
||||
</Menu>
|
||||
</TableCellLayout>
|
||||
);
|
||||
},
|
||||
}),
|
||||
];
|
||||
|
||||
const useStyles = makeStyles({
|
||||
root: {
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
justifyContent: 'center',
|
||||
paddingLeft: '1rem',
|
||||
paddingRight: '1rem',
|
||||
paddingTop: '0.5rem',
|
||||
paddingBottom: '1rem',
|
||||
backgroundColor: tokens.colorNeutralBackground2,
|
||||
width: '100%',
|
||||
},
|
||||
header: {
|
||||
display: 'flex',
|
||||
flexDirection: 'row',
|
||||
justifyContent: 'space-between',
|
||||
width: '100%',
|
||||
alignItems: 'flex-end',
|
||||
},
|
||||
title: {
|
||||
display: 'flex',
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
columnGap: '0.5rem',
|
||||
},
|
||||
search: {
|
||||
display: 'grid',
|
||||
gridTemplateColumns: '1fr repeat(2, auto)',
|
||||
columnGap: '0.5rem',
|
||||
width: '100%',
|
||||
},
|
||||
table: {
|
||||
marginTop: '1rem',
|
||||
height: '100%',
|
||||
backgroundColor: tokens.colorNeutralBackground1,
|
||||
...shorthands.borderRadius('4px'),
|
||||
},
|
||||
dataGrid: {
|
||||
...shorthands.borderRadius('10px'),
|
||||
},
|
||||
unityUpdateButton: {
|
||||
color: tokens.colorPaletteGreenForeground1,
|
||||
},
|
||||
gridHeader: {
|
||||
width: '50px',
|
||||
':hover': {
|
||||
backgroundColor: 'transparent',
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
export default function Home() {
|
||||
return (
|
||||
<main className="flex min-h-screen flex-col items-center justify-between p-24">
|
||||
<div className="z-10 max-w-5xl w-full items-center justify-between font-mono text-sm lg:flex">
|
||||
<p className="fixed left-0 top-0 flex w-full justify-center border-b border-gray-300 bg-gradient-to-b from-zinc-200 pb-6 pt-8 backdrop-blur-2xl dark:border-neutral-800 dark:bg-zinc-800/30 dark:from-inherit lg:static lg:w-auto lg:rounded-xl lg:border lg:bg-gray-200 lg:p-4 lg:dark:bg-zinc-800/30">
|
||||
Get started by editing
|
||||
<code className="font-mono font-bold">src/app/page.tsx</code>
|
||||
</p>
|
||||
<div className="fixed bottom-0 left-0 flex h-48 w-full items-end justify-center bg-gradient-to-t from-white via-white dark:from-black dark:via-black lg:static lg:h-auto lg:w-auto lg:bg-none">
|
||||
<a
|
||||
className="pointer-events-none flex place-items-center gap-2 p-8 lg:pointer-events-auto lg:p-0"
|
||||
href="https://vercel.com?utm_source=create-next-app&utm_medium=appdir-template&utm_campaign=create-next-app"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
By{' '}
|
||||
<Image
|
||||
src="/vercel.svg"
|
||||
alt="Vercel Logo"
|
||||
className="dark:invert"
|
||||
width={100}
|
||||
height={24}
|
||||
priority
|
||||
/>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
const classes = useStyles();
|
||||
|
||||
<div className="relative flex place-items-center before:absolute before:h-[300px] before:w-[480px] before:-translate-x-1/2 before:rounded-full before:bg-gradient-radial before:from-white before:to-transparent before:blur-2xl before:content-[''] after:absolute after:-z-20 after:h-[180px] after:w-[240px] after:translate-x-1/3 after:bg-gradient-conic after:from-sky-200 after:via-blue-200 after:blur-2xl after:content-[''] before:dark:bg-gradient-to-br before:dark:from-transparent before:dark:to-blue-700 before:dark:opacity-10 after:dark:from-sky-900 after:dark:via-[#0141ff] after:dark:opacity-40 before:lg:h-[360px] z-[-1]">
|
||||
<Image
|
||||
className="relative dark:drop-shadow-[0_0_0.3rem_#ffffff70] dark:invert"
|
||||
src="/next.svg"
|
||||
alt="Next.js Logo"
|
||||
width={180}
|
||||
height={37}
|
||||
priority
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="mb-32 grid text-center lg:max-w-5xl lg:w-full lg:mb-0 lg:grid-cols-4 lg:text-left">
|
||||
<a
|
||||
href="https://nextjs.org/docs?utm_source=create-next-app&utm_medium=appdir-template&utm_campaign=create-next-app"
|
||||
className="group rounded-lg border border-transparent px-5 py-4 transition-colors hover:border-gray-300 hover:bg-gray-100 hover:dark:border-neutral-700 hover:dark:bg-neutral-800/30"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
<h2 className={`mb-3 text-2xl font-semibold`}>
|
||||
Docs{' '}
|
||||
<span className="inline-block transition-transform group-hover:translate-x-1 motion-reduce:transform-none">
|
||||
->
|
||||
</span>
|
||||
</h2>
|
||||
<p className={`m-0 max-w-[30ch] text-sm opacity-50`}>
|
||||
Find in-depth information about Next.js features and API.
|
||||
</p>
|
||||
</a>
|
||||
|
||||
<a
|
||||
href="https://nextjs.org/learn?utm_source=create-next-app&utm_medium=appdir-template-tw&utm_campaign=create-next-app"
|
||||
className="group rounded-lg border border-transparent px-5 py-4 transition-colors hover:border-gray-300 hover:bg-gray-100 hover:dark:border-neutral-700 hover:dark:bg-neutral-800/30"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
<h2 className={`mb-3 text-2xl font-semibold`}>
|
||||
Learn{' '}
|
||||
<span className="inline-block transition-transform group-hover:translate-x-1 motion-reduce:transform-none">
|
||||
->
|
||||
</span>
|
||||
</h2>
|
||||
<p className={`m-0 max-w-[30ch] text-sm opacity-50`}>
|
||||
Learn about Next.js in an interactive course with quizzes!
|
||||
</p>
|
||||
</a>
|
||||
|
||||
<a
|
||||
href="https://vercel.com/templates?framework=next.js&utm_source=create-next-app&utm_medium=appdir-template&utm_campaign=create-next-app"
|
||||
className="group rounded-lg border border-transparent px-5 py-4 transition-colors hover:border-gray-300 hover:bg-gray-100 hover:dark:border-neutral-700 hover:dark:bg-neutral-800/30"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
<h2 className={`mb-3 text-2xl font-semibold`}>
|
||||
Templates{' '}
|
||||
<span className="inline-block transition-transform group-hover:translate-x-1 motion-reduce:transform-none">
|
||||
->
|
||||
</span>
|
||||
</h2>
|
||||
<p className={`m-0 max-w-[30ch] text-sm opacity-50`}>
|
||||
Explore starter templates for Next.js.
|
||||
</p>
|
||||
</a>
|
||||
|
||||
<a
|
||||
href="https://vercel.com/new?utm_source=create-next-app&utm_medium=appdir-template&utm_campaign=create-next-app"
|
||||
className="group rounded-lg border border-transparent px-5 py-4 transition-colors hover:border-gray-300 hover:bg-gray-100 hover:dark:border-neutral-700 hover:dark:bg-neutral-800/30"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
<h2 className={`mb-3 text-2xl font-semibold`}>
|
||||
Deploy{' '}
|
||||
<span className="inline-block transition-transform group-hover:translate-x-1 motion-reduce:transform-none">
|
||||
->
|
||||
</span>
|
||||
</h2>
|
||||
<p className={`m-0 max-w-[30ch] text-sm opacity-50`}>
|
||||
Instantly deploy your Next.js site to a shareable URL with Vercel.
|
||||
</p>
|
||||
</a>
|
||||
</div>
|
||||
</main>
|
||||
)
|
||||
return (
|
||||
<main className={classes.root}>
|
||||
<div className={classes.header}>
|
||||
<div className={classes.title}>
|
||||
<Title1>Projects</Title1>
|
||||
<Tooltip content="Refresh Projects" relationship="description">
|
||||
<Button appearance="subtle" icon={<ArrowSync24Regular />} aria-description="Refresh Projects" />
|
||||
</Tooltip>
|
||||
</div>
|
||||
<div className={classes.search}>
|
||||
<Input appearance="filled-lighter" placeholder="Search Projects" contentBefore={<Search24Regular />}></Input>
|
||||
<Button appearance="subtle" icon={<AppsListFilled />}>
|
||||
List View
|
||||
</Button>
|
||||
<SplitButton appearance="primary" size="medium">
|
||||
Create New Project
|
||||
</SplitButton>
|
||||
</div>
|
||||
</div>
|
||||
<div className={classes.table}>
|
||||
<DataGrid
|
||||
items={items}
|
||||
columns={columns}
|
||||
sortable
|
||||
getRowId={item => item.file.label}
|
||||
onSelectionChange={(e, data) => console.log(data)}
|
||||
className={classes.dataGrid}
|
||||
>
|
||||
<DataGridHeader>
|
||||
<DataGridRow>
|
||||
{({ renderHeaderCell }) => <DataGridHeaderCell>{renderHeaderCell()}</DataGridHeaderCell>}
|
||||
</DataGridRow>
|
||||
</DataGridHeader>
|
||||
<DataGridBody<Item>>
|
||||
{({ item, rowId }) => (
|
||||
<DataGridRow<Item> key={rowId}>
|
||||
{({ renderCell }) => <DataGridCell>{renderCell(item)}</DataGridCell>}
|
||||
</DataGridRow>
|
||||
)}
|
||||
</DataGridBody>
|
||||
</DataGrid>
|
||||
</div>
|
||||
</main>
|
||||
);
|
||||
}
|
||||
|
52
src/app/providers.tsx
Normal file
@ -0,0 +1,52 @@
|
||||
'use client';
|
||||
|
||||
// Import necessary dependencies from 'react'
|
||||
import { useEffect, useState } from 'react';
|
||||
// Import necessary dependencies from '@fluentui/react-components'
|
||||
import {
|
||||
createDOMRenderer,
|
||||
RendererProvider,
|
||||
FluentProvider,
|
||||
webLightTheme,
|
||||
SSRProvider,
|
||||
teamsDarkTheme,
|
||||
webDarkTheme,
|
||||
} from '@fluentui/react-components';
|
||||
import { customDarkTheme } from './theme';
|
||||
|
||||
// Create a DOM renderer for Fluent UI.
|
||||
const renderer = createDOMRenderer();
|
||||
|
||||
/**
|
||||
* Providers component.
|
||||
*
|
||||
* This component wraps other components with a set of providers
|
||||
* for Fluent UI, SSR, and a custom renderer.
|
||||
*
|
||||
* @param {Object} props - The properties for the Providers component.
|
||||
* @param {React.ReactNode} props.children - The child components to be wrapped by the Providers.
|
||||
* @returns {React.Element} The Providers component with child components.
|
||||
*/
|
||||
export function Providers({ children: children }: { children: React.ReactNode }) {
|
||||
// Declare a state variable named 'hasMounted' and a function named 'setHasMounted' to update it.
|
||||
const [hasMounted, setHasMounted] = useState(false);
|
||||
|
||||
// Use the 'useEffect' hook to set 'hasMounted' to true once the component has mounted.
|
||||
useEffect(() => {
|
||||
setHasMounted(true);
|
||||
}, []);
|
||||
|
||||
// If the component hasn't mounted yet, return nothing.
|
||||
if (!hasMounted) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// If the component has mounted, return a set of providers.
|
||||
return (
|
||||
<RendererProvider renderer={renderer || createDOMRenderer()}>
|
||||
<SSRProvider>
|
||||
<FluentProvider theme={customDarkTheme} className='flex'>{children}</FluentProvider>
|
||||
</SSRProvider>
|
||||
</RendererProvider>
|
||||
);
|
||||
}
|
23
src/app/theme.ts
Normal file
@ -0,0 +1,23 @@
|
||||
import { BrandVariants, createLightTheme, createDarkTheme } from '@fluentui/react-components';
|
||||
|
||||
const customBrandRamp: BrandVariants = {
|
||||
10: '#0F91A9',
|
||||
20: '#0F91A9',
|
||||
30: '#0F91A9',
|
||||
40: '#0F91A9',
|
||||
50: '#0F91A9',
|
||||
60: '#0F91A9',
|
||||
70: '#0F91A9',
|
||||
80: '#44BFD5',
|
||||
90: '#58C6DA',
|
||||
100: '#0F91A9',
|
||||
110: '#0F91A9',
|
||||
120: '#0F91A9',
|
||||
130: '#0F91A9',
|
||||
140: '#0F91A9',
|
||||
150: '#0F91A9',
|
||||
160: '#0F91A9',
|
||||
};
|
||||
|
||||
export const customLightTheme = createLightTheme(customBrandRamp);
|
||||
export const customDarkTheme = createDarkTheme(customBrandRamp);
|
@ -1,20 +1,19 @@
|
||||
import type { Config } from 'tailwindcss'
|
||||
import type { Config } from 'tailwindcss';
|
||||
|
||||
const config: Config = {
|
||||
content: [
|
||||
'./src/pages/**/*.{js,ts,jsx,tsx,mdx}',
|
||||
'./src/components/**/*.{js,ts,jsx,tsx,mdx}',
|
||||
'./src/app/**/*.{js,ts,jsx,tsx,mdx}',
|
||||
],
|
||||
theme: {
|
||||
extend: {
|
||||
backgroundImage: {
|
||||
'gradient-radial': 'radial-gradient(var(--tw-gradient-stops))',
|
||||
'gradient-conic':
|
||||
'conic-gradient(from 180deg at 50% 50%, var(--tw-gradient-stops))',
|
||||
},
|
||||
},
|
||||
},
|
||||
plugins: [],
|
||||
}
|
||||
export default config
|
||||
content: [
|
||||
'./src/pages/**/*.{js,ts,jsx,tsx,mdx}',
|
||||
'./src/components/**/*.{js,ts,jsx,tsx,mdx}',
|
||||
'./src/app/**/*.{js,ts,jsx,tsx,mdx}',
|
||||
],
|
||||
theme: {
|
||||
extend: {
|
||||
backgroundImage: {
|
||||
'gradient-radial': 'radial-gradient(var(--tw-gradient-stops))',
|
||||
'gradient-conic': 'conic-gradient(from 180deg at 50% 50%, var(--tw-gradient-stops))',
|
||||
},
|
||||
},
|
||||
},
|
||||
plugins: [],
|
||||
};
|
||||
export default config;
|
||||
|
@ -1,27 +1,28 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"target": "es5",
|
||||
"lib": ["dom", "dom.iterable", "esnext"],
|
||||
"allowJs": true,
|
||||
"skipLibCheck": true,
|
||||
"strict": true,
|
||||
"noEmit": true,
|
||||
"esModuleInterop": true,
|
||||
"module": "esnext",
|
||||
"moduleResolution": "bundler",
|
||||
"resolveJsonModule": true,
|
||||
"isolatedModules": true,
|
||||
"jsx": "preserve",
|
||||
"incremental": true,
|
||||
"plugins": [
|
||||
{
|
||||
"name": "next"
|
||||
}
|
||||
],
|
||||
"paths": {
|
||||
"@/*": ["./src/*"]
|
||||
}
|
||||
},
|
||||
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],
|
||||
"exclude": ["node_modules"]
|
||||
"compilerOptions": {
|
||||
"target": "es5",
|
||||
"lib": ["dom", "dom.iterable", "esnext"],
|
||||
"allowJs": true,
|
||||
"skipLibCheck": true,
|
||||
"strict": true,
|
||||
"noEmit": true,
|
||||
"esModuleInterop": true,
|
||||
"module": "esnext",
|
||||
"moduleResolution": "bundler",
|
||||
"resolveJsonModule": true,
|
||||
"isolatedModules": true,
|
||||
"jsx": "preserve",
|
||||
// "jsxImportSource": "@emotion/react",
|
||||
"incremental": true,
|
||||
"plugins": [
|
||||
{
|
||||
"name": "next"
|
||||
}
|
||||
],
|
||||
"paths": {
|
||||
"@/*": ["./src/*"]
|
||||
}
|
||||
},
|
||||
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],
|
||||
"exclude": ["node_modules", "src-tauri"]
|
||||
}
|
||||
|