mirror of
https://github.com/artegoser/AnoPaper.git
synced 2024-11-05 20:43:57 +03:00
feat: server and fix inline code
This commit is contained in:
parent
8bdc53f45d
commit
bff9c3875c
9 changed files with 1391 additions and 59 deletions
2
.gitignore
vendored
2
.gitignore
vendored
|
@ -125,3 +125,5 @@ dist
|
||||||
.yarn/build-state.yml
|
.yarn/build-state.yml
|
||||||
.yarn/install-state.gz
|
.yarn/install-state.gz
|
||||||
.pnp.*
|
.pnp.*
|
||||||
|
|
||||||
|
notes/
|
||||||
|
|
61
index.js
Normal file
61
index.js
Normal file
|
@ -0,0 +1,61 @@
|
||||||
|
const sha3 = require("js-sha3").sha3_512;
|
||||||
|
const express = require("express");
|
||||||
|
const bodyParser = require("body-parser");
|
||||||
|
const isValidNote = require("./note_validator");
|
||||||
|
const fs = require("fs");
|
||||||
|
const path = require("path");
|
||||||
|
|
||||||
|
const cryptojs = require("crypto-js");
|
||||||
|
|
||||||
|
require("dotenv").config();
|
||||||
|
|
||||||
|
const app = express();
|
||||||
|
|
||||||
|
app.use(bodyParser.json());
|
||||||
|
|
||||||
|
app.post("/publish", function (req, res) {
|
||||||
|
if (isValidNote(req.body)) {
|
||||||
|
let hash = sha3(JSON.stringify(req.body));
|
||||||
|
req.body.time = Date.now();
|
||||||
|
try {
|
||||||
|
fs.writeFileSync(
|
||||||
|
`./notes/${hash}.json`,
|
||||||
|
cryptojs.AES.encrypt(
|
||||||
|
JSON.stringify(req.body),
|
||||||
|
process.env.KEY
|
||||||
|
).toString()
|
||||||
|
);
|
||||||
|
res.send({ id: hash });
|
||||||
|
} catch {
|
||||||
|
res.status(500).send("Failed to write file");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
res.status(403).send("Invalid body!");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
app.get("/get-note/:delorno/:id", function (req, res) {
|
||||||
|
let path = `./notes/${req.params.id}.json`;
|
||||||
|
try {
|
||||||
|
let data = JSON.parse(
|
||||||
|
cryptojs.AES.decrypt(
|
||||||
|
fs.readFileSync(path, "utf-8"),
|
||||||
|
process.env.KEY
|
||||||
|
).toString(cryptojs.enc.Utf8)
|
||||||
|
);
|
||||||
|
res.send(data);
|
||||||
|
if (req.params.delorno === "del") fs.unlinkSync(path);
|
||||||
|
} catch {
|
||||||
|
res.status(404).send("There is no such note");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
app.use(express.static("dist"));
|
||||||
|
|
||||||
|
app.get("*", function (req, res) {
|
||||||
|
res.sendFile(path.join(__dirname, "./dist", "index.html"));
|
||||||
|
});
|
||||||
|
|
||||||
|
app.listen(process.env.PORT, () => {
|
||||||
|
console.log(`Listening on port ${process.env.PORT}`);
|
||||||
|
});
|
15
note_validator.js
Normal file
15
note_validator.js
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
const Ajv = require("ajv");
|
||||||
|
const ajv = new Ajv();
|
||||||
|
const note_schema = {
|
||||||
|
type: "object",
|
||||||
|
properties: {
|
||||||
|
name: { type: "string", maxLength: 64 },
|
||||||
|
text: { type: "string", maxLength: 5000 },
|
||||||
|
},
|
||||||
|
required: ["name", "text"],
|
||||||
|
additionalProperties: false,
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = (data) => {
|
||||||
|
return ajv.validate(note_schema, data);
|
||||||
|
};
|
1249
package-lock.json
generated
1249
package-lock.json
generated
File diff suppressed because it is too large
Load diff
17
package.json
17
package.json
|
@ -1,12 +1,15 @@
|
||||||
{
|
{
|
||||||
"name": "anopaper",
|
"name": "anopaper",
|
||||||
"private": true,
|
"private": true,
|
||||||
"version": "0.0.0",
|
"version": "1.0.0",
|
||||||
"type": "module",
|
"author": "anopaper",
|
||||||
|
"license": "MIT",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "vite",
|
"dev": "vite",
|
||||||
"build": "vite build --emptyOutDir",
|
"build": "vite build --emptyOutDir",
|
||||||
"preview": "vite preview"
|
"preview": "vite preview",
|
||||||
|
"start": "node index",
|
||||||
|
"bstart": "npm run build && npm run start"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@heroicons/react": "^2.0.12",
|
"@heroicons/react": "^2.0.12",
|
||||||
|
@ -16,7 +19,13 @@
|
||||||
"react-router-dom": "^6.4.2",
|
"react-router-dom": "^6.4.2",
|
||||||
"react-syntax-highlighter": "^15.5.0",
|
"react-syntax-highlighter": "^15.5.0",
|
||||||
"rehype-mathjax": "^4.0.2",
|
"rehype-mathjax": "^4.0.2",
|
||||||
"remark-math": "^5.1.1"
|
"remark-math": "^5.1.1",
|
||||||
|
"ajv": "^8.11.0",
|
||||||
|
"body-parser": "^1.20.1",
|
||||||
|
"crypto-js": "^4.1.1",
|
||||||
|
"dotenv": "^16.0.3",
|
||||||
|
"express": "^4.18.2",
|
||||||
|
"js-sha3": "^0.8.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/react": "^18.0.17",
|
"@types/react": "^18.0.17",
|
||||||
|
|
|
@ -33,7 +33,7 @@ function CopyToClipboard(props) {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function CodeCopyBtn(props) {
|
function CodeCopyBtn({ text }) {
|
||||||
let [copied, setCopied] = useState(false);
|
let [copied, setCopied] = useState(false);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
@ -48,7 +48,7 @@ function CodeCopyBtn(props) {
|
||||||
<div
|
<div
|
||||||
className="code-copy-btn"
|
className="code-copy-btn"
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
navigator.clipboard.writeText(props.children[0].props.children[0]);
|
navigator.clipboard.writeText(text);
|
||||||
setCopied(true);
|
setCopied(true);
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
|
|
|
@ -12,14 +12,19 @@ let theme = window.matchMedia("(prefers-color-scheme: dark)").matches
|
||||||
: "light";
|
: "light";
|
||||||
|
|
||||||
function CodeBlock(props) {
|
function CodeBlock(props) {
|
||||||
return (
|
let text = props.children[0];
|
||||||
<SyntaxHighlighter
|
let oneline = text.indexOf("\n") <= 1;
|
||||||
className={`md-code ${props.className}`}
|
if (oneline) {
|
||||||
style={theme == "light" ? github : darcula}
|
return <code className="md-code">{text}</code>;
|
||||||
>
|
} else
|
||||||
{props.children[0]}
|
return (
|
||||||
</SyntaxHighlighter>
|
<SyntaxHighlighter
|
||||||
);
|
className={`md-code ${props.className}`}
|
||||||
|
style={theme == "light" ? github : darcula}
|
||||||
|
>
|
||||||
|
{text}
|
||||||
|
</SyntaxHighlighter>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function RenderMarkdown(props) {
|
function RenderMarkdown(props) {
|
||||||
|
@ -37,9 +42,12 @@ function RenderMarkdown(props) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function Pre({ children }) {
|
function Pre({ children }) {
|
||||||
|
let text = children[0].props.children[0];
|
||||||
|
let oneline = text.indexOf("\n") <= 1;
|
||||||
|
console.log(oneline);
|
||||||
return (
|
return (
|
||||||
<pre className="blog-pre">
|
<pre className={oneline ? "" : "blog-pre"}>
|
||||||
<CodeCopyBtn>{children}</CodeCopyBtn>
|
{!oneline && <CodeCopyBtn text={text} />}
|
||||||
{children}
|
{children}
|
||||||
</pre>
|
</pre>
|
||||||
);
|
);
|
||||||
|
|
|
@ -3,41 +3,45 @@ import { ChevronDoubleRightIcon } from "@heroicons/react/24/outline";
|
||||||
import printDate from "../components/utils";
|
import printDate from "../components/utils";
|
||||||
|
|
||||||
function Notes() {
|
function Notes() {
|
||||||
return (
|
let notes = Object.entries(localStorage.getObj("Notes"))
|
||||||
<div>
|
.sort((a, b) => {
|
||||||
{Object.entries(localStorage.getObj("Notes"))
|
return b[1].time - a[1].time;
|
||||||
.sort((a, b) => {
|
})
|
||||||
return b[1].time - a[1].time;
|
.map((val) => {
|
||||||
})
|
return (
|
||||||
.map((val) => {
|
<div
|
||||||
return (
|
className="grid grid-cols-1 lg:grid-cols-2 border border-blue-300 rounded-lg m-2 p-2 justify-items-start"
|
||||||
<div
|
key={val[0]}
|
||||||
className="grid grid-cols-1 lg:grid-cols-2 border border-blue-300 rounded-lg m-2 p-2 justify-items-start"
|
>
|
||||||
key={val[0]}
|
<div className="font-medium leading-tight text-4xl mt-0 mb-2">
|
||||||
>
|
{val[1].name}
|
||||||
<div className="font-medium leading-tight text-4xl mt-0 mb-2">
|
</div>
|
||||||
{val[1].name}
|
<div className="grid grid-cols-1 lg:grid-cols-2 justify-self-center lg:justify-self-end">
|
||||||
</div>
|
<div className="text-center">{printDate(val[1].time)}</div>
|
||||||
<div className="grid grid-cols-1 lg:grid-cols-2 justify-self-center lg:justify-self-end">
|
<div className="">
|
||||||
<div className="text-center">{printDate(val[1].time)}</div>
|
<Button className="" href={`/notes/${val[0]}`}>
|
||||||
<div className="">
|
<IconWithText
|
||||||
<Button className="" href={`/notes/${val[0]}`}>
|
reverse={true}
|
||||||
<IconWithText
|
icon={
|
||||||
reverse={true}
|
<ChevronDoubleRightIcon className="transform translate-z-0 h-7 w-7" />
|
||||||
icon={
|
}
|
||||||
<ChevronDoubleRightIcon className="transform translate-z-0 h-7 w-7" />
|
>
|
||||||
}
|
Перейти
|
||||||
>
|
</IconWithText>
|
||||||
Перейти
|
</Button>
|
||||||
</IconWithText>
|
|
||||||
</Button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
);
|
</div>
|
||||||
})}
|
</div>
|
||||||
</div>
|
);
|
||||||
);
|
});
|
||||||
|
|
||||||
|
if (notes.length === 0)
|
||||||
|
return (
|
||||||
|
<div className="md">
|
||||||
|
<h3>Заметок пока нет</h3>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
return notes;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default Notes;
|
export default Notes;
|
||||||
|
|
|
@ -5,6 +5,6 @@ import react from "@vitejs/plugin-react";
|
||||||
export default defineConfig({
|
export default defineConfig({
|
||||||
plugins: [react()],
|
plugins: [react()],
|
||||||
build: {
|
build: {
|
||||||
outDir: "D:/node-js/anopaper-server/public",
|
outDir: "./dist",
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
Loading…
Reference in a new issue