mirror of
https://github.com/MedzikUser/HomeDisk.git
synced 2024-08-14 21:46:53 +00:00
delete website (move to another repository)
This commit is contained in:
parent
50ed01597f
commit
5c355cfdaf
44 changed files with 15 additions and 1656 deletions
8
.github/workflows/build-release-binaries.yml
vendored
8
.github/workflows/build-release-binaries.yml
vendored
|
@ -2,14 +2,10 @@ name: Build release binaries (and publish them if this is a tag)
|
||||||
|
|
||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
paths:
|
branches:
|
||||||
- '**'
|
- main
|
||||||
- '!website/**'
|
|
||||||
|
|
||||||
# pull_request:
|
# pull_request:
|
||||||
# paths:
|
|
||||||
# - '**'
|
|
||||||
# - '!website/**'
|
|
||||||
|
|
||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
|
|
||||||
|
|
38
.github/workflows/rust.yml
vendored
38
.github/workflows/rust.yml
vendored
|
@ -4,14 +4,8 @@ on:
|
||||||
push:
|
push:
|
||||||
branches:
|
branches:
|
||||||
- main
|
- main
|
||||||
paths:
|
|
||||||
- '**'
|
|
||||||
- '!website/**'
|
|
||||||
|
|
||||||
pull_request:
|
pull_request:
|
||||||
paths:
|
|
||||||
- '**'
|
|
||||||
- '!website/**'
|
|
||||||
|
|
||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
|
|
||||||
|
@ -49,7 +43,7 @@ jobs:
|
||||||
path: |
|
path: |
|
||||||
~/.cargo/registry/cache/
|
~/.cargo/registry/cache/
|
||||||
target/
|
target/
|
||||||
key: build-${{ runner.os }}-${{ matrix.rust }}-rust-${{ steps.rust-toolchain.outputs.rustc_hash }}-${{ hashFiles('**/Cargo.lock') }}
|
key: ${{ runner.os }}-${{ matrix.rust }}-${{ steps.rust-toolchain.outputs.rustc_hash }}-${{ hashFiles('**/Cargo.lock') }}
|
||||||
|
|
||||||
- name: cargo build
|
- name: cargo build
|
||||||
uses: actions-rs/cargo@v1
|
uses: actions-rs/cargo@v1
|
||||||
|
@ -62,36 +56,6 @@ jobs:
|
||||||
command: clippy
|
command: clippy
|
||||||
args: --no-deps -- -D warnings
|
args: --no-deps -- -D warnings
|
||||||
|
|
||||||
test:
|
|
||||||
strategy:
|
|
||||||
fail-fast: false
|
|
||||||
matrix:
|
|
||||||
rust: [stable, nightly]
|
|
||||||
|
|
||||||
name: ${{ matrix.rust }} test
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- name: Checkout
|
|
||||||
uses: actions/checkout@v3
|
|
||||||
|
|
||||||
- name: Setup Rust toolchain
|
|
||||||
id: rust-toolchain
|
|
||||||
uses: actions-rs/toolchain@v1
|
|
||||||
with:
|
|
||||||
profile: minimal
|
|
||||||
toolchain: ${{ matrix.rust }}
|
|
||||||
override: true
|
|
||||||
|
|
||||||
- name: Cache
|
|
||||||
uses: actions/cache@v3
|
|
||||||
id: cache
|
|
||||||
with:
|
|
||||||
path: |
|
|
||||||
~/.cargo/registry/cache/
|
|
||||||
target/
|
|
||||||
key: test-${{ runner.os }}-${{ matrix.rust }}-rust-${{ steps.rust-toolchain.outputs.rustc_hash }}-${{ hashFiles('**/Cargo.lock') }}
|
|
||||||
|
|
||||||
- name: cargo test
|
- name: cargo test
|
||||||
uses: actions-rs/cargo@v1
|
uses: actions-rs/cargo@v1
|
||||||
with:
|
with:
|
||||||
|
|
70
.github/workflows/website.yml
vendored
70
.github/workflows/website.yml
vendored
|
@ -1,70 +0,0 @@
|
||||||
name: Website
|
|
||||||
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
branches:
|
|
||||||
- main
|
|
||||||
paths:
|
|
||||||
- 'website/**'
|
|
||||||
|
|
||||||
pull_request:
|
|
||||||
paths:
|
|
||||||
- 'website/**'
|
|
||||||
|
|
||||||
workflow_dispatch:
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
build:
|
|
||||||
name: Next.js Build
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- name: Checkout
|
|
||||||
uses: actions/checkout@v3
|
|
||||||
|
|
||||||
- name: Setup Node
|
|
||||||
uses: actions/setup-node@v3
|
|
||||||
|
|
||||||
- name: Install pnpm
|
|
||||||
uses: pnpm/action-setup@v2
|
|
||||||
id: pnpm-install
|
|
||||||
with:
|
|
||||||
version: 7
|
|
||||||
run_install: false
|
|
||||||
|
|
||||||
- name: Get pnpm store directory
|
|
||||||
id: pnpm-cache
|
|
||||||
run: |
|
|
||||||
echo "::set-output name=pnpm_cache_dir::$(pnpm store path)"
|
|
||||||
|
|
||||||
- name: Cache pnpm
|
|
||||||
uses: actions/cache@v3
|
|
||||||
with:
|
|
||||||
path: ${{ steps.pnpm-cache.outputs.pnpm_cache_dir }}
|
|
||||||
key: ${{ runner.os }}-pnpm-store-${{ hashFiles('website/pnpm-lock.yaml') }}
|
|
||||||
restore-keys: |
|
|
||||||
${{ runner.os }}-pnpm-store-
|
|
||||||
|
|
||||||
- name: Cache Next.js
|
|
||||||
uses: actions/cache@v3
|
|
||||||
with:
|
|
||||||
path: |
|
|
||||||
${{ github.workspace }}/website/.next/cache
|
|
||||||
key: ${{ runner.os }}-nextjs-${{ hashFiles('website/pnpm-lock.yaml') }}-${{ hashFiles('website/**.[jt]s', 'website/**.[jt]sx') }}
|
|
||||||
restore-keys: |
|
|
||||||
${{ runner.os }}-nextjs-${{ hashFiles('website/pnpm-lock.yaml') }}-
|
|
||||||
|
|
||||||
- name: Install dependencies
|
|
||||||
run: pnpm install --prefix website
|
|
||||||
|
|
||||||
- name: Build page
|
|
||||||
run: pnpm --prefix website run build
|
|
||||||
|
|
||||||
- name: Export page
|
|
||||||
run: pnpm --prefix website run export
|
|
||||||
|
|
||||||
- name: Upload artifact
|
|
||||||
uses: actions/upload-artifact@v3
|
|
||||||
with:
|
|
||||||
name: website-static
|
|
||||||
path: website/out/**
|
|
40
README.md
40
README.md
|
@ -1,47 +1,31 @@
|
||||||
# HomeDisk cloud server
|
# HomeDisk cloud server
|
||||||
|
|
||||||
[![docs-rs]](https://homedisk-doc.vercel.app)
|
|
||||||
[![total-lines]](https://github.com/MedzikUser/HomeDisk)
|
|
||||||
[![code-size]](https://github.com/MedzikUser/HomeDisk)
|
|
||||||
[![CI]](https://github.com/MedzikUser/HomeDisk/actions/workflows/rust.yml)
|
|
||||||
|
|
||||||
[docs-rs]: https://img.shields.io/badge/docs.rs-66c2a5?style=for-the-badge&labelColor=555555&logo=docs.rs
|
[docs-rs]: https://img.shields.io/badge/docs.rs-66c2a5?style=for-the-badge&labelColor=555555&logo=docs.rs
|
||||||
[total-lines]: https://img.shields.io/tokei/lines/github/MedzikUser/HomeDisk?style=for-the-badge&logo=github&color=fede00
|
[total-lines]: https://img.shields.io/tokei/lines/github/MedzikUser/HomeDisk?style=for-the-badge&logo=github&color=fede00
|
||||||
[code-size]: https://img.shields.io/github/languages/code-size/MedzikUser/HomeDisk?style=for-the-badge&color=c8df52&logo=github
|
[code-size]: https://img.shields.io/github/languages/code-size/MedzikUser/HomeDisk?style=for-the-badge&color=c8df52&logo=github
|
||||||
[CI]: https://img.shields.io/github/workflow/status/MedzikUser/rust-crypto-utils/Rust/main?style=for-the-badge
|
[CI]: https://img.shields.io/github/workflow/status/MedzikUser/rust-crypto-utils/Rust/main?style=for-the-badge
|
||||||
|
|
||||||
![](https://i.imgur.com/fOtiSf7.png)
|
[home-screenshot]: https://cdn.medzik.xyz/fz4QGfS.png
|
||||||
|
[login-screenshot]: https://cdn.medzik.xyz/vo10bes.png
|
||||||
|
|
||||||
![](https://i.imgur.com/vLautmq.png)
|
[![docs-rs]](https://homedisk-doc.vercel.app)
|
||||||
|
[![total-lines]](https://github.com/MedzikUser/HomeDisk)
|
||||||
|
[![code-size]](https://github.com/MedzikUser/HomeDisk)
|
||||||
|
[![CI]](https://github.com/MedzikUser/HomeDisk/actions/workflows/rust.yml)
|
||||||
|
|
||||||
|
![home-screenshot]
|
||||||
|
![login-screenshot]
|
||||||
|
|
||||||
## 👨💻 Building
|
## 👨💻 Building
|
||||||
|
|
||||||
First clone the repository: `git clone git@github.com:MedzikUser/HomeDisk.git`
|
First clone the repository: `git clone https://github.com/MedzikUser/HomeDisk.git`
|
||||||
|
|
||||||
### Server
|
### Requirements
|
||||||
|
|
||||||
#### Requirements
|
|
||||||
- Rust
|
- Rust
|
||||||
|
|
||||||
To build run the command: `cargo build --release`
|
To build run the command: `cargo build --release`
|
||||||
|
|
||||||
The compiled binary can be found in `./target/release/cloud`
|
The compiled binary can be found in `./target/release/homedisk`
|
||||||
|
|
||||||
### Website
|
|
||||||
|
|
||||||
#### Requirements
|
|
||||||
- Node.js
|
|
||||||
- pnpm
|
|
||||||
|
|
||||||
Run these commands to build:
|
|
||||||
|
|
||||||
- Go to directory `./website`
|
|
||||||
- Install dependencies: `pnpm install`
|
|
||||||
- Build website: `pnpm run build`
|
|
||||||
- Export website to static HTML files: `pnpm run export` (Optional)
|
|
||||||
|
|
||||||
If you exported the page to HTML files, they are located in the `./out` directory,
|
|
||||||
if not, you can start the site with `pnpm run start`
|
|
||||||
|
|
||||||
## 🖴 Creating tables in a SQLite database
|
## 🖴 Creating tables in a SQLite database
|
||||||
|
|
||||||
|
|
|
@ -1,12 +0,0 @@
|
||||||
# EditorConfig is awesome: https://EditorConfig.org
|
|
||||||
|
|
||||||
# top-most EditorConfig file
|
|
||||||
root = true
|
|
||||||
|
|
||||||
[*]
|
|
||||||
indent_style = space
|
|
||||||
indent_size = 2
|
|
||||||
end_of_line = lf
|
|
||||||
charset = utf-8
|
|
||||||
trim_trailing_whitespace = true
|
|
||||||
insert_final_newline = false
|
|
|
@ -1,18 +0,0 @@
|
||||||
{
|
|
||||||
"extends": [
|
|
||||||
"eslint:recommended",
|
|
||||||
"next/core-web-vitals"
|
|
||||||
],
|
|
||||||
"rules": {
|
|
||||||
"semi": [
|
|
||||||
"warn",
|
|
||||||
"never"
|
|
||||||
],
|
|
||||||
"no-unused-vars": [
|
|
||||||
"warn"
|
|
||||||
],
|
|
||||||
"no-unused-expressions": [
|
|
||||||
"warn"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
34
website/.gitignore
vendored
34
website/.gitignore
vendored
|
@ -1,34 +0,0 @@
|
||||||
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
|
|
||||||
|
|
||||||
# dependencies
|
|
||||||
/node_modules
|
|
||||||
/.pnp
|
|
||||||
.pnp.js
|
|
||||||
|
|
||||||
# testing
|
|
||||||
/coverage
|
|
||||||
|
|
||||||
# next.js
|
|
||||||
/.next/
|
|
||||||
/out/
|
|
||||||
|
|
||||||
# production
|
|
||||||
/build
|
|
||||||
|
|
||||||
# misc
|
|
||||||
.DS_Store
|
|
||||||
*.pem
|
|
||||||
|
|
||||||
# debug
|
|
||||||
npm-debug.log*
|
|
||||||
yarn-debug.log*
|
|
||||||
yarn-error.log*
|
|
||||||
|
|
||||||
# local env files
|
|
||||||
.env.local
|
|
||||||
.env.development.local
|
|
||||||
.env.test.local
|
|
||||||
.env.production.local
|
|
||||||
|
|
||||||
# vercel
|
|
||||||
.vercel
|
|
|
@ -1,8 +0,0 @@
|
||||||
import axios from "axios"
|
|
||||||
import config from "../config"
|
|
||||||
|
|
||||||
const instance = axios.create({
|
|
||||||
baseURL: config.apiUrl,
|
|
||||||
})
|
|
||||||
|
|
||||||
export default instance
|
|
|
@ -1,34 +0,0 @@
|
||||||
import axios from './axios'
|
|
||||||
|
|
||||||
export default async function createDir(path: string, token: string): Promise<any> {
|
|
||||||
const request = axios.post("/fs/createdir", {
|
|
||||||
path
|
|
||||||
}, {
|
|
||||||
headers: {
|
|
||||||
Authorization: `Bearer ${token}`,
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
const response = request
|
|
||||||
.then(response => {
|
|
||||||
const { data } = response
|
|
||||||
return data
|
|
||||||
})
|
|
||||||
.catch(err => {
|
|
||||||
if (err.response?.data?.error_message) {
|
|
||||||
const error = err.response.data.error_message
|
|
||||||
|
|
||||||
if (error.toString() == "[object Object]") {
|
|
||||||
Object.keys(error).forEach(key => {
|
|
||||||
throw new Error(key)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
throw new Error(error)
|
|
||||||
}
|
|
||||||
|
|
||||||
throw new Error(err)
|
|
||||||
})
|
|
||||||
|
|
||||||
return response
|
|
||||||
}
|
|
|
@ -1,9 +0,0 @@
|
||||||
import list from "./list"
|
|
||||||
import login from "./login"
|
|
||||||
import register from "./register"
|
|
||||||
import upload from "./upload"
|
|
||||||
import createDir from "./create-directory"
|
|
||||||
|
|
||||||
const api = { list, login, register, upload, createDir }
|
|
||||||
|
|
||||||
export default api
|
|
|
@ -1,34 +0,0 @@
|
||||||
import axios from './axios'
|
|
||||||
|
|
||||||
export default async function list(path: string, token: string): Promise<any> {
|
|
||||||
const request = axios.post("/fs/list", {
|
|
||||||
path
|
|
||||||
}, {
|
|
||||||
headers: {
|
|
||||||
Authorization: `Bearer ${token}`,
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
const response = request
|
|
||||||
.then(response => {
|
|
||||||
const { data } = response
|
|
||||||
return data
|
|
||||||
})
|
|
||||||
.catch(err => {
|
|
||||||
if (err.response?.data?.error_message) {
|
|
||||||
const error = err.response.data.error_message
|
|
||||||
|
|
||||||
if (error.toString() == "[object Object]") {
|
|
||||||
Object.keys(error).forEach(key => {
|
|
||||||
throw new Error(key)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
throw new Error(error)
|
|
||||||
}
|
|
||||||
|
|
||||||
throw new Error(err)
|
|
||||||
})
|
|
||||||
|
|
||||||
return response
|
|
||||||
}
|
|
|
@ -1,32 +0,0 @@
|
||||||
import axios from './axios'
|
|
||||||
|
|
||||||
export default async function login(username: string, password: string): Promise<string> {
|
|
||||||
const request = axios.post("/auth/login", {
|
|
||||||
username,
|
|
||||||
password,
|
|
||||||
})
|
|
||||||
|
|
||||||
const response = request
|
|
||||||
.then(response => {
|
|
||||||
const { data } = response
|
|
||||||
|
|
||||||
return data.LoggedIn.access_token
|
|
||||||
})
|
|
||||||
.catch(err => {
|
|
||||||
if (err.response?.data?.error_message) {
|
|
||||||
const error = err.response.data.error_message
|
|
||||||
|
|
||||||
if (error.toString() == "[object Object]") {
|
|
||||||
Object.keys(error).forEach(key => {
|
|
||||||
throw new Error(key)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
throw new Error(error)
|
|
||||||
}
|
|
||||||
|
|
||||||
throw new Error(err)
|
|
||||||
})
|
|
||||||
|
|
||||||
return response
|
|
||||||
}
|
|
|
@ -1,32 +0,0 @@
|
||||||
import axios from './axios'
|
|
||||||
|
|
||||||
export default async function register(username: string, password: string): Promise<string> {
|
|
||||||
const request = axios.post("/auth/register", {
|
|
||||||
username,
|
|
||||||
password,
|
|
||||||
})
|
|
||||||
|
|
||||||
const response = request
|
|
||||||
.then(response => {
|
|
||||||
const { data } = response
|
|
||||||
|
|
||||||
return data.LoggedIn.access_token
|
|
||||||
})
|
|
||||||
.catch(err => {
|
|
||||||
if (err.response?.data?.error_message) {
|
|
||||||
const error = err.response.data.error_message
|
|
||||||
|
|
||||||
if (error.toString() == "[object Object]") {
|
|
||||||
Object.keys(error).forEach(key => {
|
|
||||||
throw new Error(key)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
throw new Error(error)
|
|
||||||
}
|
|
||||||
|
|
||||||
throw new Error(err)
|
|
||||||
})
|
|
||||||
|
|
||||||
return response
|
|
||||||
}
|
|
|
@ -1,32 +0,0 @@
|
||||||
import axios from './axios'
|
|
||||||
|
|
||||||
export default async function list(path: string, formData: FormData, token: string): Promise<any> {
|
|
||||||
const request = axios.post(`/fs/upload?path=${path}`, formData, {
|
|
||||||
headers: {
|
|
||||||
Authorization: `Bearer ${token}`,
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
const response = request
|
|
||||||
.then(response => {
|
|
||||||
const { data } = response
|
|
||||||
return data
|
|
||||||
})
|
|
||||||
.catch(err => {
|
|
||||||
if (err.response?.data?.error_message) {
|
|
||||||
const error = err.response.data.error_message
|
|
||||||
|
|
||||||
if (error.toString() == "[object Object]") {
|
|
||||||
Object.keys(error).forEach(key => {
|
|
||||||
throw new Error(key)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
throw new Error(error)
|
|
||||||
}
|
|
||||||
|
|
||||||
throw new Error(err)
|
|
||||||
})
|
|
||||||
|
|
||||||
return response
|
|
||||||
}
|
|
|
@ -1,9 +0,0 @@
|
||||||
import { Button } from "@mui/material"
|
|
||||||
import styled from "styled-components"
|
|
||||||
|
|
||||||
const SubmitButton = styled(Button)`
|
|
||||||
margin-top: 1rem;
|
|
||||||
align-content: "center";
|
|
||||||
`
|
|
||||||
|
|
||||||
export default SubmitButton
|
|
|
@ -1,7 +0,0 @@
|
||||||
import styled from "styled-components"
|
|
||||||
|
|
||||||
const ErrorComponent = styled.div`
|
|
||||||
color: ${({ theme }) => theme.colors.error};
|
|
||||||
`
|
|
||||||
|
|
||||||
export default ErrorComponent
|
|
|
@ -1,35 +0,0 @@
|
||||||
import styled from "styled-components"
|
|
||||||
|
|
||||||
const Title = styled.h1`
|
|
||||||
margin: 0;
|
|
||||||
line-height: 1.15;
|
|
||||||
font-size: 2rem;
|
|
||||||
text-align: center;
|
|
||||||
margin-bottom: 1rem;
|
|
||||||
|
|
||||||
a {
|
|
||||||
color: ${({ theme }) => theme.pages.index.title.a};
|
|
||||||
text-decoration: none;
|
|
||||||
animation: animate 1.5s linear infinite;
|
|
||||||
}
|
|
||||||
|
|
||||||
@keyframes animate {
|
|
||||||
0% {
|
|
||||||
opacity: 0;
|
|
||||||
}
|
|
||||||
50% {
|
|
||||||
opacity: 1;
|
|
||||||
}
|
|
||||||
100% {
|
|
||||||
opacity: 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
a:hover,
|
|
||||||
a:focus,
|
|
||||||
a:active {
|
|
||||||
text-decoration: underline;
|
|
||||||
}
|
|
||||||
`
|
|
||||||
|
|
||||||
export default Title
|
|
|
@ -1,14 +0,0 @@
|
||||||
import styled from 'styled-components'
|
|
||||||
|
|
||||||
const Container = styled.div`
|
|
||||||
height: 100%;
|
|
||||||
min-height: 100vh;
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
justify-content: center;
|
|
||||||
align-items: center;
|
|
||||||
background-color: ${({ theme }) => theme.colors.background};
|
|
||||||
color: ${({ theme }) => theme.colors.color};
|
|
||||||
`
|
|
||||||
|
|
||||||
export default Container
|
|
|
@ -1,33 +0,0 @@
|
||||||
import { GitHub } from "@mui/icons-material"
|
|
||||||
import { IconButton } from "@mui/material"
|
|
||||||
import styled from "styled-components"
|
|
||||||
import { links } from "../config"
|
|
||||||
|
|
||||||
const StyledFooter = styled.footer`
|
|
||||||
width: 100%;
|
|
||||||
height: 100px;
|
|
||||||
border-top: 1px solid ${({ theme }) => theme.footer.borderTop};
|
|
||||||
display: flex;
|
|
||||||
justify-content: center;
|
|
||||||
align-items: center;
|
|
||||||
background-color: ${({ theme }) => theme.colors.background};
|
|
||||||
color: ${({ theme }) => theme.colors.color};
|
|
||||||
|
|
||||||
a {
|
|
||||||
display: flex;
|
|
||||||
justify-content: center;
|
|
||||||
align-items: cente;
|
|
||||||
}
|
|
||||||
`
|
|
||||||
|
|
||||||
export default function Footer() {
|
|
||||||
return (
|
|
||||||
<StyledFooter>
|
|
||||||
<IconButton color="inherit">
|
|
||||||
<a href={links.github} target="_blank" rel="noreferrer" color="inherit">
|
|
||||||
<GitHub />
|
|
||||||
</a>
|
|
||||||
</IconButton>
|
|
||||||
</StyledFooter>
|
|
||||||
)
|
|
||||||
}
|
|
|
@ -1,45 +0,0 @@
|
||||||
import { faMoon, faSignOut, faSun } from "@fortawesome/free-solid-svg-icons"
|
|
||||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"
|
|
||||||
import { RocketLaunch } from "@mui/icons-material"
|
|
||||||
import { AppBar, IconButton, Link, Stack, Toolbar, Typography } from "@mui/material"
|
|
||||||
|
|
||||||
export default function Footer({ toggleTheme, theme}: Props) {
|
|
||||||
return (
|
|
||||||
<AppBar
|
|
||||||
position="static"
|
|
||||||
sx={{ marginBottom: "calc(2% + 10px)" }}
|
|
||||||
>
|
|
||||||
<Toolbar>
|
|
||||||
<Link href="/" color="inherit">
|
|
||||||
<IconButton
|
|
||||||
size="large"
|
|
||||||
edge="start"
|
|
||||||
color="inherit"
|
|
||||||
aria-label="logo"
|
|
||||||
>
|
|
||||||
<RocketLaunch />
|
|
||||||
</IconButton>
|
|
||||||
</Link>
|
|
||||||
|
|
||||||
<Typography variant="h6" component="div" sx={{ flexGrow: 1 }}>
|
|
||||||
HomeDisk
|
|
||||||
</Typography>
|
|
||||||
|
|
||||||
<Stack direction="row" spacing={2}>
|
|
||||||
<IconButton onClick={() => toggleTheme()}>
|
|
||||||
<FontAwesomeIcon icon={theme == "light" ? faMoon : faSun} />
|
|
||||||
</IconButton>
|
|
||||||
|
|
||||||
<IconButton>
|
|
||||||
<FontAwesomeIcon icon={faSignOut} />
|
|
||||||
</IconButton>
|
|
||||||
</Stack>
|
|
||||||
</Toolbar>
|
|
||||||
</AppBar>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
type Props = {
|
|
||||||
toggleTheme: () => any,
|
|
||||||
theme: string
|
|
||||||
}
|
|
|
@ -1,49 +0,0 @@
|
||||||
import styled from "styled-components"
|
|
||||||
|
|
||||||
const Card = styled.div`
|
|
||||||
margin: 1rem;
|
|
||||||
padding: 1.5rem;
|
|
||||||
text-align: left;
|
|
||||||
color: inherit;
|
|
||||||
text-decoration: none;
|
|
||||||
border: 1px solid #eaeaea;
|
|
||||||
border-radius: 10px;
|
|
||||||
transition: color 0.15s ease, border-color 0.15s ease;
|
|
||||||
max-width: 300px;
|
|
||||||
|
|
||||||
:hover,
|
|
||||||
:focus,
|
|
||||||
:active {
|
|
||||||
color: #0070f3;
|
|
||||||
border-color: #0070f3;
|
|
||||||
}
|
|
||||||
|
|
||||||
h2 {
|
|
||||||
margin: 0 0 1rem 0;
|
|
||||||
font-size: 1.5rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
p {
|
|
||||||
margin: 0;
|
|
||||||
font-size: 1.25rem;
|
|
||||||
line-height: 1.5;
|
|
||||||
}
|
|
||||||
`
|
|
||||||
|
|
||||||
const CardSignIn = styled.a`
|
|
||||||
color: ${({ theme }) => theme.pages.index.cards.signin};
|
|
||||||
`
|
|
||||||
|
|
||||||
const CardRegister = styled.a`
|
|
||||||
color: ${({ theme }) => theme.pages.index.cards.register};
|
|
||||||
`
|
|
||||||
|
|
||||||
const CardFiles = styled.a`
|
|
||||||
color: ${({ theme }) => theme.pages.index.cards.files};
|
|
||||||
`
|
|
||||||
|
|
||||||
const CardSettings = styled.a`
|
|
||||||
color: ${({ theme }) => theme.pages.index.cards.settings};
|
|
||||||
`
|
|
||||||
|
|
||||||
export { Card, CardSignIn, CardRegister, CardFiles, CardSettings }
|
|
|
@ -1,9 +0,0 @@
|
||||||
import styled from "styled-components"
|
|
||||||
|
|
||||||
const Description = styled.p`
|
|
||||||
line-height: 1.5;
|
|
||||||
font-size: 1.5rem;
|
|
||||||
text-align: center;
|
|
||||||
`
|
|
||||||
|
|
||||||
export default Description
|
|
|
@ -1,11 +0,0 @@
|
||||||
import styled from "styled-components"
|
|
||||||
|
|
||||||
const Grid = styled.div`
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
flex-wrap: wrap;
|
|
||||||
max-width: 800px;
|
|
||||||
`
|
|
||||||
|
|
||||||
export default Grid
|
|
|
@ -1,34 +0,0 @@
|
||||||
import styled from "styled-components"
|
|
||||||
|
|
||||||
const Title = styled.h1`
|
|
||||||
margin: 0;
|
|
||||||
line-height: 1.15;
|
|
||||||
font-size: 4rem;
|
|
||||||
text-align: center;
|
|
||||||
|
|
||||||
a {
|
|
||||||
color: ${({ theme }) => theme.pages.index.title.a};
|
|
||||||
text-decoration: none;
|
|
||||||
animation: animate 1.5s linear infinite;
|
|
||||||
}
|
|
||||||
|
|
||||||
@keyframes animate {
|
|
||||||
0% {
|
|
||||||
opacity: 0;
|
|
||||||
}
|
|
||||||
50% {
|
|
||||||
opacity: 1;
|
|
||||||
}
|
|
||||||
100% {
|
|
||||||
opacity: 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
a:hover,
|
|
||||||
a:focus,
|
|
||||||
a:active {
|
|
||||||
text-decoration: underline;
|
|
||||||
}
|
|
||||||
`
|
|
||||||
|
|
||||||
export default Title
|
|
|
@ -1,11 +0,0 @@
|
||||||
import styled from 'styled-components'
|
|
||||||
|
|
||||||
const Main = styled.main`
|
|
||||||
flex: 1;
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
justify-content: center;
|
|
||||||
align-items: center;
|
|
||||||
`
|
|
||||||
|
|
||||||
export default Main
|
|
|
@ -1,8 +0,0 @@
|
||||||
import styled from "styled-components"
|
|
||||||
|
|
||||||
const IconDiv = styled.div`
|
|
||||||
padding-right: 5px;
|
|
||||||
padding-left: 5px;
|
|
||||||
`
|
|
||||||
|
|
||||||
export default IconDiv
|
|
|
@ -1,9 +0,0 @@
|
||||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"
|
|
||||||
import styled from "styled-components"
|
|
||||||
|
|
||||||
const Icon = styled(FontAwesomeIcon)`
|
|
||||||
padding-right: 5px;
|
|
||||||
padding-left: 5px;
|
|
||||||
`
|
|
||||||
|
|
||||||
export default Icon
|
|
|
@ -1,71 +0,0 @@
|
||||||
import React, { useState } from 'react'
|
|
||||||
import { Backdrop, Box, Button, Fade, Link, Modal, TextField } from "@mui/material"
|
|
||||||
import { useCookies } from "react-cookie"
|
|
||||||
import api from '../../../api_utils'
|
|
||||||
import style from './style'
|
|
||||||
|
|
||||||
function CreateFolderModal({ open, setOpen, refresh }: Props) {
|
|
||||||
const [name, setName] = useState("")
|
|
||||||
|
|
||||||
const [cookies] = useCookies(["token"])
|
|
||||||
|
|
||||||
const handleChange: React.ChangeEventHandler<HTMLInputElement> = event => {
|
|
||||||
const value = event.target.value
|
|
||||||
setName(value)
|
|
||||||
}
|
|
||||||
|
|
||||||
// handle click "Enter (Return)"
|
|
||||||
const handleKeyPress = (event: React.KeyboardEvent) => {
|
|
||||||
if (event.keyCode === 13 || event.which === 13 || event.charCode === 13) {
|
|
||||||
handle()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const handle = () => {
|
|
||||||
setOpen(false)
|
|
||||||
|
|
||||||
const request = api.createDir(name, cookies.token)
|
|
||||||
|
|
||||||
request
|
|
||||||
.then(refresh)
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Modal
|
|
||||||
open={open}
|
|
||||||
onClose={() => setOpen(false)}
|
|
||||||
closeAfterTransition
|
|
||||||
BackdropComponent={Backdrop}
|
|
||||||
BackdropProps={{
|
|
||||||
timeout: 500,
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<Fade in={open}>
|
|
||||||
<Box sx={style}>
|
|
||||||
<TextField
|
|
||||||
label="Folder"
|
|
||||||
placeholder="Folder"
|
|
||||||
margin="normal"
|
|
||||||
value={name}
|
|
||||||
onChange={handleChange}
|
|
||||||
onKeyPress={handleKeyPress}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<Link>
|
|
||||||
<Button variant="outlined" onClick={handle}>
|
|
||||||
Create Folder
|
|
||||||
</Button>
|
|
||||||
</Link>
|
|
||||||
</Box>
|
|
||||||
</Fade>
|
|
||||||
</Modal>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
export type Props = {
|
|
||||||
open: boolean,
|
|
||||||
setOpen: React.Dispatch<React.SetStateAction<boolean>>,
|
|
||||||
refresh: () => void,
|
|
||||||
}
|
|
||||||
|
|
||||||
export default CreateFolderModal
|
|
|
@ -1,14 +0,0 @@
|
||||||
const style = {
|
|
||||||
position: 'absolute' as 'absolute',
|
|
||||||
top: '50%',
|
|
||||||
left: '50%',
|
|
||||||
transform: 'translate(-50%, -50%)',
|
|
||||||
width: 400,
|
|
||||||
bgcolor: 'background.paper',
|
|
||||||
color: 'primary.main',
|
|
||||||
border: '2px solid #fff',
|
|
||||||
boxShadow: 24,
|
|
||||||
p: 4
|
|
||||||
}
|
|
||||||
|
|
||||||
export default style
|
|
|
@ -1,93 +0,0 @@
|
||||||
import React, { useState } from 'react'
|
|
||||||
import { Backdrop, Box, Button, Fade, Link, Modal } from "@mui/material"
|
|
||||||
import { useCookies } from "react-cookie"
|
|
||||||
import { toast } from 'react-toastify'
|
|
||||||
import api from '../../../api_utils'
|
|
||||||
import style from './style'
|
|
||||||
|
|
||||||
function UploadModal({ open, setOpen, path, refresh }: Props) {
|
|
||||||
const [file, setFile]: [FileList | null | undefined, React.Dispatch<React.SetStateAction<FileList | null | undefined>>] = useState()
|
|
||||||
|
|
||||||
const [cookies] = useCookies(["token"])
|
|
||||||
|
|
||||||
const onFileChange: React.ChangeEventHandler<HTMLInputElement> = event => {
|
|
||||||
setFile(event.target.files)
|
|
||||||
console.log(file)
|
|
||||||
}
|
|
||||||
|
|
||||||
const handleUpload = () => {
|
|
||||||
const formData = new FormData()
|
|
||||||
|
|
||||||
if (file == null || typeof file == "undefined") {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
formData.append(
|
|
||||||
"file",
|
|
||||||
file[0]
|
|
||||||
)
|
|
||||||
|
|
||||||
const filePath = `${path}/${file[0].name}`
|
|
||||||
|
|
||||||
const request = api.upload(filePath, formData, cookies.token)
|
|
||||||
|
|
||||||
toast.promise(
|
|
||||||
request,
|
|
||||||
{
|
|
||||||
pending: 'Uploading file...',
|
|
||||||
success: {
|
|
||||||
delay: 500,
|
|
||||||
render() {
|
|
||||||
refresh()
|
|
||||||
setOpen(false)
|
|
||||||
|
|
||||||
return "File uploaded!"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
error: {
|
|
||||||
delay: 500,
|
|
||||||
render(err) {
|
|
||||||
if (err.data.response?.data?.error_message) {
|
|
||||||
return err.data.response.data.error_message.toString()
|
|
||||||
} else {
|
|
||||||
return err.data.toString()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Modal
|
|
||||||
open={open}
|
|
||||||
onClose={() => setOpen(false)}
|
|
||||||
closeAfterTransition
|
|
||||||
BackdropComponent={Backdrop}
|
|
||||||
BackdropProps={{
|
|
||||||
timeout: 500,
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<Fade in={open}>
|
|
||||||
<Box sx={style}>
|
|
||||||
<input type="file" onChange={onFileChange} />
|
|
||||||
|
|
||||||
<Link>
|
|
||||||
<Button variant="outlined" onClick={handleUpload}>
|
|
||||||
Upload
|
|
||||||
</Button>
|
|
||||||
</Link>
|
|
||||||
</Box>
|
|
||||||
</Fade>
|
|
||||||
</Modal>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
export type Props = {
|
|
||||||
open: boolean,
|
|
||||||
setOpen: React.Dispatch<React.SetStateAction<boolean>>,
|
|
||||||
path: string,
|
|
||||||
refresh: () => void,
|
|
||||||
}
|
|
||||||
|
|
||||||
export default UploadModal
|
|
|
@ -1,37 +0,0 @@
|
||||||
import styled from "styled-components"
|
|
||||||
|
|
||||||
const Table = styled.table`
|
|
||||||
border: 1px solid;
|
|
||||||
width: 80vw;
|
|
||||||
border-collapse: collapse;
|
|
||||||
|
|
||||||
thead {
|
|
||||||
background-color: #01754b;
|
|
||||||
color: white;
|
|
||||||
}
|
|
||||||
|
|
||||||
tr,
|
|
||||||
td {
|
|
||||||
border: 1px solid #000;
|
|
||||||
padding: 8px;
|
|
||||||
}
|
|
||||||
|
|
||||||
td:first-child {
|
|
||||||
width: 50%;
|
|
||||||
}
|
|
||||||
|
|
||||||
td:last-child {
|
|
||||||
width: 20%;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
a {
|
|
||||||
text-decoration: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
a:hover {
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
`
|
|
||||||
|
|
||||||
export default Table
|
|
|
@ -1,8 +0,0 @@
|
||||||
export const links = {
|
|
||||||
github: "https://github.com/HomeDisk/cloud"
|
|
||||||
}
|
|
||||||
|
|
||||||
export default {
|
|
||||||
apiUrl: "/api",
|
|
||||||
links,
|
|
||||||
}
|
|
5
website/next-env.d.ts
vendored
5
website/next-env.d.ts
vendored
|
@ -1,5 +0,0 @@
|
||||||
/// <reference types="next" />
|
|
||||||
/// <reference types="next/image-types/global" />
|
|
||||||
|
|
||||||
// NOTE: This file should not be edited
|
|
||||||
// see https://nextjs.org/docs/basic-features/typescript for more information.
|
|
|
@ -1,10 +0,0 @@
|
||||||
module.exports = {
|
|
||||||
async rewrites() {
|
|
||||||
return [
|
|
||||||
{
|
|
||||||
source: '/api/:slug*',
|
|
||||||
destination: 'http://127.0.0.1:8080/:slug*'
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,56 +0,0 @@
|
||||||
import { Button } from '@mui/material'
|
|
||||||
import Head from 'next/head'
|
|
||||||
import styled from 'styled-components'
|
|
||||||
|
|
||||||
const Title = styled.h1`
|
|
||||||
margin: 0;
|
|
||||||
line-height: 1.15;
|
|
||||||
font-size: 1.5rem;
|
|
||||||
text-align: center;
|
|
||||||
|
|
||||||
a {
|
|
||||||
color: ${({ theme }) => theme.pages.index.title.a};
|
|
||||||
text-decoration: none;
|
|
||||||
animation: animate 1.5s linear infinite;
|
|
||||||
}
|
|
||||||
|
|
||||||
@keyframes animate {
|
|
||||||
0% {
|
|
||||||
opacity: 0;
|
|
||||||
}
|
|
||||||
50% {
|
|
||||||
opacity: 1;
|
|
||||||
}
|
|
||||||
100% {
|
|
||||||
opacity: 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
a:hover,
|
|
||||||
a:focus,
|
|
||||||
a:active {
|
|
||||||
text-decoration: underline;
|
|
||||||
}
|
|
||||||
`
|
|
||||||
|
|
||||||
const StyledButton = styled(Button)`
|
|
||||||
margin-top: 1rem;
|
|
||||||
`
|
|
||||||
|
|
||||||
export default function NotFound() {
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
<Head>
|
|
||||||
<title>404 - HomeDisk</title>
|
|
||||||
</Head>
|
|
||||||
|
|
||||||
<Title>
|
|
||||||
404 | This page could not be found
|
|
||||||
</Title>
|
|
||||||
|
|
||||||
<StyledButton href="/">
|
|
||||||
Go to Home Page
|
|
||||||
</StyledButton>
|
|
||||||
</>
|
|
||||||
)
|
|
||||||
}
|
|
|
@ -1,56 +0,0 @@
|
||||||
import { Button } from '@mui/material'
|
|
||||||
import Head from 'next/head'
|
|
||||||
import styled from 'styled-components'
|
|
||||||
|
|
||||||
const Title = styled.h1`
|
|
||||||
margin: 0;
|
|
||||||
line-height: 1.15;
|
|
||||||
font-size: 1.5rem;
|
|
||||||
text-align: center;
|
|
||||||
|
|
||||||
a {
|
|
||||||
color: ${({ theme }) => theme.pages.index.title.a};
|
|
||||||
text-decoration: none;
|
|
||||||
animation: animate 1.5s linear infinite;
|
|
||||||
}
|
|
||||||
|
|
||||||
@keyframes animate {
|
|
||||||
0% {
|
|
||||||
opacity: 0;
|
|
||||||
}
|
|
||||||
50% {
|
|
||||||
opacity: 1;
|
|
||||||
}
|
|
||||||
100% {
|
|
||||||
opacity: 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
a:hover,
|
|
||||||
a:focus,
|
|
||||||
a:active {
|
|
||||||
text-decoration: underline;
|
|
||||||
}
|
|
||||||
`
|
|
||||||
|
|
||||||
const StyledButton = styled(Button)`
|
|
||||||
margin-top: 1rem;
|
|
||||||
`
|
|
||||||
|
|
||||||
export default function NotFound() {
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
<Head>
|
|
||||||
<title>500 - HomeDisk</title>
|
|
||||||
</Head>
|
|
||||||
|
|
||||||
<Title>
|
|
||||||
500 | Server-side error occurred
|
|
||||||
</Title>
|
|
||||||
|
|
||||||
<StyledButton href="/">
|
|
||||||
Go to Home Page
|
|
||||||
</StyledButton>
|
|
||||||
</>
|
|
||||||
)
|
|
||||||
}
|
|
|
@ -1,136 +0,0 @@
|
||||||
import { ThemeProvider as MuiThemeProvider, createTheme as muiCreateTheme, PaletteMode } from '@mui/material'
|
|
||||||
import { useEffect, useState } from 'react'
|
|
||||||
import { useCookies } from 'react-cookie'
|
|
||||||
import { ToastContainer } from 'react-toastify'
|
|
||||||
import { createGlobalStyle, ThemeProvider } from 'styled-components'
|
|
||||||
import Container from '../components/container'
|
|
||||||
import Footer from '../components/footer'
|
|
||||||
import Header from '../components/header'
|
|
||||||
import Main from '../components/main'
|
|
||||||
import "react-toastify/dist/ReactToastify.css"
|
|
||||||
|
|
||||||
const GlobalStyle = createGlobalStyle`
|
|
||||||
html,
|
|
||||||
body {
|
|
||||||
padding: 0;
|
|
||||||
margin: 0;
|
|
||||||
font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Roboto, Oxygen,
|
|
||||||
Ubuntu, Cantarell, Fira Sans, Droid Sans, Helvetica Neue, sans-serif;
|
|
||||||
}
|
|
||||||
|
|
||||||
a {
|
|
||||||
color: inherit;
|
|
||||||
text-decoration: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
* {
|
|
||||||
box-sizing: border-box;
|
|
||||||
}
|
|
||||||
`
|
|
||||||
|
|
||||||
const lightTheme = {
|
|
||||||
colors: {
|
|
||||||
background: "#ffffff",
|
|
||||||
color: "#000000",
|
|
||||||
error: "#f85b5b"
|
|
||||||
},
|
|
||||||
pages: {
|
|
||||||
index: {
|
|
||||||
cards: {
|
|
||||||
signin: "#0a60cf",
|
|
||||||
register: "#a06800",
|
|
||||||
files: "#3d8011",
|
|
||||||
settings: "#75006f"
|
|
||||||
},
|
|
||||||
title: {
|
|
||||||
a: "#a109c0"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
footer: {
|
|
||||||
borderTop: "#eaeaea"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const darkTheme = {
|
|
||||||
colors: {
|
|
||||||
background: "#131212",
|
|
||||||
color: "#ffffff",
|
|
||||||
error: "#f85b5b"
|
|
||||||
},
|
|
||||||
pages: {
|
|
||||||
index: {
|
|
||||||
cards: {
|
|
||||||
signin: "#0a60cf",
|
|
||||||
register: "#a06800",
|
|
||||||
files: "#54ad19",
|
|
||||||
settings: "#c90dbf"
|
|
||||||
},
|
|
||||||
title: {
|
|
||||||
a: "#a109c0"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
footer: {
|
|
||||||
borderTop: "#161616"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default function App({ Component, pageProps }) {
|
|
||||||
const [cookies, setCookies] = useCookies(["theme"])
|
|
||||||
|
|
||||||
const [theme, setTheme] = useState(lightTheme)
|
|
||||||
const [themeName, setThemeName]: [PaletteMode, any] = useState("light")
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (!cookies.theme) setCookies("theme", "light")
|
|
||||||
|
|
||||||
if (cookies.theme == "dark"){
|
|
||||||
setTheme(darkTheme)
|
|
||||||
setThemeName("dark")
|
|
||||||
}
|
|
||||||
}, [setCookies, setTheme, setThemeName, cookies])
|
|
||||||
|
|
||||||
const toggleTheme = () => {
|
|
||||||
if (cookies.theme == "light") {
|
|
||||||
setTheme(darkTheme)
|
|
||||||
setThemeName("dark")
|
|
||||||
|
|
||||||
setCookies("theme", "dark")
|
|
||||||
}
|
|
||||||
if (cookies.theme == "dark") {
|
|
||||||
setTheme(lightTheme)
|
|
||||||
setThemeName("light")
|
|
||||||
|
|
||||||
setCookies("theme", "light")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const muiThene = muiCreateTheme({
|
|
||||||
palette: {
|
|
||||||
mode: themeName,
|
|
||||||
},
|
|
||||||
})
|
|
||||||
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
<GlobalStyle />
|
|
||||||
|
|
||||||
<ToastContainer theme={themeName} />
|
|
||||||
|
|
||||||
<MuiThemeProvider theme={muiThene}>
|
|
||||||
<ThemeProvider theme={theme}>
|
|
||||||
<Container>
|
|
||||||
<Header toggleTheme={toggleTheme} theme={themeName} />
|
|
||||||
|
|
||||||
<Main>
|
|
||||||
<Component {...pageProps} />
|
|
||||||
</Main>
|
|
||||||
|
|
||||||
<Footer />
|
|
||||||
</Container>
|
|
||||||
</ThemeProvider>
|
|
||||||
</MuiThemeProvider>
|
|
||||||
</>
|
|
||||||
)
|
|
||||||
}
|
|
|
@ -1,32 +0,0 @@
|
||||||
import Document, { DocumentContext, DocumentInitialProps } from 'next/document'
|
|
||||||
import { ServerStyleSheet } from 'styled-components'
|
|
||||||
|
|
||||||
export default class MyDocument extends Document {
|
|
||||||
static async getInitialProps(
|
|
||||||
ctx: DocumentContext
|
|
||||||
): Promise<DocumentInitialProps> {
|
|
||||||
const sheet = new ServerStyleSheet()
|
|
||||||
const originalRenderPage = ctx.renderPage
|
|
||||||
|
|
||||||
try {
|
|
||||||
ctx.renderPage = () =>
|
|
||||||
originalRenderPage({
|
|
||||||
enhanceApp: (App) => (props) =>
|
|
||||||
sheet.collectStyles(<App {...props} />),
|
|
||||||
})
|
|
||||||
|
|
||||||
const initialProps = await Document.getInitialProps(ctx)
|
|
||||||
return {
|
|
||||||
...initialProps,
|
|
||||||
styles: [
|
|
||||||
<>
|
|
||||||
{initialProps.styles}
|
|
||||||
{sheet.getStyleElement()}
|
|
||||||
</>,
|
|
||||||
],
|
|
||||||
}
|
|
||||||
} finally {
|
|
||||||
sheet.seal()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,80 +0,0 @@
|
||||||
import Head from 'next/head'
|
|
||||||
import { useEffect, useState } from 'react'
|
|
||||||
import { useCookies } from 'react-cookie'
|
|
||||||
import { Card, CardFiles, CardRegister, CardSettings, CardSignIn } from '../components/home/cards'
|
|
||||||
import Description from '../components/home/description'
|
|
||||||
import Grid from '../components/home/grid'
|
|
||||||
import Title from '../components/home/title'
|
|
||||||
import { links } from '../config'
|
|
||||||
|
|
||||||
export default function Home() {
|
|
||||||
const [cookies] = useCookies(["token"])
|
|
||||||
|
|
||||||
const [cards, setCards] = useState(<CardsNonLogged />)
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (cookies.token) {
|
|
||||||
setCards(<CardsLogged />)
|
|
||||||
}
|
|
||||||
}, [setCards, cookies])
|
|
||||||
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
<Head>
|
|
||||||
<title>HomeDisk</title>
|
|
||||||
</Head>
|
|
||||||
|
|
||||||
<Title>
|
|
||||||
Welcome to <a href={links.github} target="_blank" rel="noreferrer">HomeDisk!</a>
|
|
||||||
</Title>
|
|
||||||
|
|
||||||
<Description>
|
|
||||||
Fast and lightweight local cloud for your data written in Rust
|
|
||||||
</Description>
|
|
||||||
|
|
||||||
<Grid>
|
|
||||||
{cards}
|
|
||||||
</Grid>
|
|
||||||
</>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
function CardsNonLogged() {
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
<Card>
|
|
||||||
<CardSignIn href="/login">
|
|
||||||
<h2>Sign in →</h2>
|
|
||||||
<p>Log in to your account</p>
|
|
||||||
</CardSignIn>
|
|
||||||
</Card>
|
|
||||||
|
|
||||||
<Card>
|
|
||||||
<CardRegister href="/register">
|
|
||||||
<h2>Register →</h2>
|
|
||||||
<p>Register a new account</p>
|
|
||||||
</CardRegister>
|
|
||||||
</Card>
|
|
||||||
</>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
function CardsLogged() {
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
<Card>
|
|
||||||
<CardFiles href="/user/files">
|
|
||||||
<h2>Files →</h2>
|
|
||||||
<p>View your files</p>
|
|
||||||
</CardFiles>
|
|
||||||
</Card>
|
|
||||||
|
|
||||||
<Card>
|
|
||||||
<CardSettings href="/user/settings">
|
|
||||||
<h2>Settings →</h2>
|
|
||||||
<p>Go to user settings</p>
|
|
||||||
</CardSettings>
|
|
||||||
</Card>
|
|
||||||
</>
|
|
||||||
)
|
|
||||||
}
|
|
|
@ -1,97 +0,0 @@
|
||||||
import React from 'react'
|
|
||||||
import { TextField } from '@mui/material'
|
|
||||||
import Head from 'next/head'
|
|
||||||
import Router from 'next/router'
|
|
||||||
import { useEffect, useState } from 'react'
|
|
||||||
import { useCookies } from 'react-cookie'
|
|
||||||
import api from '../api_utils'
|
|
||||||
import Title from '../components/auth/title'
|
|
||||||
import ErrorComponent from '../components/auth/error'
|
|
||||||
import SubmitButton from '../components/auth/button'
|
|
||||||
|
|
||||||
export default function Login() {
|
|
||||||
const [cookies, setCookies] = useCookies(["token"])
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (cookies.token) {
|
|
||||||
Router.push('/user/files')
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
const [error, setError] = useState("")
|
|
||||||
const [username, setUsername] = useState("")
|
|
||||||
const [password, setPassword] = useState("")
|
|
||||||
|
|
||||||
const handleUsernameChange: React.ChangeEventHandler<HTMLInputElement> = event => {
|
|
||||||
const value = event.target.value
|
|
||||||
setUsername(value)
|
|
||||||
}
|
|
||||||
|
|
||||||
const handlePasswordChange: React.ChangeEventHandler<HTMLInputElement> = event => {
|
|
||||||
const value = event.target.value
|
|
||||||
setPassword(value)
|
|
||||||
}
|
|
||||||
|
|
||||||
// handle click "Enter (Return)"
|
|
||||||
const handleKeyPress = (event: React.KeyboardEvent) => {
|
|
||||||
if (event.keyCode === 13 || event.which === 13 || event.charCode === 13) {
|
|
||||||
handleLogin()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const handleLogin = () => {
|
|
||||||
const request = api.login(username, password)
|
|
||||||
|
|
||||||
request
|
|
||||||
.then(token => {
|
|
||||||
setCookies("token", token)
|
|
||||||
setError("")
|
|
||||||
})
|
|
||||||
.catch(err => setError(err.toString()))
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
<Head>
|
|
||||||
<title>Login - HomeDisk</title>
|
|
||||||
</Head>
|
|
||||||
|
|
||||||
<Title>
|
|
||||||
Sign in
|
|
||||||
</Title>
|
|
||||||
|
|
||||||
{error != "" && (
|
|
||||||
<ErrorComponent>{error}</ErrorComponent>
|
|
||||||
)}
|
|
||||||
|
|
||||||
<TextField
|
|
||||||
label="Username"
|
|
||||||
placeholder="Username"
|
|
||||||
margin="normal"
|
|
||||||
value={username}
|
|
||||||
onChange={handleUsernameChange}
|
|
||||||
onKeyPress={handleKeyPress}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<TextField
|
|
||||||
label="Password"
|
|
||||||
placeholder="Password"
|
|
||||||
type="password"
|
|
||||||
margin="normal"
|
|
||||||
value={password}
|
|
||||||
onChange={handlePasswordChange}
|
|
||||||
onKeyPress={handleKeyPress}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<SubmitButton
|
|
||||||
variant="contained"
|
|
||||||
size="large"
|
|
||||||
color="secondary"
|
|
||||||
onClick={handleLogin}
|
|
||||||
disabled={username == "" || password == ""}
|
|
||||||
>
|
|
||||||
Login
|
|
||||||
</SubmitButton>
|
|
||||||
</>
|
|
||||||
)
|
|
||||||
}
|
|
|
@ -1,97 +0,0 @@
|
||||||
import React from 'react'
|
|
||||||
import { TextField } from '@mui/material'
|
|
||||||
import Head from 'next/head'
|
|
||||||
import Router from 'next/router'
|
|
||||||
import { useEffect, useState } from 'react'
|
|
||||||
import { useCookies } from 'react-cookie'
|
|
||||||
import api from '../api_utils'
|
|
||||||
import ErrorComponent from '../components/auth/error'
|
|
||||||
import Title from '../components/auth/title'
|
|
||||||
import SubmitButton from '../components/auth/button'
|
|
||||||
|
|
||||||
export default function Login() {
|
|
||||||
const [cookies, setCookies] = useCookies(["token"])
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (cookies.token) {
|
|
||||||
Router.push('/user/files')
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
const [error, setError] = useState("")
|
|
||||||
const [username, setUsername] = useState("")
|
|
||||||
const [password, setPassword] = useState("")
|
|
||||||
|
|
||||||
const handleUsernameChange: React.ChangeEventHandler<HTMLInputElement> = event => {
|
|
||||||
const value = event.target.value
|
|
||||||
setUsername(value)
|
|
||||||
}
|
|
||||||
|
|
||||||
const handlePasswordChange: React.ChangeEventHandler<HTMLInputElement> = event => {
|
|
||||||
const value = event.target.value
|
|
||||||
setPassword(value)
|
|
||||||
}
|
|
||||||
|
|
||||||
// handle click "Enter (Return)"
|
|
||||||
const handleKeyPress = (event: React.KeyboardEvent) => {
|
|
||||||
if (event.keyCode === 13 || event.which === 13 || event.charCode === 13) {
|
|
||||||
handleLogin()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const handleLogin = () => {
|
|
||||||
const request = api.register(username, password)
|
|
||||||
|
|
||||||
request
|
|
||||||
.then(token => {
|
|
||||||
setCookies("token", token)
|
|
||||||
setError("")
|
|
||||||
})
|
|
||||||
.catch(err => setError(err.toString()))
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
<Head>
|
|
||||||
<title>Register - HomeDisk</title>
|
|
||||||
</Head>
|
|
||||||
|
|
||||||
<Title>
|
|
||||||
Register
|
|
||||||
</Title>
|
|
||||||
|
|
||||||
{error != "" && (
|
|
||||||
<ErrorComponent>{error}</ErrorComponent>
|
|
||||||
)}
|
|
||||||
|
|
||||||
<TextField
|
|
||||||
label="Username"
|
|
||||||
placeholder="Username"
|
|
||||||
margin="normal"
|
|
||||||
value={username}
|
|
||||||
onChange={handleUsernameChange}
|
|
||||||
onKeyPress={handleKeyPress}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<TextField
|
|
||||||
label="Password"
|
|
||||||
placeholder="Password"
|
|
||||||
type="password"
|
|
||||||
margin="normal"
|
|
||||||
value={password}
|
|
||||||
onChange={handlePasswordChange}
|
|
||||||
onKeyPress={handleKeyPress}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<SubmitButton
|
|
||||||
variant="contained"
|
|
||||||
size="large"
|
|
||||||
color="secondary"
|
|
||||||
onClick={handleLogin}
|
|
||||||
disabled={username == "" || password == ""}
|
|
||||||
>
|
|
||||||
Register
|
|
||||||
</SubmitButton>
|
|
||||||
</>
|
|
||||||
)
|
|
||||||
}
|
|
|
@ -1,161 +0,0 @@
|
||||||
import { faFile, faFolder } from "@fortawesome/free-solid-svg-icons"
|
|
||||||
import { CloudUpload, CreateNewFolder } from "@mui/icons-material"
|
|
||||||
import { IconButton, Link as MuiLink } from "@mui/material"
|
|
||||||
import Head from 'next/head'
|
|
||||||
import Link from 'next/link'
|
|
||||||
import { useEffect, useState } from 'react'
|
|
||||||
import { useCookies } from 'react-cookie'
|
|
||||||
import { resolve as pathResolve } from 'path'
|
|
||||||
import api from '../../api_utils'
|
|
||||||
import Icon from "../../components/other/icon"
|
|
||||||
import Table from "../../components/user/table"
|
|
||||||
import UploadModal from "../../components/user/modals/upload"
|
|
||||||
import CreateFolderModal from "../../components/user/modals/create-folder"
|
|
||||||
import IconDiv from "../../components/other/icon-div"
|
|
||||||
|
|
||||||
export default function Files() {
|
|
||||||
const [cookies] = useCookies(["token"])
|
|
||||||
|
|
||||||
const [path, setPath] = useState("")
|
|
||||||
const [files, setFiles] = useState([{ name: "", size: "", modified: "" }])
|
|
||||||
const [folders, setFolders] = useState([{ name: "", size: "", modified: "" }])
|
|
||||||
|
|
||||||
const refresh = (path: string) => {
|
|
||||||
api.list(path, cookies.token)
|
|
||||||
.then(data => {
|
|
||||||
setPath(path)
|
|
||||||
setFolders(data.dirs)
|
|
||||||
setFiles(data.files)
|
|
||||||
})
|
|
||||||
.catch(err => console.error(err))
|
|
||||||
}
|
|
||||||
|
|
||||||
const refreshFolder = () => refresh(path)
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
const params = new URLSearchParams(window.location.search)
|
|
||||||
const path = params.get("path") || ""
|
|
||||||
|
|
||||||
api.list(path, cookies.token)
|
|
||||||
.then(data => {
|
|
||||||
setPath(path)
|
|
||||||
setFolders(data.dirs)
|
|
||||||
setFiles(data.files)
|
|
||||||
})
|
|
||||||
.catch(err => console.error(err))
|
|
||||||
}, [cookies])
|
|
||||||
|
|
||||||
// modals
|
|
||||||
const [uploadModal, setUploadModal] = useState(false)
|
|
||||||
const [createFolderModal, setCreateFolderModal] = useState(false)
|
|
||||||
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
<Head>
|
|
||||||
<title>Files - HomeDisk</title>
|
|
||||||
</Head>
|
|
||||||
|
|
||||||
<MuiLink sx={{display: "flex"}}>
|
|
||||||
<IconDiv>
|
|
||||||
<IconButton
|
|
||||||
size="large"
|
|
||||||
edge="start"
|
|
||||||
color="inherit"
|
|
||||||
aria-label="logo"
|
|
||||||
onClick={() => setUploadModal(true)}
|
|
||||||
>
|
|
||||||
<CloudUpload />
|
|
||||||
</IconButton>
|
|
||||||
</IconDiv>
|
|
||||||
|
|
||||||
<IconDiv>
|
|
||||||
<IconButton
|
|
||||||
size="large"
|
|
||||||
edge="start"
|
|
||||||
color="inherit"
|
|
||||||
aria-label="logo"
|
|
||||||
onClick={() => setCreateFolderModal(true)}
|
|
||||||
>
|
|
||||||
<CreateNewFolder />
|
|
||||||
</IconButton>
|
|
||||||
</IconDiv>
|
|
||||||
</MuiLink>
|
|
||||||
|
|
||||||
<UploadModal open={uploadModal} setOpen={setUploadModal} path={path} refresh={refreshFolder} />
|
|
||||||
<CreateFolderModal open={createFolderModal} setOpen={setCreateFolderModal} refresh={refreshFolder} />
|
|
||||||
|
|
||||||
<Table>
|
|
||||||
<thead>
|
|
||||||
<tr>
|
|
||||||
<td>Name</td>
|
|
||||||
<td>Size</td>
|
|
||||||
<td>Modified</td>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
|
|
||||||
<tbody>
|
|
||||||
{path != "" && path != "/" && (
|
|
||||||
<tr>
|
|
||||||
<td>
|
|
||||||
<Link href={`?path=${pathResolve(path, '..')}`}>
|
|
||||||
<MuiLink onClick={() => refresh(pathResolve(path, '..'))}>
|
|
||||||
<Icon icon={faFolder} />
|
|
||||||
.. (go up)
|
|
||||||
</MuiLink>
|
|
||||||
</Link>
|
|
||||||
</td>
|
|
||||||
<td></td>
|
|
||||||
<td></td>
|
|
||||||
</tr>
|
|
||||||
)}
|
|
||||||
|
|
||||||
{folders.map((f, index) => <FolderComponent key={index} name={f.name} path={`${path}/${f.name}`} size={f.size} modified={f.modified} refresh={refresh} />)}
|
|
||||||
{files.map((f, index) => <FileComponent key={index} name={f.name} path={`${path}/${f.name}`} size={f.size} modified={f.modified} refresh={refresh} />)}
|
|
||||||
</tbody>
|
|
||||||
</Table>
|
|
||||||
</>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
function FolderComponent({ name, path, size, modified, refresh }: Props) {
|
|
||||||
return (
|
|
||||||
<tr>
|
|
||||||
<td>
|
|
||||||
<Link href={`?path=${path}`}>
|
|
||||||
<MuiLink onClick={() => refresh(path)}>
|
|
||||||
<Icon icon={faFolder} />
|
|
||||||
{name.replace("/", "")}
|
|
||||||
</MuiLink>
|
|
||||||
</Link>
|
|
||||||
</td>
|
|
||||||
<td>{size}</td>
|
|
||||||
<td>{modified}</td>
|
|
||||||
</tr>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
function FileComponent({ name, path, size, modified, refresh }: Props) {
|
|
||||||
return (
|
|
||||||
<tr>
|
|
||||||
<td>
|
|
||||||
<Link href={`?path=${path}`}>
|
|
||||||
<MuiLink onClick={() => refresh(path)}>
|
|
||||||
<Icon icon={faFile} />
|
|
||||||
{name.replace("/", "")}
|
|
||||||
</MuiLink>
|
|
||||||
</Link>
|
|
||||||
</td>
|
|
||||||
<td>{size}</td>
|
|
||||||
<td>{modified} ago</td>
|
|
||||||
</tr>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
type Props = {
|
|
||||||
name: string,
|
|
||||||
path: string,
|
|
||||||
size: string,
|
|
||||||
modified: string,
|
|
||||||
// eslint-disable-next-line no-unused-vars
|
|
||||||
refresh: (path: string) => void
|
|
||||||
}
|
|
|
@ -1,20 +0,0 @@
|
||||||
{
|
|
||||||
"compilerOptions": {
|
|
||||||
"target": "es6",
|
|
||||||
"lib": ["dom", "dom.iterable", "esnext"],
|
|
||||||
"allowJs": true,
|
|
||||||
"skipLibCheck": true,
|
|
||||||
"strict": false,
|
|
||||||
"forceConsistentCasingInFileNames": true,
|
|
||||||
"noEmit": true,
|
|
||||||
"incremental": true,
|
|
||||||
"esModuleInterop": true,
|
|
||||||
"module": "esnext",
|
|
||||||
"moduleResolution": "node",
|
|
||||||
"resolveJsonModule": true,
|
|
||||||
"isolatedModules": true,
|
|
||||||
"jsx": "preserve"
|
|
||||||
},
|
|
||||||
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx"],
|
|
||||||
"exclude": ["node_modules"]
|
|
||||||
}
|
|
|
@ -1,23 +0,0 @@
|
||||||
interface ThemeInterface {
|
|
||||||
colors: {
|
|
||||||
background: string;
|
|
||||||
color: string;
|
|
||||||
error: string;
|
|
||||||
};
|
|
||||||
pages: {
|
|
||||||
index: {
|
|
||||||
cards: {
|
|
||||||
signin: string;
|
|
||||||
register: string;
|
|
||||||
};
|
|
||||||
title: {
|
|
||||||
a: string;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
footer: {
|
|
||||||
borderTop: string;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export default ThemeInterface
|
|
Loading…
Reference in a new issue