mirror of
https://github.com/tachiyomiorg/tachiyomi-extensions-inspector.git
synced 2024-12-24 15:51:49 +01:00
Port to typescript
This commit is contained in:
parent
59c69a4f7f
commit
efbb2a8524
1
webUI/react/.eslintignore
Normal file
1
webUI/react/.eslintignore
Normal file
@ -0,0 +1 @@
|
||||
.eslintrc.js
|
@ -1,33 +1,17 @@
|
||||
module.exports = {
|
||||
env: {
|
||||
browser: true,
|
||||
es2021: true,
|
||||
},
|
||||
extends: [
|
||||
'plugin:react/recommended',
|
||||
'airbnb',
|
||||
],
|
||||
extends: ['airbnb-typescript'],
|
||||
plugins: ['@typescript-eslint'],
|
||||
parserOptions: {
|
||||
ecmaFeatures: {
|
||||
jsx: true,
|
||||
},
|
||||
ecmaVersion: 12,
|
||||
sourceType: 'module',
|
||||
project: './tsconfig.json',
|
||||
},
|
||||
plugins: [
|
||||
'react',
|
||||
],
|
||||
rules: {
|
||||
// Indent with 4 spaces
|
||||
indent: ['error', 4],
|
||||
'@typescript-eslint/indent': ['error', 4],
|
||||
|
||||
// Indent JSX with 4 spaces
|
||||
'react/jsx-indent': ['error', 4],
|
||||
|
||||
// Indent props with 4 spaces
|
||||
'react/jsx-indent-props': ['error', 4],
|
||||
|
||||
// allow JSX in both js and jsx files
|
||||
'react/jsx-filename-extension': [1, { extensions: ['.js', '.jsx'] }],
|
||||
},
|
||||
};
|
||||
|
@ -34,11 +34,17 @@
|
||||
]
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/react": "^17.0.0",
|
||||
"@types/react-dom": "^17.0.0",
|
||||
"@types/react-router-dom": "^5.1.6",
|
||||
"@typescript-eslint/eslint-plugin": "^4.11.0",
|
||||
"@typescript-eslint/parser": "4.11.0",
|
||||
"eslint": "^7.16.0",
|
||||
"eslint-config-airbnb": "^18.2.1",
|
||||
"eslint-config-airbnb-typescript": "^12.0.0",
|
||||
"eslint-plugin-import": "^2.22.1",
|
||||
"eslint-plugin-jsx-a11y": "^6.4.1",
|
||||
"eslint-plugin-react": "^7.21.5",
|
||||
"eslint-plugin-react-hooks": "^4.2.0"
|
||||
"eslint-plugin-react-hooks": "^4.2.0",
|
||||
"typescript": "^4.1.0"
|
||||
}
|
||||
}
|
@ -8,6 +8,34 @@ import Button from '@material-ui/core/Button';
|
||||
import NavBar from './components/NavBar';
|
||||
import ExtensionCard from './components/ExtensionCard';
|
||||
|
||||
function Extensions() {
|
||||
let mapped;
|
||||
const [extensions, setExtensions] = useState<IExtension[]>([]);
|
||||
|
||||
if (extensions.length === 0) {
|
||||
mapped = <h3>wait</h3>;
|
||||
fetch('http://127.0.0.1:4567/api/v1/extensions')
|
||||
.then((response) => response.json())
|
||||
.then((data) => setExtensions(data));
|
||||
} else {
|
||||
mapped = extensions.map((it) => <ExtensionCard extension={it} />);
|
||||
}
|
||||
|
||||
return <h2>{mapped}</h2>;
|
||||
}
|
||||
|
||||
function Home() {
|
||||
return (
|
||||
<Button variant="contained" color="primary">
|
||||
Hello World
|
||||
</Button>
|
||||
);
|
||||
}
|
||||
|
||||
function Users() {
|
||||
return <h2>Users</h2>;
|
||||
}
|
||||
|
||||
export default function App() {
|
||||
return (
|
||||
<Router>
|
||||
@ -28,31 +56,3 @@ export default function App() {
|
||||
</Router>
|
||||
);
|
||||
}
|
||||
|
||||
function Extensions() {
|
||||
let mapped;
|
||||
const [extensions, setExtensions] = useState([]);
|
||||
|
||||
if (extensions.length === 0) {
|
||||
mapped = <h3>wait</h3>;
|
||||
fetch('http://127.0.0.1:4567/api/v1/extensions')
|
||||
.then((response) => response.json())
|
||||
.then((data) => setExtensions(data));
|
||||
} else {
|
||||
mapped = extensions.map((it) => <ExtensionCard {...it} />);
|
||||
}
|
||||
|
||||
return <h2>{mapped}</h2>;
|
||||
}
|
||||
|
||||
function Home() {
|
||||
return (
|
||||
<Button variant="contained" color="primary">
|
||||
Hello World
|
||||
</Button>
|
||||
);
|
||||
}
|
||||
|
||||
function Users() {
|
||||
return <h2>Users</h2>;
|
||||
}
|
@ -1,65 +0,0 @@
|
||||
import React from "react";
|
||||
import { makeStyles } from "@material-ui/core/styles";
|
||||
import Card from "@material-ui/core/Card";
|
||||
import CardContent from "@material-ui/core/CardContent";
|
||||
import Button from "@material-ui/core/Button";
|
||||
import Avatar from "@material-ui/core/Avatar";
|
||||
import Typography from "@material-ui/core/Typography";
|
||||
|
||||
const useStyles = makeStyles((theme) => ({
|
||||
root: {
|
||||
display: "flex",
|
||||
justifyContent: "space-between",
|
||||
alignItems: "center",
|
||||
padding: 16
|
||||
},
|
||||
bullet: {
|
||||
display: "inline-block",
|
||||
margin: "0 2px",
|
||||
transform: "scale(0.8)"
|
||||
},
|
||||
title: {
|
||||
fontSize: 14
|
||||
},
|
||||
pos: {
|
||||
marginBottom: 12
|
||||
},
|
||||
icon: {
|
||||
width: theme.spacing(7),
|
||||
height: theme.spacing(7),
|
||||
flex: "0 0 auto",
|
||||
marginRight: 16
|
||||
}
|
||||
}));
|
||||
|
||||
export default function ExtensionCard(props) {
|
||||
const classes = useStyles();
|
||||
const bull = <span className={classes.bullet}>•</span>;
|
||||
const {name, lang, versionName, iconUrl} = props
|
||||
const langPress = lang === "all"? "All": lang.toUpperCase()
|
||||
|
||||
return (
|
||||
<Card>
|
||||
<CardContent className={classes.root}>
|
||||
<div style={{display:"flex"}}>
|
||||
<Avatar
|
||||
variant="rounded"
|
||||
className={classes.icon}
|
||||
alt={name}
|
||||
src={iconUrl}
|
||||
/>
|
||||
<div style={{display:"flex", flexDirection:"column"}}>
|
||||
<Typography variant="h5" component="h2">
|
||||
{name}
|
||||
</Typography>
|
||||
<Typography variant="caption" display="block" gutterBottom>
|
||||
{langPress} {versionName}
|
||||
</Typography>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<Button variant="outlined" >install</Button>
|
||||
</CardContent>
|
||||
</Card>
|
||||
);
|
||||
}
|
75
webUI/react/src/components/ExtensionCard.tsx
Normal file
75
webUI/react/src/components/ExtensionCard.tsx
Normal file
@ -0,0 +1,75 @@
|
||||
import React from 'react';
|
||||
import { makeStyles } from '@material-ui/core/styles';
|
||||
import Card from '@material-ui/core/Card';
|
||||
import CardContent from '@material-ui/core/CardContent';
|
||||
import Button from '@material-ui/core/Button';
|
||||
import Avatar from '@material-ui/core/Avatar';
|
||||
import Typography from '@material-ui/core/Typography';
|
||||
|
||||
const useStyles = makeStyles((theme) => ({
|
||||
root: {
|
||||
display: 'flex',
|
||||
justifyContent: 'space-between',
|
||||
alignItems: 'center',
|
||||
padding: 16,
|
||||
},
|
||||
bullet: {
|
||||
display: 'inline-block',
|
||||
margin: '0 2px',
|
||||
transform: 'scale(0.8)',
|
||||
},
|
||||
title: {
|
||||
fontSize: 14,
|
||||
},
|
||||
pos: {
|
||||
marginBottom: 12,
|
||||
},
|
||||
icon: {
|
||||
width: theme.spacing(7),
|
||||
height: theme.spacing(7),
|
||||
flex: '0 0 auto',
|
||||
marginRight: 16,
|
||||
},
|
||||
}));
|
||||
|
||||
interface IProps {
|
||||
extension: IExtension
|
||||
}
|
||||
|
||||
export default function ExtensionCard({
|
||||
extension: {
|
||||
name, lang, versionName, iconUrl,
|
||||
},
|
||||
}: IProps) {
|
||||
const classes = useStyles();
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
const bull = <span className={classes.bullet}>•</span>;
|
||||
const langPress = lang === 'all' ? 'All' : lang.toUpperCase();
|
||||
|
||||
return (
|
||||
<Card>
|
||||
<CardContent className={classes.root}>
|
||||
<div style={{ display: 'flex' }}>
|
||||
<Avatar
|
||||
variant="rounded"
|
||||
className={classes.icon}
|
||||
alt={name}
|
||||
src={iconUrl}
|
||||
/>
|
||||
<div style={{ display: 'flex', flexDirection: 'column' }}>
|
||||
<Typography variant="h5" component="h2">
|
||||
{name}
|
||||
</Typography>
|
||||
<Typography variant="caption" display="block" gutterBottom>
|
||||
{langPress}
|
||||
{' '}
|
||||
{versionName}
|
||||
</Typography>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<Button variant="outlined">install</Button>
|
||||
</CardContent>
|
||||
</Card>
|
||||
);
|
||||
}
|
@ -1,12 +1,11 @@
|
||||
import React, {useState} from 'react';
|
||||
import {makeStyles} from '@material-ui/core/styles';
|
||||
import React, { useState } from 'react';
|
||||
import { makeStyles } from '@material-ui/core/styles';
|
||||
import AppBar from '@material-ui/core/AppBar';
|
||||
import Toolbar from '@material-ui/core/Toolbar';
|
||||
import Typography from '@material-ui/core/Typography';
|
||||
import Button from '@material-ui/core/Button';
|
||||
import IconButton from '@material-ui/core/IconButton';
|
||||
import MenuIcon from '@material-ui/icons/Menu';
|
||||
import TemporaryDrawer from "./TemporaryDrawer";
|
||||
import TemporaryDrawer from './TemporaryDrawer';
|
||||
|
||||
const useStyles = makeStyles((theme) => ({
|
||||
root: {
|
||||
@ -22,22 +21,28 @@ const useStyles = makeStyles((theme) => ({
|
||||
|
||||
export default function NavBar() {
|
||||
const classes = useStyles();
|
||||
const [drawerOpen, setDrawerOpen] = useState(false)
|
||||
const [drawerOpen, setDrawerOpen] = useState(false);
|
||||
|
||||
return (
|
||||
<div className={classes.root}>
|
||||
<AppBar position="static">
|
||||
<Toolbar>
|
||||
<IconButton edge="start" className={classes.menuButton} color="inherit" aria-label="menu" disableRipple
|
||||
onClick={() => setDrawerOpen(true)}>
|
||||
<MenuIcon/>
|
||||
<IconButton
|
||||
edge="start"
|
||||
className={classes.menuButton}
|
||||
color="inherit"
|
||||
aria-label="menu"
|
||||
disableRipple
|
||||
onClick={() => setDrawerOpen(true)}
|
||||
>
|
||||
<MenuIcon />
|
||||
</IconButton>
|
||||
<Typography variant="h6" className={classes.title}>
|
||||
Tachidesk
|
||||
</Typography>
|
||||
</Toolbar>
|
||||
</AppBar>
|
||||
<TemporaryDrawer drawerOpen={drawerOpen} setDrawerOpen={setDrawerOpen}/>
|
||||
<TemporaryDrawer drawerOpen={drawerOpen} setDrawerOpen={setDrawerOpen} />
|
||||
</div>
|
||||
);
|
||||
}
|
@ -1,55 +0,0 @@
|
||||
import React from "react";
|
||||
import {makeStyles} from "@material-ui/core/styles";
|
||||
import Drawer from "@material-ui/core/Drawer";
|
||||
import Button from "@material-ui/core/Button";
|
||||
import List from "@material-ui/core/List";
|
||||
import ListItem from "@material-ui/core/ListItem";
|
||||
import ListItemIcon from "@material-ui/core/ListItemIcon";
|
||||
import ListItemText from "@material-ui/core/ListItemText";
|
||||
import InboxIcon from "@material-ui/icons/MoveToInbox";
|
||||
import MailIcon from "@material-ui/icons/Mail";
|
||||
import {Link} from "react-router-dom";
|
||||
|
||||
const useStyles = makeStyles({
|
||||
list: {
|
||||
width: 250
|
||||
}
|
||||
});
|
||||
|
||||
export default function TemporaryDrawer(props) {
|
||||
const classes = useStyles();
|
||||
const {drawerOpen, setDrawerOpen} = props
|
||||
|
||||
const sideList = side => (
|
||||
<div
|
||||
className={classes.list}
|
||||
role="presentation"
|
||||
onClick={() => setDrawerOpen(false)}
|
||||
onKeyDown={() => setDrawerOpen(false)}
|
||||
>
|
||||
<List>
|
||||
<Link to="/extensions" style={{color: "inherit", textDecoration: "none"}}>
|
||||
<ListItem button key="Extensions">
|
||||
<ListItemIcon>
|
||||
<InboxIcon/>
|
||||
</ListItemIcon>
|
||||
<ListItemText primary="Extensions"/>
|
||||
</ListItem>
|
||||
</Link>
|
||||
</List>
|
||||
</div>
|
||||
);
|
||||
|
||||
return (
|
||||
<div>
|
||||
<Drawer
|
||||
BackdropProps={{invisible: true}}
|
||||
open={drawerOpen}
|
||||
anchor={"left"}
|
||||
onClose={() => setDrawerOpen(false)}
|
||||
>
|
||||
{sideList("left")}
|
||||
</Drawer>
|
||||
</div>
|
||||
);
|
||||
}
|
58
webUI/react/src/components/TemporaryDrawer.tsx
Normal file
58
webUI/react/src/components/TemporaryDrawer.tsx
Normal file
@ -0,0 +1,58 @@
|
||||
import React from 'react';
|
||||
import { makeStyles } from '@material-ui/core/styles';
|
||||
import Drawer from '@material-ui/core/Drawer';
|
||||
import List from '@material-ui/core/List';
|
||||
import ListItem from '@material-ui/core/ListItem';
|
||||
import ListItemIcon from '@material-ui/core/ListItemIcon';
|
||||
import ListItemText from '@material-ui/core/ListItemText';
|
||||
import InboxIcon from '@material-ui/icons/MoveToInbox';
|
||||
import { Link } from 'react-router-dom';
|
||||
|
||||
const useStyles = makeStyles({
|
||||
list: {
|
||||
width: 250,
|
||||
},
|
||||
});
|
||||
|
||||
interface IProps {
|
||||
drawerOpen: boolean
|
||||
setDrawerOpen(state: boolean): void
|
||||
}
|
||||
|
||||
export default function TemporaryDrawer({ drawerOpen, setDrawerOpen }: IProps) {
|
||||
const classes = useStyles();
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
const sideList = (side: 'left') => (
|
||||
<div
|
||||
className={classes.list}
|
||||
role="presentation"
|
||||
onClick={() => setDrawerOpen(false)}
|
||||
onKeyDown={() => setDrawerOpen(false)}
|
||||
>
|
||||
<List>
|
||||
<Link to="/extensions" style={{ color: 'inherit', textDecoration: 'none' }}>
|
||||
<ListItem button key="Extensions">
|
||||
<ListItemIcon>
|
||||
<InboxIcon />
|
||||
</ListItemIcon>
|
||||
<ListItemText primary="Extensions" />
|
||||
</ListItem>
|
||||
</Link>
|
||||
</List>
|
||||
</div>
|
||||
);
|
||||
|
||||
return (
|
||||
<div>
|
||||
<Drawer
|
||||
BackdropProps={{ invisible: true }}
|
||||
open={drawerOpen}
|
||||
anchor="left"
|
||||
onClose={() => setDrawerOpen(false)}
|
||||
>
|
||||
{sideList('left')}
|
||||
</Drawer>
|
||||
</div>
|
||||
);
|
||||
}
|
@ -6,12 +6,11 @@ import './index.css';
|
||||
// roboto font
|
||||
import 'fontsource-roboto';
|
||||
|
||||
|
||||
ReactDOM.render(
|
||||
<React.StrictMode>
|
||||
<App />
|
||||
</React.StrictMode>,
|
||||
document.getElementById('root')
|
||||
<React.StrictMode>
|
||||
<App />
|
||||
</React.StrictMode>,
|
||||
document.getElementById('root'),
|
||||
);
|
||||
|
||||
// If you want to start measuring performance in your app, pass a function
|
1
webUI/react/src/react-app-env.d.ts
vendored
Normal file
1
webUI/react/src/react-app-env.d.ts
vendored
Normal file
@ -0,0 +1 @@
|
||||
/// <reference types="react-scripts" />
|
@ -1,13 +0,0 @@
|
||||
const reportWebVitals = onPerfEntry => {
|
||||
if (onPerfEntry && onPerfEntry instanceof Function) {
|
||||
import('web-vitals').then(({ getCLS, getFID, getFCP, getLCP, getTTFB }) => {
|
||||
getCLS(onPerfEntry);
|
||||
getFID(onPerfEntry);
|
||||
getFCP(onPerfEntry);
|
||||
getLCP(onPerfEntry);
|
||||
getTTFB(onPerfEntry);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
export default reportWebVitals;
|
17
webUI/react/src/reportWebVitals.ts
Normal file
17
webUI/react/src/reportWebVitals.ts
Normal file
@ -0,0 +1,17 @@
|
||||
import { ReportHandler } from 'web-vitals';
|
||||
|
||||
const reportWebVitals = (onPerfEntry?: ReportHandler) => {
|
||||
if (onPerfEntry) {
|
||||
import('web-vitals').then(({
|
||||
getCLS, getFID, getFCP, getLCP, getTTFB,
|
||||
}) => {
|
||||
getCLS(onPerfEntry);
|
||||
getFID(onPerfEntry);
|
||||
getFCP(onPerfEntry);
|
||||
getLCP(onPerfEntry);
|
||||
getTTFB(onPerfEntry);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
export default reportWebVitals;
|
6
webUI/react/src/typings.d.ts
vendored
Normal file
6
webUI/react/src/typings.d.ts
vendored
Normal file
@ -0,0 +1,6 @@
|
||||
interface IExtension {
|
||||
name: string
|
||||
lang: string
|
||||
versionName: string
|
||||
iconUrl: string
|
||||
}
|
26
webUI/react/tsconfig.json
Normal file
26
webUI/react/tsconfig.json
Normal file
@ -0,0 +1,26 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"target": "es5",
|
||||
"lib": [
|
||||
"dom",
|
||||
"dom.iterable",
|
||||
"esnext"
|
||||
],
|
||||
"allowJs": true,
|
||||
"skipLibCheck": true,
|
||||
"esModuleInterop": true,
|
||||
"allowSyntheticDefaultImports": true,
|
||||
"strict": true,
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"noFallthroughCasesInSwitch": true,
|
||||
"module": "esnext",
|
||||
"moduleResolution": "node",
|
||||
"resolveJsonModule": true,
|
||||
"isolatedModules": true,
|
||||
"noEmit": true,
|
||||
"jsx": "react-jsx"
|
||||
},
|
||||
"include": [
|
||||
"src"
|
||||
]
|
||||
}
|
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user