Skip to content

Commit 0b83d84

Browse files
committed
refactor: start rewrite
1 parent b77c3f6 commit 0b83d84

26 files changed

+7767
-7885
lines changed

.eslintrc.js

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -143,15 +143,13 @@ module.exports = {
143143
"@typescript-eslint/member-ordering": "warn",
144144
"@typescript-eslint/no-confusing-non-null-assertion": "warn",
145145
"@typescript-eslint/no-confusing-void-expression": "warn",
146-
"@typescript-eslint/no-duplicate-imports": "warn",
147146
"@typescript-eslint/no-explicit-any": "off",
148147
"@typescript-eslint/no-extraneous-class": "warn",
149148
"@typescript-eslint/no-implied-eval": "off",
150149
"@typescript-eslint/no-loop-func": "warn",
151150
"@typescript-eslint/no-loss-of-precision": "warn",
152151
"@typescript-eslint/no-misused-promises": "off",
153152
"@typescript-eslint/no-non-null-assertion": "off",
154-
"@typescript-eslint/no-parameter-properties": "warn",
155153
"@typescript-eslint/no-shadow": "warn",
156154
"@typescript-eslint/no-throw-literal": "warn",
157155
"@typescript-eslint/no-unnecessary-boolean-literal-compare": "warn",
@@ -174,7 +172,6 @@ module.exports = {
174172
"@typescript-eslint/require-await": "off",
175173
"@typescript-eslint/return-await": "warn",
176174
"@typescript-eslint/strict-boolean-expressions": "warn",
177-
"@typescript-eslint/sort-type-union-intersection-members": "warn",
178175
"@typescript-eslint/switch-exhaustiveness-check": "warn",
179176
"@typescript-eslint/unified-signatures": "warn",
180177
},

CODE_OF_CONDUCT.md

Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
# Contributor Covenant Code of Conduct
2+
3+
## Our Pledge
4+
5+
We as members, contributors, and leaders pledge to make participation in our
6+
community a harassment-free experience for everyone, regardless of age, body
7+
size, visible or invisible disability, ethnicity, sex characteristics, gender
8+
identity and expression, level of experience, education, socio-economic status,
9+
nationality, personal appearance, race, religion, or sexual identity
10+
and orientation.
11+
12+
We pledge to act and interact in ways that contribute to an open, welcoming,
13+
diverse, inclusive, and healthy community.
14+
15+
## Our Standards
16+
17+
Examples of behavior that contributes to a positive environment for our
18+
community include:
19+
20+
* Demonstrating empathy and kindness toward other people
21+
* Being respectful of differing opinions, viewpoints, and experiences
22+
* Giving and gracefully accepting constructive feedback
23+
* Accepting responsibility and apologizing to those affected by our mistakes,
24+
and learning from the experience
25+
* Focusing on what is best not just for us as individuals, but for the
26+
overall community
27+
28+
Examples of unacceptable behavior include:
29+
30+
* The use of sexualized language or imagery, and sexual attention or
31+
advances of any kind
32+
* Trolling, insulting or derogatory comments, and personal or political attacks
33+
* Public or private harassment
34+
* Publishing others' private information, such as a physical or email
35+
address, without their explicit permission
36+
* Other conduct which could reasonably be considered inappropriate in a
37+
professional setting
38+
39+
## Enforcement Responsibilities
40+
41+
Community leaders are responsible for clarifying and enforcing our standards of
42+
acceptable behavior and will take appropriate and fair corrective action in
43+
response to any behavior that they deem inappropriate, threatening, offensive,
44+
or harmful.
45+
46+
Community leaders have the right and responsibility to remove, edit, or reject
47+
comments, commits, code, wiki edits, issues, and other contributions that are
48+
not aligned to this Code of Conduct, and will communicate reasons for moderation
49+
decisions when appropriate.
50+
51+
## Scope
52+
53+
This Code of Conduct applies within all community spaces, and also applies when
54+
an individual is officially representing the community in public spaces.
55+
Examples of representing our community include using an official e-mail address,
56+
posting via an official social media account, or acting as an appointed
57+
representative at an online or offline event.
58+
59+
## Enforcement
60+
61+
Instances of abusive, harassing, or otherwise unacceptable behavior may be
62+
reported to the community leaders responsible for enforcement at
63+
maxtrombdt@gmail.com.
64+
All complaints will be reviewed and investigated promptly and fairly.
65+
66+
All community leaders are obligated to respect the privacy and security of the
67+
reporter of any incident.
68+
69+
## Enforcement Guidelines
70+
71+
Community leaders will follow these Community Impact Guidelines in determining
72+
the consequences for any action they deem in violation of this Code of Conduct:
73+
74+
### 1. Correction
75+
76+
**Community Impact**: Use of inappropriate language or other behavior deemed
77+
unprofessional or unwelcome in the community.
78+
79+
**Consequence**: A private, written warning from community leaders, providing
80+
clarity around the nature of the violation and an explanation of why the
81+
behavior was inappropriate. A public apology may be requested.
82+
83+
### 2. Warning
84+
85+
**Community Impact**: A violation through a single incident or series
86+
of actions.
87+
88+
**Consequence**: A warning with consequences for continued behavior. No
89+
interaction with the people involved, including unsolicited interaction with
90+
those enforcing the Code of Conduct, for a specified period of time. This
91+
includes avoiding interactions in community spaces as well as external channels
92+
like social media. Violating these terms may lead to a temporary or
93+
permanent ban.
94+
95+
### 3. Temporary Ban
96+
97+
**Community Impact**: A serious violation of community standards, including
98+
sustained inappropriate behavior.
99+
100+
**Consequence**: A temporary ban from any sort of interaction or public
101+
communication with the community for a specified period of time. No public or
102+
private interaction with the people involved, including unsolicited interaction
103+
with those enforcing the Code of Conduct, is allowed during this period.
104+
Violating these terms may lead to a permanent ban.
105+
106+
### 4. Permanent Ban
107+
108+
**Community Impact**: Demonstrating a pattern of violation of community
109+
standards, including sustained inappropriate behavior, harassment of an
110+
individual, or aggression toward or disparagement of classes of individuals.
111+
112+
**Consequence**: A permanent ban from any sort of public interaction within
113+
the community.
114+
115+
## Attribution
116+
117+
This Code of Conduct is adapted from the [Contributor Covenant][homepage],
118+
version 2.0, available at
119+
https://www.contributor-covenant.org/version/2/0/code_of_conduct.html.
120+
121+
Community Impact Guidelines were inspired by [Mozilla's code of conduct
122+
enforcement ladder](https://github.com/mozilla/diversity).
123+
124+
[homepage]: https://www.contributor-covenant.org
125+
126+
For answers to common questions about this code of conduct, see the FAQ at
127+
https://www.contributor-covenant.org/faq. Translations are available at
128+
https://www.contributor-covenant.org/translations.
File renamed without changes.

app/FilePreview.tsx

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
import { faDownload } from "@fortawesome/free-solid-svg-icons";
2+
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
3+
import formatBytes from "../lib/formatBytes";
4+
import type { FileOptions } from "../types";
5+
import DateComponent from "./DateComponent";
6+
7+
const FilePreview = ({ fileData: { date, name, size }, last }: FileOptions) => (
8+
<li className="break-all flex justify-between">
9+
<div className="flex flex-col">
10+
<a href={`/api/files/${name}`}>
11+
{name} ({formatBytes(size)})
12+
</a>
13+
<small className="opacity-50">
14+
<DateComponent timestamp={date} />
15+
</small>
16+
</div>
17+
<a
18+
className="w-10 h-10 p-2 rounded-lg hover:bg-zinc-200 dark:hover:bg-zinc-800 hover:bg-opacity-80 dark:hover:bg-opacity-80"
19+
href={`/api/files/${name}?download=true`}
20+
>
21+
<FontAwesomeIcon icon={faDownload} />
22+
</a>
23+
{!last && <hr />}
24+
</li>
25+
);
26+
27+
export default FilePreview;

app/FilesList.tsx

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
import { memo } from "react";
2+
import type { Files } from "../types";
3+
import FilePreview from "./FilePreview";
4+
5+
const FilesList = async ({ files }: { files: Files }) =>
6+
files.length ? (
7+
<ul className="list-none p-0 m-0">
8+
{files.map((fileData, i) => (
9+
<FilePreview
10+
fileData={fileData}
11+
key={fileData.name}
12+
last={i === files.length - 1}
13+
/>
14+
))}
15+
</ul>
16+
) : (
17+
"Nessun file presente"
18+
);
19+
20+
export default memo(FilesList);

app/UploadComponents.tsx

Lines changed: 154 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,154 @@
1+
"use client";
2+
import ms from "ms";
3+
import { memo, useState } from "react";
4+
import formatBytes from "../lib/formatBytes";
5+
6+
const UploadComponents = () => {
7+
const [file, setFile] = useState<File>();
8+
const [upload, setUpload] = useState<{
9+
progress: number;
10+
total: number;
11+
}>();
12+
const [error, setError] = useState<string>();
13+
const [duration, setDuration] = useState<number>();
14+
const [speed, setSpeed] = useState<number>();
15+
const uploadFile = () => {
16+
if (upload) return;
17+
if (!file) {
18+
alert("Devi prima scegliere il file da condividere!");
19+
return;
20+
}
21+
setUpload({
22+
progress: 0,
23+
total: file.size,
24+
});
25+
setSpeed(undefined);
26+
setDuration(undefined);
27+
setError(undefined);
28+
const { value: password } = document.getElementById(
29+
"password"
30+
) as HTMLInputElement;
31+
const xhr = new XMLHttpRequest();
32+
let lastLoaded = 0,
33+
oldLoaded = 0;
34+
const interval = setInterval(() => {
35+
setSpeed(lastLoaded - oldLoaded);
36+
oldLoaded = lastLoaded;
37+
}, 1000);
38+
const startUploadTime = Date.now();
39+
const url = new URL(`${location.origin}/api/files/${file.name}`);
40+
41+
if (password) url.searchParams.set("password", password);
42+
xhr.open("POST", url);
43+
xhr.upload.addEventListener("progress", ({ loaded, total }) => {
44+
setUpload({
45+
progress: loaded,
46+
total,
47+
});
48+
lastLoaded = loaded;
49+
});
50+
xhr.addEventListener("load", () => {
51+
clearInterval(interval);
52+
switch (xhr.status) {
53+
case 200:
54+
setDuration(Date.now() - startUploadTime);
55+
break;
56+
case 500:
57+
setError("Il file non può essere caricato al momento");
58+
break;
59+
case 409:
60+
setError("Esiste già un file con questo nome");
61+
break;
62+
case 400:
63+
setError("Si è verificato un errore durante il caricamento dei dati");
64+
break;
65+
default:
66+
}
67+
});
68+
xhr.send(file);
69+
};
70+
71+
return (
72+
<>
73+
<div className="mt-8 ml-8">
74+
<label
75+
className="rounded px-5 py-3 cursor-pointer transition bg-zinc-200 dark:bg-zinc-800 hover:bg-zinc-300 dark:hover:bg-zinc-700 hover:bg-opacity-80 dark:hover:bg-opacity-80"
76+
htmlFor="file"
77+
>
78+
Choose file
79+
</label>
80+
<input
81+
type="file"
82+
accept="*/*"
83+
id="file"
84+
className="hidden"
85+
onChange={(e) => {
86+
const f = e.target.files?.[0];
87+
88+
if (f && f.size > 1e10)
89+
alert("Non puoi condividere file più grandi di 10GB!");
90+
else {
91+
setFile(f);
92+
setUpload(undefined);
93+
}
94+
}}
95+
/>
96+
<div className="ml-4 mr-8 mb-4 inline-block align-middle relative top-2 break-all">
97+
{file ? `${file.name} (${formatBytes(file.size)})` : ""}
98+
</div>
99+
</div>
100+
<div className="my-4 ml-8 mr-4 h-4">
101+
<label className="align-middle" htmlFor="password">
102+
Password (optional):
103+
</label>
104+
<input
105+
id="password"
106+
className="text-lg pl-2 align-middle ml-2 bg-zinc-200 dark:bg-zinc-800 text-inherit rounded"
107+
type="text"
108+
/>
109+
</div>
110+
<button
111+
className="py-3 px-5 rounded transition duration-500 bg-zinc-200 dark:bg-zinc-800 hover:bg-zinc-300 dark:hover:bg-zinc-700 hover:bg-opacity-80 dark:hover:bg-opacity-80 text-inherit border-none mx-auto my-8 enabled:hover:scale-110 enabled:active:scale-95 disabled:cursor-not-allowed disabled:opacity-50 disabled:bg-zinc-200 dark:disabled:bg-zinc-800"
112+
onClick={uploadFile}
113+
disabled={!file}
114+
>
115+
Invia file
116+
</button>
117+
{upload && (
118+
<div className="mb-4 mx-auto w-5/6 text-center">
119+
<span>
120+
{error ??
121+
(upload.progress === upload.total
122+
? `Caricamento completato in ${ms(
123+
duration ?? 1000
124+
)} (${formatBytes(
125+
(upload.total * 1000) / (duration ?? 1000)
126+
)}/s)`
127+
: `Caricando ${formatBytes(
128+
upload.progress,
129+
false
130+
)}/${formatBytes(upload.total, false)} (${Math.round(
131+
(upload.progress / upload.total) * 100
132+
)}%) - ${formatBytes(speed ?? upload.progress, false)}/s`)}
133+
</span>
134+
<div className="bg-zinc-300 dark:bg-zinc-700 bg-opacity-80 dark:bg-opacity-80 rounded-md transition-all duration-500 w-full mt-2">
135+
<div
136+
className={`bg-cyan-500 h-3 rounded-md transition-all ${
137+
error !== undefined
138+
? "w-full bg-red-500"
139+
: upload.progress === upload.total
140+
? "bg-green-500"
141+
: ""
142+
}`}
143+
style={{
144+
width: error! || `${(upload.progress / upload.total) * 100}%`,
145+
}}
146+
></div>
147+
</div>
148+
</div>
149+
)}
150+
</>
151+
);
152+
};
153+
154+
export default memo(UploadComponents);

app/global.css

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
a:hover {
2+
text-decoration: underline;
3+
color: inherit;
4+
}

0 commit comments

Comments
 (0)