This commit is contained in:
12
src/App/AppLayout/index.tsx
Normal file
12
src/App/AppLayout/index.tsx
Normal file
@ -0,0 +1,12 @@
|
||||
import { FC, ReactNode } from "react";
|
||||
|
||||
import style from './style.module.scss'
|
||||
|
||||
interface AppLayoutProp {
|
||||
children?: ReactNode
|
||||
}
|
||||
|
||||
export const AppLayout: FC<AppLayoutProp> = ({ children }) =>
|
||||
<div className={style.container}>
|
||||
{children}
|
||||
</div>
|
16
src/App/AppLayout/style.module.scss
Normal file
16
src/App/AppLayout/style.module.scss
Normal file
@ -0,0 +1,16 @@
|
||||
.container {
|
||||
display: flex;
|
||||
|
||||
width: 100vw;
|
||||
height: 100dvh;
|
||||
|
||||
> * {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
@media (max-width: 1200px) {
|
||||
& {
|
||||
flex-direction: column;
|
||||
}
|
||||
}
|
||||
}
|
11
src/App/index.tsx
Normal file
11
src/App/index.tsx
Normal file
@ -0,0 +1,11 @@
|
||||
import { FC } from "react";
|
||||
import { AppLayout } from "./AppLayout";
|
||||
import { Editor } from "../Editor";
|
||||
import { TransformGrid } from "../TransformGrid";
|
||||
|
||||
export const App: FC = () =>
|
||||
<AppLayout>
|
||||
<Editor />
|
||||
<TransformGrid />
|
||||
</AppLayout>
|
||||
|
BIN
src/Assets/favicon.webp
Normal file
BIN
src/Assets/favicon.webp
Normal file
Binary file not shown.
After Width: | Height: | Size: 8.7 KiB |
18
src/Components/Button.tsx
Normal file
18
src/Components/Button.tsx
Normal file
@ -0,0 +1,18 @@
|
||||
import styled from "styled-components";
|
||||
|
||||
export const Button = styled.button`
|
||||
border: none;
|
||||
padding: 6px 10px;
|
||||
border-radius: 4px;
|
||||
cursor: pointer;
|
||||
background-color: #ff1696;
|
||||
color: white;
|
||||
|
||||
&:hover {
|
||||
background-color: #da1c9b;
|
||||
}
|
||||
|
||||
&:placeholder {
|
||||
color: gray;
|
||||
}
|
||||
`
|
22
src/Components/Input.tsx
Normal file
22
src/Components/Input.tsx
Normal file
@ -0,0 +1,22 @@
|
||||
import styled from "styled-components";
|
||||
|
||||
export const Input = styled.input`
|
||||
background-color: transparent;
|
||||
color: #fafafa;
|
||||
border: none;
|
||||
border-bottom: 1px solid #fafafa;
|
||||
text-align: center;
|
||||
accent-color: #ff1696;
|
||||
box-sizing: border-box;
|
||||
font-size: 12px;
|
||||
|
||||
width: 24px;
|
||||
|
||||
&[type=checkbox] {
|
||||
width: auto;
|
||||
}
|
||||
|
||||
&:focus {
|
||||
outline: none;
|
||||
}
|
||||
`
|
14
src/Components/TextArea.tsx
Normal file
14
src/Components/TextArea.tsx
Normal file
@ -0,0 +1,14 @@
|
||||
import styled from "styled-components";
|
||||
|
||||
export const TextArea = styled.textarea`
|
||||
flex: 1;
|
||||
border: none;
|
||||
resize: none;
|
||||
background-color: transparent;
|
||||
color: #fafafa;
|
||||
padding: 10px;
|
||||
|
||||
&:focus {
|
||||
outline: none;
|
||||
}
|
||||
`
|
39
src/Editor/index.tsx
Normal file
39
src/Editor/index.tsx
Normal file
@ -0,0 +1,39 @@
|
||||
import { FC } from "react";
|
||||
import { Editor as MonacoEditor } from "@monaco-editor/react";
|
||||
import { useRecoilState } from "recoil";
|
||||
import { EditorValueState } from "../GlobalStates/EditorValueState";
|
||||
import { motion } from "framer-motion";
|
||||
|
||||
export const Editor: FC = () => {
|
||||
const [value, setValue] = useRecoilState(EditorValueState)
|
||||
|
||||
return (
|
||||
<motion.div
|
||||
transition={{ delay: 1.5 }}
|
||||
initial={{ opacity: 0 }}
|
||||
animate={{ opacity: 1 }}>
|
||||
<MonacoEditor
|
||||
loading={<></>}
|
||||
value={value}
|
||||
language="yaml"
|
||||
onChange={(v) => setValue(v ?? '')}
|
||||
options={{
|
||||
automaticLayout: true,
|
||||
lineNumbersMinChars: 3,
|
||||
minimap: { enabled: false },
|
||||
theme: "vs-dark",
|
||||
fontSize: 24,
|
||||
scrollBeyondLastLine: false,
|
||||
fontFamily: 'JetBrains Mono Variable',
|
||||
fontLigatures: true,
|
||||
wordWrap: "on",
|
||||
mouseWheelZoom: true,
|
||||
smoothScrolling: true,
|
||||
cursorSmoothCaretAnimation: 'on',
|
||||
cursorBlinking: 'smooth',
|
||||
cursorStyle: 'block'
|
||||
}}
|
||||
theme="vs-dark" />
|
||||
</motion.div>
|
||||
)
|
||||
}
|
8
src/GlobalStates/EditorValueState.ts
Normal file
8
src/GlobalStates/EditorValueState.ts
Normal file
@ -0,0 +1,8 @@
|
||||
import { atom } from "recoil";
|
||||
|
||||
export const EditorValueState = atom({
|
||||
key: 'editor_value',
|
||||
default: JSON.stringify({
|
||||
Hello: 'world!'
|
||||
}, null, 2)
|
||||
})
|
30
src/LandingAnimation/index.tsx
Normal file
30
src/LandingAnimation/index.tsx
Normal file
@ -0,0 +1,30 @@
|
||||
import { FC, useEffect, useState } from "react";
|
||||
import { AnimatePresence, motion, TargetAndTransition } from 'framer-motion'
|
||||
|
||||
import style from './style.module.scss'
|
||||
import Suika from '../Assets/favicon.webp'
|
||||
|
||||
export const LandingAnimation: FC = () => {
|
||||
const [isVisible, setVisible] = useState(true)
|
||||
const exitAnimation: TargetAndTransition = {
|
||||
opacity: 0
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
setTimeout(() => {
|
||||
setVisible(false)
|
||||
}, 1000)
|
||||
}, [])
|
||||
|
||||
return (
|
||||
<AnimatePresence>
|
||||
{isVisible && (
|
||||
<motion.div exit={exitAnimation} className={style.container}>
|
||||
<img src={Suika} alt="suika" />
|
||||
<h1>The PTOOLS</h1>
|
||||
<p>Right tools for you!</p>
|
||||
</motion.div>
|
||||
)}
|
||||
</AnimatePresence>
|
||||
)
|
||||
}
|
20
src/LandingAnimation/style.module.scss
Normal file
20
src/LandingAnimation/style.module.scss
Normal file
@ -0,0 +1,20 @@
|
||||
.container {
|
||||
position: absolute;
|
||||
|
||||
top: 0;
|
||||
left: 0;
|
||||
z-index: 100;
|
||||
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
|
||||
width: 100dvw;
|
||||
height: 100dvh;
|
||||
|
||||
img {
|
||||
width: 100px;
|
||||
}
|
||||
}
|
22
src/TransformGrid/index.tsx
Normal file
22
src/TransformGrid/index.tsx
Normal file
@ -0,0 +1,22 @@
|
||||
import { FC } from "react";
|
||||
import { motion } from "framer-motion";
|
||||
|
||||
import style from './style.module.scss'
|
||||
import { TransformGridItem } from "../TransformGridItem";
|
||||
import { transforms } from "../Transforms/Transform";
|
||||
|
||||
export const TransformGrid: FC = () =>
|
||||
<ul className={style.grid}>
|
||||
{transforms.map((v, i) =>
|
||||
<motion.li
|
||||
key={i}
|
||||
initial={{ opacity: 0 }}
|
||||
animate={{ opacity: 1 }}
|
||||
transition={{ delay: i * 0.1 + 1.5 }} >
|
||||
|
||||
<TransformGridItem
|
||||
transform={v}/>
|
||||
|
||||
</motion.li>
|
||||
)}
|
||||
</ul>
|
10
src/TransformGrid/style.module.scss
Normal file
10
src/TransformGrid/style.module.scss
Normal file
@ -0,0 +1,10 @@
|
||||
.grid {
|
||||
padding: 10px;
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(400px, 1fr));
|
||||
|
||||
gap: 10px;
|
||||
height: 100%;
|
||||
box-sizing: border-box;
|
||||
overflow-y: scroll;
|
||||
}
|
30
src/TransformGridItem/index.tsx
Normal file
30
src/TransformGridItem/index.tsx
Normal file
@ -0,0 +1,30 @@
|
||||
import { FC } from "react";
|
||||
import style from './style.module.scss'
|
||||
import { Button } from "../Components/Button";
|
||||
import { Input } from "../Components/Input";
|
||||
import { TextArea } from "../Components/TextArea";
|
||||
import { Transform } from "../Transforms/Transform";
|
||||
|
||||
interface TransformGridItemProp {
|
||||
transform: Transform
|
||||
}
|
||||
|
||||
export const TransformGridItem: FC<TransformGridItemProp> = ({ transform }) => {
|
||||
return (
|
||||
<div className={style.item}>
|
||||
<div className={style.toolbar}>
|
||||
<Button><<<</Button>
|
||||
<h2 className={style.name}>{transform.name}</h2>
|
||||
|
||||
<div className={style.options}>
|
||||
<label className={style.optionItem}>hello: <Input type="checkbox" /></label>
|
||||
<label className={style.optionItem}>hello: <Input type="text" /></label>
|
||||
<label className={style.optionItem}>hello: <Input type="checkbox" /></label>
|
||||
<label className={style.optionItem}>hello: <Input type="checkbox" /></label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<TextArea placeholder="(empty)" className={style.input} />
|
||||
</div>
|
||||
)
|
||||
}
|
38
src/TransformGridItem/style.module.scss
Normal file
38
src/TransformGridItem/style.module.scss
Normal file
@ -0,0 +1,38 @@
|
||||
.item {
|
||||
background-color: #1e1e1e;
|
||||
border-radius: 6px;
|
||||
display: flex;
|
||||
padding: 10px;
|
||||
flex-direction: column;
|
||||
min-height: 300px;
|
||||
|
||||
.toolbar {
|
||||
display: flex;
|
||||
gap: 10px;
|
||||
align-items: center;
|
||||
padding: 0px 10px;
|
||||
background-color: #323232;
|
||||
border-radius: 4px;
|
||||
|
||||
.name {
|
||||
font-size: inherit;
|
||||
padding: 14px 0px;
|
||||
}
|
||||
|
||||
.options {
|
||||
flex-grow: 1;
|
||||
display: flex;
|
||||
padding: 14px 2px;
|
||||
gap: 10px;
|
||||
height: 100%;
|
||||
overflow-x: scroll;
|
||||
scrollbar-width: thin;
|
||||
scrollbar-color: gray #323232;
|
||||
align-items: center;
|
||||
|
||||
.optionItem {
|
||||
display: flex;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
6
src/Transforms/Base64DecodeTransform.ts
Normal file
6
src/Transforms/Base64DecodeTransform.ts
Normal file
@ -0,0 +1,6 @@
|
||||
import { Transform } from "./Transform";
|
||||
|
||||
export const Base64DecodeTransform: Transform = {
|
||||
name: 'base64d',
|
||||
fn: () => 'Hello, world!'
|
||||
}
|
12
src/Transforms/Transform.ts
Normal file
12
src/Transforms/Transform.ts
Normal file
@ -0,0 +1,12 @@
|
||||
import { Base64DecodeTransform } from "./Base64DecodeTransform"
|
||||
|
||||
export interface Transform {
|
||||
name: string
|
||||
fn: () => string
|
||||
}
|
||||
|
||||
export const transforms: Transform[] = [
|
||||
Base64DecodeTransform,
|
||||
Base64DecodeTransform,
|
||||
Base64DecodeTransform,
|
||||
]
|
12
src/main.css
Normal file
12
src/main.css
Normal file
@ -0,0 +1,12 @@
|
||||
:root {
|
||||
color: #fafafa;
|
||||
background-color: #212121;
|
||||
font-family: 'JetBrains Mono Variable', monospace;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
h1, h2, h3, h4, h5, h6, p, pre, textarea, input, button, li, ul, ol {
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
list-style-type: none;
|
||||
}
|
22
src/main.tsx
Normal file
22
src/main.tsx
Normal file
@ -0,0 +1,22 @@
|
||||
import { StrictMode } from 'react'
|
||||
import { createRoot } from 'react-dom/client'
|
||||
|
||||
import 'normalize.css/normalize.css'
|
||||
import '@fontsource-variable/jetbrains-mono/index.css'
|
||||
|
||||
// ---
|
||||
|
||||
import './main.css'
|
||||
import { App } from './App'
|
||||
import { LandingAnimation } from './LandingAnimation'
|
||||
import { RecoilRoot } from 'recoil'
|
||||
|
||||
createRoot(document.getElementById('root')!).render(
|
||||
<StrictMode>
|
||||
<RecoilRoot>
|
||||
<App />
|
||||
|
||||
<LandingAnimation />
|
||||
</RecoilRoot>
|
||||
</StrictMode>,
|
||||
)
|
1
src/vite-env.d.ts
vendored
Normal file
1
src/vite-env.d.ts
vendored
Normal file
@ -0,0 +1 @@
|
||||
/// <reference types="vite/client" />
|
Reference in New Issue
Block a user