Moved from GitHub
This commit is contained in:
commit
df7dddae70
50 changed files with 12549 additions and 0 deletions
38
.github/ISSUE_TEMPLATE/bug_report.md
vendored
Normal file
38
.github/ISSUE_TEMPLATE/bug_report.md
vendored
Normal file
|
@ -0,0 +1,38 @@
|
|||
---
|
||||
name: Bug report
|
||||
about: Create a report to help us improve
|
||||
title: ''
|
||||
labels: ''
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
**Describe the bug**
|
||||
A clear and concise description of what the bug is.
|
||||
|
||||
**To Reproduce**
|
||||
Steps to reproduce the behavior:
|
||||
1. Go to '...'
|
||||
2. Click on '....'
|
||||
3. Scroll down to '....'
|
||||
4. See error
|
||||
|
||||
**Expected behavior**
|
||||
A clear and concise description of what you expected to happen.
|
||||
|
||||
**Screenshots**
|
||||
If applicable, add screenshots to help explain your problem.
|
||||
|
||||
**Desktop (please complete the following information):**
|
||||
- OS: [e.g. iOS]
|
||||
- Browser [e.g. chrome, safari]
|
||||
- Version [e.g. 22]
|
||||
|
||||
**Smartphone (please complete the following information):**
|
||||
- Device: [e.g. iPhone6]
|
||||
- OS: [e.g. iOS8.1]
|
||||
- Browser [e.g. stock browser, safari]
|
||||
- Version [e.g. 22]
|
||||
|
||||
**Additional context**
|
||||
Add any other context about the problem here.
|
20
.github/ISSUE_TEMPLATE/feature_request.md
vendored
Normal file
20
.github/ISSUE_TEMPLATE/feature_request.md
vendored
Normal file
|
@ -0,0 +1,20 @@
|
|||
---
|
||||
name: Feature request
|
||||
about: Suggest an idea for this project
|
||||
title: ''
|
||||
labels: ''
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
**Is your feature request related to a problem? Please describe.**
|
||||
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
|
||||
|
||||
**Describe the solution you'd like**
|
||||
A clear and concise description of what you want to happen.
|
||||
|
||||
**Describe alternatives you've considered**
|
||||
A clear and concise description of any alternative solutions or features you've considered.
|
||||
|
||||
**Additional context**
|
||||
Add any other context or screenshots about the feature request here.
|
12
.github/PULL_REQUEST_TEMPLATE.md
vendored
Normal file
12
.github/PULL_REQUEST_TEMPLATE.md
vendored
Normal file
|
@ -0,0 +1,12 @@
|
|||
# Task
|
||||
|
||||
# Description
|
||||
|
||||
# Demo
|
||||
|
||||
# How Has This Been Tested?
|
||||
|
||||
# Checklist
|
||||
|
||||
- [ ] I have performed a self-review of my own code
|
||||
- [ ] I have added tests to cover my changes
|
25
.github/workflows/release.yml
vendored
Normal file
25
.github/workflows/release.yml
vendored
Normal file
|
@ -0,0 +1,25 @@
|
|||
name: Release
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
- dev
|
||||
|
||||
jobs:
|
||||
release:
|
||||
permissions:
|
||||
contents: write
|
||||
issues: write
|
||||
pull-requests: write
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 20
|
||||
- run: npm ci
|
||||
- run: npm run build
|
||||
- run: npx semantic-release
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
16
.github/workflows/test.yml
vendored
Normal file
16
.github/workflows/test.yml
vendored
Normal file
|
@ -0,0 +1,16 @@
|
|||
name: Test
|
||||
|
||||
on: push
|
||||
|
||||
jobs:
|
||||
lint:
|
||||
name: Run tests
|
||||
runs-on: ubuntu-latest
|
||||
# container: "node:20"
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 20
|
||||
- run: npm ci
|
||||
- run: npm run build --if-present
|
26
.gitignore
vendored
Normal file
26
.gitignore
vendored
Normal file
|
@ -0,0 +1,26 @@
|
|||
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
|
||||
|
||||
# dependencies
|
||||
/node_modules
|
||||
/.pnp
|
||||
.pnp.js
|
||||
|
||||
# testing
|
||||
/coverage
|
||||
|
||||
# production
|
||||
/build
|
||||
|
||||
# misc
|
||||
.DS_Store
|
||||
.env.local
|
||||
.env.development.local
|
||||
.env.test.local
|
||||
.env.production.local
|
||||
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
*.env
|
||||
*.txt
|
||||
/dist
|
11
.prettierrc
Normal file
11
.prettierrc
Normal file
|
@ -0,0 +1,11 @@
|
|||
{
|
||||
"arrowParens": "always",
|
||||
"bracketSpacing": true,
|
||||
"bracketSameLine": false,
|
||||
"tabWidth": 4,
|
||||
"trailingComma": "all",
|
||||
"semi": true,
|
||||
"printWidth": 80,
|
||||
"endOfLine": "lf",
|
||||
"singleQuote": false
|
||||
}
|
128
CODE_OF_CONDUCT.md
Normal file
128
CODE_OF_CONDUCT.md
Normal file
|
@ -0,0 +1,128 @@
|
|||
# Contributor Covenant Code of Conduct
|
||||
|
||||
## Our Pledge
|
||||
|
||||
We as members, contributors, and leaders pledge to make participation in our
|
||||
community a harassment-free experience for everyone, regardless of age, body
|
||||
size, visible or invisible disability, ethnicity, sex characteristics, gender
|
||||
identity and expression, level of experience, education, socio-economic status,
|
||||
nationality, personal appearance, race, religion, or sexual identity
|
||||
and orientation.
|
||||
|
||||
We pledge to act and interact in ways that contribute to an open, welcoming,
|
||||
diverse, inclusive, and healthy community.
|
||||
|
||||
## Our Standards
|
||||
|
||||
Examples of behavior that contributes to a positive environment for our
|
||||
community include:
|
||||
|
||||
* Demonstrating empathy and kindness toward other people
|
||||
* Being respectful of differing opinions, viewpoints, and experiences
|
||||
* Giving and gracefully accepting constructive feedback
|
||||
* Accepting responsibility and apologizing to those affected by our mistakes,
|
||||
and learning from the experience
|
||||
* Focusing on what is best not just for us as individuals, but for the
|
||||
overall community
|
||||
|
||||
Examples of unacceptable behavior include:
|
||||
|
||||
* The use of sexualized language or imagery, and sexual attention or
|
||||
advances of any kind
|
||||
* Trolling, insulting or derogatory comments, and personal or political attacks
|
||||
* Public or private harassment
|
||||
* Publishing others' private information, such as a physical or email
|
||||
address, without their explicit permission
|
||||
* Other conduct which could reasonably be considered inappropriate in a
|
||||
professional setting
|
||||
|
||||
## Enforcement Responsibilities
|
||||
|
||||
Community leaders are responsible for clarifying and enforcing our standards of
|
||||
acceptable behavior and will take appropriate and fair corrective action in
|
||||
response to any behavior that they deem inappropriate, threatening, offensive,
|
||||
or harmful.
|
||||
|
||||
Community leaders have the right and responsibility to remove, edit, or reject
|
||||
comments, commits, code, wiki edits, issues, and other contributions that are
|
||||
not aligned to this Code of Conduct, and will communicate reasons for moderation
|
||||
decisions when appropriate.
|
||||
|
||||
## Scope
|
||||
|
||||
This Code of Conduct applies within all community spaces, and also applies when
|
||||
an individual is officially representing the community in public spaces.
|
||||
Examples of representing our community include using an official e-mail address,
|
||||
posting via an official social media account, or acting as an appointed
|
||||
representative at an online or offline event.
|
||||
|
||||
## Enforcement
|
||||
|
||||
Instances of abusive, harassing, or otherwise unacceptable behavior may be
|
||||
reported to the community leaders responsible for enforcement at
|
||||
help.lakio@gmail.com.
|
||||
All complaints will be reviewed and investigated promptly and fairly.
|
||||
|
||||
All community leaders are obligated to respect the privacy and security of the
|
||||
reporter of any incident.
|
||||
|
||||
## Enforcement Guidelines
|
||||
|
||||
Community leaders will follow these Community Impact Guidelines in determining
|
||||
the consequences for any action they deem in violation of this Code of Conduct:
|
||||
|
||||
### 1. Correction
|
||||
|
||||
**Community Impact**: Use of inappropriate language or other behavior deemed
|
||||
unprofessional or unwelcome in the community.
|
||||
|
||||
**Consequence**: A private, written warning from community leaders, providing
|
||||
clarity around the nature of the violation and an explanation of why the
|
||||
behavior was inappropriate. A public apology may be requested.
|
||||
|
||||
### 2. Warning
|
||||
|
||||
**Community Impact**: A violation through a single incident or series
|
||||
of actions.
|
||||
|
||||
**Consequence**: A warning with consequences for continued behavior. No
|
||||
interaction with the people involved, including unsolicited interaction with
|
||||
those enforcing the Code of Conduct, for a specified period of time. This
|
||||
includes avoiding interactions in community spaces as well as external channels
|
||||
like social media. Violating these terms may lead to a temporary or
|
||||
permanent ban.
|
||||
|
||||
### 3. Temporary Ban
|
||||
|
||||
**Community Impact**: A serious violation of community standards, including
|
||||
sustained inappropriate behavior.
|
||||
|
||||
**Consequence**: A temporary ban from any sort of interaction or public
|
||||
communication with the community for a specified period of time. No public or
|
||||
private interaction with the people involved, including unsolicited interaction
|
||||
with those enforcing the Code of Conduct, is allowed during this period.
|
||||
Violating these terms may lead to a permanent ban.
|
||||
|
||||
### 4. Permanent Ban
|
||||
|
||||
**Community Impact**: Demonstrating a pattern of violation of community
|
||||
standards, including sustained inappropriate behavior, harassment of an
|
||||
individual, or aggression toward or disparagement of classes of individuals.
|
||||
|
||||
**Consequence**: A permanent ban from any sort of public interaction within
|
||||
the community.
|
||||
|
||||
## Attribution
|
||||
|
||||
This Code of Conduct is adapted from the [Contributor Covenant][homepage],
|
||||
version 2.0, available at
|
||||
https://www.contributor-covenant.org/version/2/0/code_of_conduct.html.
|
||||
|
||||
Community Impact Guidelines were inspired by [Mozilla's code of conduct
|
||||
enforcement ladder](https://github.com/mozilla/diversity).
|
||||
|
||||
[homepage]: https://www.contributor-covenant.org
|
||||
|
||||
For answers to common questions about this code of conduct, see the FAQ at
|
||||
https://www.contributor-covenant.org/faq. Translations are available at
|
||||
https://www.contributor-covenant.org/translations.
|
17
CONTRIBUTING.md
Normal file
17
CONTRIBUTING.md
Normal file
|
@ -0,0 +1,17 @@
|
|||
# Contributing
|
||||
|
||||
When contributing to this repository, please first discuss the change you wish to make via issue,
|
||||
email, or any other method with the owners of this repository before making a change.
|
||||
|
||||
Please note we have a code of conduct, please follow it in all your interactions with the project.
|
||||
|
||||
## Pull Request Process
|
||||
|
||||
1. Ensure any install or build dependencies are removed before the end of the layer when doing a
|
||||
build.
|
||||
2. Update the README.md with details of changes to the interface, this includes new environment
|
||||
variables, exposed ports, useful file locations and container parameters.
|
||||
3. Increase the version numbers in any examples files and the README.md to the new version that this
|
||||
Pull Request would represent. The versioning scheme we use is [SemVer](http://semver.org/).
|
||||
4. You may merge the Pull Request in once you have the sign-off of two other developers, or if you
|
||||
do not have permission to do that, you may request the second reviewer to merge it for you.
|
21
LICENSE
Normal file
21
LICENSE
Normal file
|
@ -0,0 +1,21 @@
|
|||
MIT License
|
||||
|
||||
Copyright (c) 2024 LakioLive
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
76
README.md
Normal file
76
README.md
Normal file
|
@ -0,0 +1,76 @@
|
|||
# SloudPLPage
|
||||
|
||||
Welcome to the **SloudPLPage** project! This site is made for [SloudPL](https://sloud.pl/). It offers game server hosting and other services.
|
||||
|
||||
## Table of Contents
|
||||
|
||||
- [Demo](#demo)
|
||||
- [Installation](#installation)
|
||||
- [Technologies](#technologies)
|
||||
- [Contributing](#contributing)
|
||||
- [Authors](#authors)
|
||||
- [License](#license)
|
||||
|
||||
## Demo
|
||||
|
||||
Check out the live demo [here](https://sloud.pl/).
|
||||
|
||||
## Installation
|
||||
|
||||
To get a local copy up and running, follow these simple steps:
|
||||
|
||||
### Prerequisites
|
||||
|
||||
- **Node.js**: Ensure you have Node.js installed. You can download it from [nodejs.org](https://nodejs.org/).
|
||||
|
||||
### Clone the repository
|
||||
|
||||
```sh
|
||||
git clone https://github.com/LakioLive/SloudPLPage
|
||||
cd SloudPLPage
|
||||
```
|
||||
|
||||
### Install dependencies
|
||||
|
||||
```sh
|
||||
npm install
|
||||
```
|
||||
|
||||
### Start the development server
|
||||
|
||||
```sh
|
||||
npm run dev
|
||||
```
|
||||
|
||||
Open [http://localhost:5173](http://localhost:5173) to view it in the browser.
|
||||
|
||||
## Technologies
|
||||
|
||||
- **TypeScript**: Typed superset of JavaScript that compiles to plain JavaScript.
|
||||
- **React**: JavaScript library for building user interfaces.
|
||||
- **Vite**: Next-generation frontend tooling for fast and optimized builds.
|
||||
- **TailwindCSS**: Utility-first CSS framework for rapid UI development.
|
||||
- **Sass**: CSS preprocessor that adds power and elegance to the basic language.
|
||||
- **i18next**: Internationalization framework for translating your React applications.
|
||||
- **React Icons**: Include popular icons in your React projects easily.
|
||||
|
||||
## Contributing
|
||||
|
||||
Contributions are what make the open-source community such an amazing place to learn, inspire, and create. Any contributions you make are **greatly appreciated**.
|
||||
|
||||
### Steps to Contribute
|
||||
|
||||
1. Fork the Project
|
||||
2. Create your Feature Branch (`git checkout -b feature/YourFeature`)
|
||||
3. Commit your Changes (`git commit -m 'Add some YourFeature'`)
|
||||
4. Push to the Branch (`git push origin feature/YourFeature`)
|
||||
5. Open a Pull Request
|
||||
|
||||
## Authors
|
||||
|
||||
LakioLive
|
||||
SloudPL
|
||||
|
||||
## License
|
||||
|
||||
Distributed under the **MIT License**. See `LICENSE` for more information.
|
28
eslint.config.js
Normal file
28
eslint.config.js
Normal file
|
@ -0,0 +1,28 @@
|
|||
import js from '@eslint/js'
|
||||
import globals from 'globals'
|
||||
import reactHooks from 'eslint-plugin-react-hooks'
|
||||
import reactRefresh from 'eslint-plugin-react-refresh'
|
||||
import tseslint from 'typescript-eslint'
|
||||
|
||||
export default tseslint.config(
|
||||
{ ignores: ['dist'] },
|
||||
{
|
||||
extends: [js.configs.recommended, ...tseslint.configs.recommended],
|
||||
files: ['**/*.{ts,tsx}'],
|
||||
languageOptions: {
|
||||
ecmaVersion: 2020,
|
||||
globals: globals.browser,
|
||||
},
|
||||
plugins: {
|
||||
'react-hooks': reactHooks,
|
||||
'react-refresh': reactRefresh,
|
||||
},
|
||||
rules: {
|
||||
...reactHooks.configs.recommended.rules,
|
||||
'react-refresh/only-export-components': [
|
||||
'warn',
|
||||
{ allowConstantExport: true },
|
||||
],
|
||||
},
|
||||
},
|
||||
)
|
12
index.html
Normal file
12
index.html
Normal file
|
@ -0,0 +1,12 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>SloudPL</title>
|
||||
</head>
|
||||
<body>
|
||||
<div id="root"></div>
|
||||
<script type="module" src="/src/main.tsx"></script>
|
||||
</body>
|
||||
</html>
|
11102
package-lock.json
generated
Normal file
11102
package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load diff
42
package.json
Normal file
42
package.json
Normal file
|
@ -0,0 +1,42 @@
|
|||
{
|
||||
"name": "sloudpl",
|
||||
"private": true,
|
||||
"version": "0.0.0",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
"build": "tsc -b && vite build",
|
||||
"lint": "eslint .",
|
||||
"preview": "vite preview"
|
||||
},
|
||||
"dependencies": {
|
||||
"i18next": "^24.2.0",
|
||||
"i18next-browser-languagedetector": "^8.0.2",
|
||||
"react": "^18.3.1",
|
||||
"react-dom": "^18.3.1",
|
||||
"react-i18next": "^15.2.0",
|
||||
"react-icons": "^5.4.0",
|
||||
"react-loading-skeleton": "^3.5.0",
|
||||
"react-spinners": "^0.15.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@eslint/js": "^9.17.0",
|
||||
"@semantic-release/git": "^10.0.1",
|
||||
"@semantic-release/github": "^11.0.1",
|
||||
"@types/react": "^18.3.18",
|
||||
"@types/react-dom": "^18.3.5",
|
||||
"@vitejs/plugin-react": "^4.3.4",
|
||||
"autoprefixer": "^10.4.20",
|
||||
"eslint": "^9.17.0",
|
||||
"eslint-plugin-react-hooks": "^5.0.0",
|
||||
"eslint-plugin-react-refresh": "^0.4.16",
|
||||
"globals": "^15.14.0",
|
||||
"postcss": "^8.4.49",
|
||||
"sass": "^1.83.0",
|
||||
"semantic-release": "^24.2.0",
|
||||
"tailwindcss": "^3.4.17",
|
||||
"typescript": "~5.6.2",
|
||||
"typescript-eslint": "^8.18.2",
|
||||
"vite": "^6.0.5"
|
||||
}
|
||||
}
|
6
postcss.config.js
Normal file
6
postcss.config.js
Normal file
|
@ -0,0 +1,6 @@
|
|||
export default {
|
||||
plugins: {
|
||||
tailwindcss: {},
|
||||
autoprefixer: {},
|
||||
},
|
||||
}
|
18
release.config.js
Normal file
18
release.config.js
Normal file
|
@ -0,0 +1,18 @@
|
|||
const config = {
|
||||
branches: ["main", "dev"],
|
||||
plugins: [
|
||||
"@semantic-release/commit-analyzer",
|
||||
"@semantic-release/release-notes-generator",
|
||||
[
|
||||
"@semantic-release/git",
|
||||
{
|
||||
assets: ["dist/*.js", "dist/*.js.map"],
|
||||
message:
|
||||
"chore(release): ${nextRelease.version} [skip ci]\n\n${nextRelease.notes}",
|
||||
},
|
||||
],
|
||||
"@semantic-release/github",
|
||||
],
|
||||
};
|
||||
|
||||
export default config;
|
15
src/components/App.tsx
Normal file
15
src/components/App.tsx
Normal file
|
@ -0,0 +1,15 @@
|
|||
import { lazy, Suspense } from "react";
|
||||
import "../i18n/i18n";
|
||||
|
||||
import LoadingLandingPage from "./ui/loadings/loadingLandingPage/LoadingLandingPage";
|
||||
const LandingPage = lazy(() => import("./pages/LandingPage"));
|
||||
|
||||
export default function App() {
|
||||
return (
|
||||
<>
|
||||
<Suspense fallback={<LoadingLandingPage />}>
|
||||
<LandingPage />
|
||||
</Suspense>
|
||||
</>
|
||||
);
|
||||
}
|
36
src/components/pages/LandingPage.tsx
Normal file
36
src/components/pages/LandingPage.tsx
Normal file
|
@ -0,0 +1,36 @@
|
|||
import { lazy, Suspense } from "react";
|
||||
import LoadingNavbar from "../ui/loadings/loadingNavbar/LoadingNavbar";
|
||||
import LoadingHeader from "../ui/loadings/loadingHeader/LoadingHeader";
|
||||
import LoadingInfo from "../ui/loadings/loadingInfo/LoadingInfo";
|
||||
import LoadingGames from "../ui/loadings/loadingGames/LoadingGames";
|
||||
import LoadingFooter from "../ui/loadings/loadingFooter/LoadingFooter";
|
||||
|
||||
const Navbar = lazy(() => import("./navbar/Navbar"));
|
||||
const Header = lazy(() => import("./header/Header"));
|
||||
const Info = lazy(() => import("./info/Info"));
|
||||
const Games = lazy(() => import("./games/Games"));
|
||||
const Footer = lazy(() => import("./footer/Footer"));
|
||||
|
||||
export default function LandingPage() {
|
||||
return (
|
||||
<>
|
||||
<Suspense fallback={<LoadingNavbar />}>
|
||||
<Navbar />
|
||||
</Suspense>
|
||||
<main className="grid gap-5 px-5 md:px-8 lg:px-14 xl:px-48 2xl:px-72 py-5 bg-gray-100 dark:bg-dark-mode-gray-2 transition">
|
||||
<Suspense fallback={<LoadingHeader />}>
|
||||
<Header />
|
||||
</Suspense>
|
||||
<Suspense fallback={<LoadingInfo />}>
|
||||
<Info />
|
||||
</Suspense>
|
||||
<Suspense fallback={<LoadingGames />}>
|
||||
<Games />
|
||||
</Suspense>
|
||||
</main>
|
||||
<Suspense fallback={<LoadingFooter />}>
|
||||
<Footer />
|
||||
</Suspense>
|
||||
</>
|
||||
);
|
||||
}
|
42
src/components/pages/footer/Footer.tsx
Normal file
42
src/components/pages/footer/Footer.tsx
Normal file
|
@ -0,0 +1,42 @@
|
|||
import { useTranslation } from "react-i18next";
|
||||
|
||||
interface FooterOption {
|
||||
title: string;
|
||||
url: string;
|
||||
}
|
||||
|
||||
export default function Footer() {
|
||||
const { t } = useTranslation(["footer"]);
|
||||
|
||||
const initialFooterOptions = t("options", {
|
||||
returnObjects: true,
|
||||
}) as FooterOption[];
|
||||
|
||||
return (
|
||||
<footer className="footer grid gap-3 px-5 sm:px-10 lg:px-24 py-4 sm:py-5 lg:py-12 dark:bg-dark-mode-black">
|
||||
<div className="text-center sm:text-left grid gap-3 justify-items-center sm:flex sm:justify-between sm:items-center">
|
||||
<div className="grid">
|
||||
<p className="text-xs lg:text-base dark:text-white">
|
||||
{t("contact")}
|
||||
</p>
|
||||
<p className="text-xs lg:text-base dark:text-white">
|
||||
{t("email")}
|
||||
</p>
|
||||
</div>
|
||||
<ul className="hidden md:flex sm:grid-cols-3 gap-3 sm:gap-x-2 sm:gap-y-1 lg:gap-x-6 lg:gap-y-2">
|
||||
{initialFooterOptions.map((option, i) => (
|
||||
<li
|
||||
key={i}
|
||||
className="text-xs lg:text-base text-gray-600 dark:text-dark-mode-gray hover:text-black dark:hover:text-white font-medium rounded-md cursor-pointer transition"
|
||||
>
|
||||
<a href={option.url}>{option.title}</a>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</div>
|
||||
<div className="grid place-items-center w-full">
|
||||
<p className="dark:text-white">{t("copyright")}</p>
|
||||
</div>
|
||||
</footer>
|
||||
);
|
||||
}
|
69
src/components/pages/games/Games.tsx
Normal file
69
src/components/pages/games/Games.tsx
Normal file
|
@ -0,0 +1,69 @@
|
|||
import { useTranslation } from "react-i18next";
|
||||
import { AiOutlinePicture } from "react-icons/ai";
|
||||
|
||||
interface GamesOption {
|
||||
title: string;
|
||||
descr: string;
|
||||
imgUrl: string;
|
||||
btnText: string;
|
||||
btnUrl: string;
|
||||
}
|
||||
|
||||
export default function Games() {
|
||||
const { t } = useTranslation(["games"]);
|
||||
|
||||
const initialGamesOptions = t("options", {
|
||||
returnObjects: true,
|
||||
}) as GamesOption[];
|
||||
|
||||
return (
|
||||
<section className="games grid gap-5">
|
||||
{initialGamesOptions.map((option, i) => (
|
||||
<div key={i} className="grid md:flex gap-5">
|
||||
{(i % 2 !== 0 || window.innerWidth < 768) && (
|
||||
<div className="grid place-items-center md:w-1/2 bg-gray-400 rounded-3xl">
|
||||
{option.imgUrl === "empty" ? (
|
||||
<AiOutlinePicture className="text-6xl text-white dark:text-black transition" />
|
||||
) : (
|
||||
<img
|
||||
src={option.imgUrl}
|
||||
alt={option.title}
|
||||
className="object-none w-full h-96 rounded-3xl"
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
<div className="grid justify-items-start content-between gap-5 md:w-1/2 p-10 bg-white dark:bg-dark-mode-black rounded-3xl transition">
|
||||
<div className="grid content-start gap-2 md:gap-4">
|
||||
<h1 className="text-3xl md:text-4xl dark:text-white transition">
|
||||
{option.title}
|
||||
</h1>
|
||||
<p className="text-xs lg:text-base text-gray-500 dark:text-dark-mode-gray transition">
|
||||
{option.descr}
|
||||
</p>
|
||||
</div>
|
||||
<a
|
||||
href={option.btnUrl}
|
||||
className="px-4 py-2 md:px-5 md:py-2.5 text-sm text-white font-medium bg-gray-800 hover:bg-gray-900 dark:bg-gray-800 dark:hover:bg-gray-700 dark:border-gray-700 focus:outline-none focus:ring-2 focus:ring-gray-300 rounded-lg dark:focus:ring-gray-700 transition"
|
||||
>
|
||||
{option.btnText}
|
||||
</a>
|
||||
</div>
|
||||
{i % 2 === 0 && window.innerWidth > 768 && (
|
||||
<div className="grid place-items-center md:w-1/2 bg-gray-400 rounded-3xl">
|
||||
{option.imgUrl === "empty" ? (
|
||||
<AiOutlinePicture className="text-6xl text-white dark:text-black transition" />
|
||||
) : (
|
||||
<img
|
||||
src={option.imgUrl}
|
||||
alt={option.title}
|
||||
className="object-none w-full h-96 rounded-3xl"
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
))}
|
||||
</section>
|
||||
);
|
||||
}
|
44
src/components/pages/header/Header.tsx
Normal file
44
src/components/pages/header/Header.tsx
Normal file
|
@ -0,0 +1,44 @@
|
|||
import { useCallback } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
// import { AiOutlinePicture } from "react-icons/ai";
|
||||
|
||||
export default function Header() {
|
||||
const { t } = useTranslation(["header"]);
|
||||
|
||||
const handleSendFooter = useCallback(() => {
|
||||
window.scrollTo({
|
||||
top: 9999,
|
||||
left: 0,
|
||||
behavior: "smooth",
|
||||
});
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<header className="header grid md:flex gap-5">
|
||||
<div className="grid justify-items-start content-between gap-5 md:w-1/2 h-80 md:h-96 p-5 md:p-8 lg:p-10 bg-white dark:bg-dark-mode-black rounded-3xl transition">
|
||||
<div className="grid content-start gap-2 md:gap-4">
|
||||
<h1 className="text-3xl md:text-4xl dark:text-white transition">
|
||||
{t("title")}
|
||||
</h1>
|
||||
<p className="text-xs lg:text-base text-gray-500 dark:text-dark-mode-gray transition">
|
||||
{t("descr")}
|
||||
</p>
|
||||
</div>
|
||||
<button
|
||||
className="px-4 py-2 md:px-5 md:py-2.5 text-sm text-white font-medium bg-gray-800 hover:bg-gray-900 dark:bg-gray-800 dark:hover:bg-gray-700 dark:border-gray-700 focus:outline-none focus:ring-2 focus:ring-gray-300 rounded-lg dark:focus:ring-gray-700 transition"
|
||||
onClick={handleSendFooter}
|
||||
>
|
||||
{t("btnText")}
|
||||
</button>
|
||||
</div>
|
||||
<div className="grid place-items-center md:w-1/2 h-80 md:h-96 bg-gray-400 rounded-3xl">
|
||||
{/* <AiOutlinePicture className="text-6xl text-white dark:text-black transition" /> */}
|
||||
<img
|
||||
src="https://node1.sloudhost.ovh/sloudpl/servers.jpg"
|
||||
alt="hosting"
|
||||
className="object-fill w-full h-80 md:h-96 rounded-3xl"
|
||||
/>
|
||||
</div>
|
||||
</header>
|
||||
);
|
||||
}
|
58
src/components/pages/info/Info.tsx
Normal file
58
src/components/pages/info/Info.tsx
Normal file
|
@ -0,0 +1,58 @@
|
|||
import { useTranslation } from "react-i18next";
|
||||
import { GoClockFill } from "react-icons/go";
|
||||
import { IoShieldSharp } from "react-icons/io5";
|
||||
import { MdAutoFixHigh } from "react-icons/md";
|
||||
import { FaAngleDoubleUp } from "react-icons/fa";
|
||||
|
||||
interface InfoOption {
|
||||
title: string;
|
||||
descr: string;
|
||||
}
|
||||
|
||||
const initialInfoIcons = [
|
||||
GoClockFill,
|
||||
MdAutoFixHigh,
|
||||
IoShieldSharp,
|
||||
FaAngleDoubleUp,
|
||||
];
|
||||
|
||||
export default function Info() {
|
||||
const { t } = useTranslation(["info"]);
|
||||
|
||||
const initialInfoOptions = t("options", {
|
||||
returnObjects: true,
|
||||
}) as InfoOption[];
|
||||
|
||||
return (
|
||||
<section className="info grid md:flex justify-between gap-5 p-10 bg-white dark:bg-dark-mode-black rounded-3xl transition">
|
||||
<div className="grid content-start gap-2 md:gap-4">
|
||||
<h2 className="text-2xl md:text-3xl dark:text-white transition">
|
||||
{t("title")}
|
||||
</h2>
|
||||
<p className="text-xs lg:text-base text-gray-500 dark:text-dark-mode-gray transition">
|
||||
{t("descr")}
|
||||
</p>
|
||||
</div>
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-x-10 md:w-1/2">
|
||||
{initialInfoIcons.map((Icon, i) => (
|
||||
<div
|
||||
key={i}
|
||||
className="grid gap-2 py-5 border-t first:border-t-0 md:border-t-0 md:[&:nth-child(3)]:mt-5 md:[&:nth-child(3)]:pt-5 md:[&:nth-child(4)]:mt-5 md:[&:nth-child(4)]:pt-5 md:[&:nth-child(3)]:border-t md:[&:nth-child(4)]:border-t"
|
||||
>
|
||||
<div className="flex items-center gap-2">
|
||||
<div className="w-min p-1 md:p-2 text-xl md:text-2xl text-blue-500 bg-blue-100 rounded-lg transition">
|
||||
<Icon />
|
||||
</div>
|
||||
<h3 className="text-lg lg:text-xl dark:text-white font-medium transition">
|
||||
{initialInfoOptions[i].title}
|
||||
</h3>
|
||||
</div>
|
||||
<p className="text-xs lg:text-base text-gray-500 dark:text-dark-mode-gray transition">
|
||||
{initialInfoOptions[i].descr}
|
||||
</p>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</section>
|
||||
);
|
||||
}
|
175
src/components/pages/navbar/Navbar.tsx
Normal file
175
src/components/pages/navbar/Navbar.tsx
Normal file
|
@ -0,0 +1,175 @@
|
|||
import { useCallback, useEffect, useRef, useState } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { FaMoon, FaBars, FaTimes } from "react-icons/fa";
|
||||
import { IoSunny } from "react-icons/io5";
|
||||
import useClickOutside from "../../../hooks/UseClickOutside";
|
||||
|
||||
interface NavbarOption {
|
||||
title: string;
|
||||
url: string;
|
||||
}
|
||||
|
||||
export default function Navbar() {
|
||||
const [isDarkMode, setIsDarkMode] = useState(false);
|
||||
const [isMenuOpen, setIsMenuOpen] = useState(false);
|
||||
const [isMenuLangOpen, setIsMenuLangOpen] = useState(false);
|
||||
const refContainerMenu = useRef(null);
|
||||
const refContainerMenuLang = useRef(null);
|
||||
const { t, i18n } = useTranslation(["navbar"]);
|
||||
|
||||
const initialNavbarOptions = t("options", {
|
||||
returnObjects: true,
|
||||
}) as NavbarOption[];
|
||||
|
||||
useClickOutside(refContainerMenu, () => {
|
||||
setIsMenuOpen(false);
|
||||
});
|
||||
|
||||
useClickOutside(refContainerMenuLang, () => {
|
||||
setIsMenuLangOpen(false);
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
const savedTheme = localStorage.getItem("theme");
|
||||
|
||||
if (savedTheme) {
|
||||
const mode = savedTheme === "dark" ? "dark" : "light";
|
||||
|
||||
setIsDarkMode(savedTheme === "dark");
|
||||
localStorage.setItem("theme", mode);
|
||||
document.documentElement.classList.add(mode);
|
||||
} else {
|
||||
const prefersDark = window.matchMedia(
|
||||
"(prefers-color-scheme: dark)",
|
||||
).matches;
|
||||
const mode = prefersDark ? "dark" : "light";
|
||||
|
||||
setIsDarkMode(prefersDark);
|
||||
localStorage.setItem("theme", mode);
|
||||
document.documentElement.classList.add(mode);
|
||||
}
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
const savedLanguage = sessionStorage.getItem("language");
|
||||
if (savedLanguage) {
|
||||
i18n.changeLanguage(savedLanguage);
|
||||
}
|
||||
}, [i18n]);
|
||||
|
||||
const handleDarkMode = useCallback(() => {
|
||||
setIsDarkMode(!isDarkMode);
|
||||
|
||||
if (!isDarkMode) {
|
||||
document.documentElement.classList.add("dark");
|
||||
localStorage.setItem("theme", "dark");
|
||||
} else {
|
||||
document.documentElement.classList.remove("dark");
|
||||
localStorage.setItem("theme", "light");
|
||||
}
|
||||
}, [isDarkMode]);
|
||||
|
||||
const handleMenu = useCallback(() => {
|
||||
setIsMenuOpen(!isMenuOpen);
|
||||
}, [isMenuOpen]);
|
||||
|
||||
const handleMenuLang = useCallback(() => {
|
||||
setIsMenuLangOpen(!isMenuLangOpen);
|
||||
}, [isMenuLangOpen]);
|
||||
|
||||
const changeLanguage = useCallback(
|
||||
(lng: string) => {
|
||||
i18n.changeLanguage(lng);
|
||||
sessionStorage.setItem("language", lng);
|
||||
},
|
||||
[i18n],
|
||||
);
|
||||
|
||||
const handleChangeLanguage = useCallback(
|
||||
(land: string) => {
|
||||
changeLanguage(land);
|
||||
setIsMenuLangOpen(false);
|
||||
},
|
||||
[changeLanguage],
|
||||
);
|
||||
|
||||
return (
|
||||
<nav className="navbar sticky top-0 left-0 right-0 flex items-center justify-between px-5 sm:px-10 lg:px-24 py-3 md:py-4 bg-white dark:bg-dark-mode-black border-b dark:border-dark-mode-gray transition z-50">
|
||||
<h3 className="text-2xl md:text-3xl lg:text-4xl font-semibold dark:text-white transition">
|
||||
SloudPL
|
||||
</h3>
|
||||
<ul className="hidden md:flex justify-center items-center gap-1 lg:gap-4 w-full">
|
||||
{initialNavbarOptions.map((option, i) => (
|
||||
<li
|
||||
key={i}
|
||||
className="px-2 py-1 lg:px-3 lg:py-2 text-xs lg:text-base xl:text-lg dark:text-white hover:bg-gray-100 dark:hover:bg-dark-mode-gray-2 rounded-md cursor-pointer transition"
|
||||
>
|
||||
<a href={option.url}>{option.title}</a>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
<div className="flex items-center gap-2 md:gap-3">
|
||||
<button
|
||||
className="p-1 lg:p-2 text-2xl dark:text-white hover:bg-gray-100 dark:hover:bg-dark-mode-gray-2 rounded-md transition"
|
||||
onClick={handleDarkMode}
|
||||
>
|
||||
{isDarkMode ? <FaMoon /> : <IoSunny />}
|
||||
</button>
|
||||
<div className="relative">
|
||||
<button
|
||||
className="p-1 lg:p-2 text-base dark:text-white hover:bg-gray-100 dark:hover:bg-dark-mode-gray-2 rounded-md transition"
|
||||
onClick={handleMenuLang}
|
||||
>
|
||||
{i18n.language.toUpperCase()}
|
||||
</button>
|
||||
{isMenuLangOpen && (
|
||||
<ul
|
||||
ref={refContainerMenuLang}
|
||||
className="absolute right-0 w-32 bg-white dark:bg-dark-mode-black border rounded-md shadow-lg"
|
||||
>
|
||||
<li
|
||||
className="px-3 py-2 text-base dark:text-white hover:bg-gray-100 dark:hover:bg-dark-mode-gray-2 cursor-pointer transition"
|
||||
onClick={() => {
|
||||
handleChangeLanguage("pl");
|
||||
}}
|
||||
>
|
||||
PL
|
||||
</li>
|
||||
<li
|
||||
className="px-3 py-2 text-base dark:text-white hover:bg-gray-100 dark:hover:bg-dark-mode-gray-2 cursor-pointer transition"
|
||||
onClick={() => {
|
||||
handleChangeLanguage("en");
|
||||
}}
|
||||
>
|
||||
EN
|
||||
</li>
|
||||
</ul>
|
||||
)}
|
||||
</div>
|
||||
<button
|
||||
className="text-2xl md:hidden dark:text-white transition"
|
||||
onClick={handleMenu}
|
||||
>
|
||||
{isMenuOpen ? <FaTimes /> : <FaBars />}
|
||||
</button>
|
||||
</div>
|
||||
{isMenuOpen && (
|
||||
<div className="absolute top-full left-0 md:hidden w-full h-svh bg-black/50">
|
||||
<ul
|
||||
ref={refContainerMenu}
|
||||
className="flex flex-col gap-2 p-4 bg-white dark:bg-dark-mode-black border-t shadow-md transition"
|
||||
>
|
||||
{initialNavbarOptions.map((option, i) => (
|
||||
<li
|
||||
key={i}
|
||||
className="px-3 py-2 text-base dark:text-white hover:bg-gray-100 dark:hover:bg-dark-mode-gray-2 rounded-md cursor-pointer transition"
|
||||
>
|
||||
<a href={option.url}>{option.title}</a>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</div>
|
||||
)}
|
||||
</nav>
|
||||
);
|
||||
}
|
20
src/components/ui/loadings/loadingFooter/LoadingFooter.tsx
Normal file
20
src/components/ui/loadings/loadingFooter/LoadingFooter.tsx
Normal file
|
@ -0,0 +1,20 @@
|
|||
import Skeleton from "react-loading-skeleton";
|
||||
import "react-loading-skeleton/dist/skeleton.css";
|
||||
|
||||
export default function LoadingFooter() {
|
||||
return (
|
||||
<footer className="grid gap-3 px-5 sm:px-10 lg:px-24 py-4 sm:py-5 lg:py-12 dark:bg-dark-mode-black">
|
||||
<div className="flex justify-center md:justify-between">
|
||||
<div className="">
|
||||
<Skeleton width="200px" height="50px" />
|
||||
</div>
|
||||
<div className="hidden md:block w-[500px] xl:w-[700px]">
|
||||
<Skeleton width="100%" height="50px" />
|
||||
</div>
|
||||
</div>
|
||||
<div className="text-center">
|
||||
<Skeleton width="200px" height="40px" />
|
||||
</div>
|
||||
</footer>
|
||||
);
|
||||
}
|
23
src/components/ui/loadings/loadingGames/LoadingGames.tsx
Normal file
23
src/components/ui/loadings/loadingGames/LoadingGames.tsx
Normal file
|
@ -0,0 +1,23 @@
|
|||
import Skeleton from "react-loading-skeleton";
|
||||
import "react-loading-skeleton/dist/skeleton.css";
|
||||
|
||||
export default function LoadingGames() {
|
||||
return (
|
||||
<section className="grid gap-5">
|
||||
{[...Array(4)].map((_, i) => (
|
||||
<div key={i} className="grid md:flex gap-5">
|
||||
<div className="md:w-1/2 h-80 md:h-96">
|
||||
<div className="w-full h-full">
|
||||
<Skeleton width="100%" height="100%" />
|
||||
</div>
|
||||
</div>
|
||||
<div className="md:w-1/2 h-80 md:h-96">
|
||||
<div className="w-full h-full">
|
||||
<Skeleton width="100%" height="100%" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</section>
|
||||
);
|
||||
}
|
19
src/components/ui/loadings/loadingHeader/LoadingHeader.tsx
Normal file
19
src/components/ui/loadings/loadingHeader/LoadingHeader.tsx
Normal file
|
@ -0,0 +1,19 @@
|
|||
import Skeleton from "react-loading-skeleton";
|
||||
import "react-loading-skeleton/dist/skeleton.css";
|
||||
|
||||
export default function LoadingHeader() {
|
||||
return (
|
||||
<header className="grid md:flex gap-5">
|
||||
<div className="md:w-1/2 h-80 md:h-96">
|
||||
<div className="w-full h-full">
|
||||
<Skeleton width="100%" height="100%" />
|
||||
</div>
|
||||
</div>
|
||||
<div className="md:w-1/2 h-80 md:h-96">
|
||||
<div className="w-full h-full">
|
||||
<Skeleton width="100%" height="100%" />
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
);
|
||||
}
|
14
src/components/ui/loadings/loadingInfo/LoadingInfo.tsx
Normal file
14
src/components/ui/loadings/loadingInfo/LoadingInfo.tsx
Normal file
|
@ -0,0 +1,14 @@
|
|||
import Skeleton from "react-loading-skeleton";
|
||||
import "react-loading-skeleton/dist/skeleton.css";
|
||||
|
||||
export default function LoadingInfo() {
|
||||
return (
|
||||
<section>
|
||||
<div className="w-full h-80 md:h-96">
|
||||
<div className="w-full h-full">
|
||||
<Skeleton width="100%" height="100%" />
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
);
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
import { BeatLoader } from "react-spinners";
|
||||
|
||||
export default function LoadingLandingPage() {
|
||||
return (
|
||||
<div className="flex justify-center items-center w-screen h-screen">
|
||||
<h3 className="text-4xl">Loading...</h3>
|
||||
<BeatLoader className="mt-2" color="#0096FF" size={15} />
|
||||
</div>
|
||||
);
|
||||
}
|
18
src/components/ui/loadings/loadingNavbar/LoadingNavbar.tsx
Normal file
18
src/components/ui/loadings/loadingNavbar/LoadingNavbar.tsx
Normal file
|
@ -0,0 +1,18 @@
|
|||
import Skeleton from "react-loading-skeleton";
|
||||
import "react-loading-skeleton/dist/skeleton.css";
|
||||
|
||||
export default function LoadingNavbar() {
|
||||
return (
|
||||
<nav className="sticky top-0 left-0 right-0 flex justify-between items-center px-5 sm:px-10 lg:px-24 py-3 md:py-4 bg-white dark:bg-dark-mode-black border-b dark:border-dark-mode-gray transition z-50">
|
||||
<div className="">
|
||||
<Skeleton width="65px" height="50px" />
|
||||
</div>
|
||||
<div className="hidden md:block">
|
||||
<Skeleton width="500px" height="50px" />
|
||||
</div>
|
||||
<div>
|
||||
<Skeleton width="100px" height="50px" />
|
||||
</div>
|
||||
</nav>
|
||||
);
|
||||
}
|
33
src/hooks/UseClickOutside.tsx
Normal file
33
src/hooks/UseClickOutside.tsx
Normal file
|
@ -0,0 +1,33 @@
|
|||
import { useEffect } from "react";
|
||||
|
||||
const useClickOutside = (
|
||||
ref: React.RefObject<HTMLElement>,
|
||||
callback: () => void,
|
||||
exceptions?: React.RefObject<HTMLElement>[],
|
||||
) => {
|
||||
useEffect(() => {
|
||||
const handleClickOutside = (event: MouseEvent) => {
|
||||
const isException =
|
||||
exceptions?.some(
|
||||
(exception) =>
|
||||
exception.current &&
|
||||
exception.current.contains(event.target as Node),
|
||||
) ?? false;
|
||||
|
||||
if (
|
||||
ref.current &&
|
||||
!ref.current.contains(event.target as Node) &&
|
||||
!isException
|
||||
) {
|
||||
callback();
|
||||
}
|
||||
};
|
||||
|
||||
document.addEventListener("mousedown", handleClickOutside);
|
||||
return () => {
|
||||
document.removeEventListener("mousedown", handleClickOutside);
|
||||
};
|
||||
}, [ref, callback, exceptions]);
|
||||
};
|
||||
|
||||
export default useClickOutside;
|
44
src/i18n/i18n.ts
Normal file
44
src/i18n/i18n.ts
Normal file
|
@ -0,0 +1,44 @@
|
|||
import i18next from "i18next";
|
||||
import { initReactI18next } from "react-i18next";
|
||||
import LanguageDetector from "i18next-browser-languagedetector";
|
||||
|
||||
import navbarEn from "../locales/en/navbar.json";
|
||||
import navbarPl from "../locales/pl/navbar.json";
|
||||
import headerEn from "../locales/en/header.json";
|
||||
import headerPl from "../locales/pl/header.json";
|
||||
import infoEn from "../locales/en/info.json";
|
||||
import infoPl from "../locales/pl/info.json";
|
||||
import gamesEn from "../locales/en/games.json";
|
||||
import gamesPl from "../locales/pl/games.json";
|
||||
import footerEn from "../locales/en/footer.json";
|
||||
import footerPl from "../locales/pl/footer.json";
|
||||
|
||||
const resources = {
|
||||
en: {
|
||||
navbar: navbarEn,
|
||||
header: headerEn,
|
||||
info: infoEn,
|
||||
games: gamesEn,
|
||||
footer: footerEn,
|
||||
},
|
||||
pl: {
|
||||
navbar: navbarPl,
|
||||
header: headerPl,
|
||||
info: infoPl,
|
||||
games: gamesPl,
|
||||
footer: footerPl,
|
||||
},
|
||||
};
|
||||
|
||||
i18next
|
||||
.use(initReactI18next)
|
||||
.use(LanguageDetector)
|
||||
.init({
|
||||
supportedLngs: ["en", "pl"],
|
||||
resources,
|
||||
debug: false,
|
||||
fallbackLng: "en",
|
||||
saveMissing: true,
|
||||
});
|
||||
|
||||
export default i18next;
|
31
src/locales/en/footer.json
Normal file
31
src/locales/en/footer.json
Normal file
|
@ -0,0 +1,31 @@
|
|||
{
|
||||
"contact": "Contact:",
|
||||
"email": "E-Mail: main@sloudhost.ovh",
|
||||
"options": [
|
||||
{
|
||||
"title": "Home Page",
|
||||
"url": "#"
|
||||
},
|
||||
{
|
||||
"title": "Applications",
|
||||
"url": "https://apps.sloudhost.ovh/"
|
||||
},
|
||||
{
|
||||
"title": "Status",
|
||||
"url": "https://status.sloudhost.ovh/"
|
||||
},
|
||||
{
|
||||
"title": "Hosting",
|
||||
"url": "https://billing.sloudhost.ovh/"
|
||||
},
|
||||
{
|
||||
"title": "Discord",
|
||||
"url": "https://sloudhost.ovh/discord/"
|
||||
},
|
||||
{
|
||||
"title": "SloudClient",
|
||||
"url": "https://sloudhost.ovh/mc/client/"
|
||||
}
|
||||
],
|
||||
"copyright": "Copyright SLOUDHOST.OVH © 2024"
|
||||
}
|
32
src/locales/en/games.json
Normal file
32
src/locales/en/games.json
Normal file
|
@ -0,0 +1,32 @@
|
|||
{
|
||||
"options": [
|
||||
{
|
||||
"title": "Minecraft",
|
||||
"descr": "Minecraft is an open-world survival video game created by Markus Persson and developed by Mojang Studios. Minecraft allows players to build and destroy objects located in a randomly generated game world. The player can attack creatures they encounter, collect resources, and craft items.",
|
||||
"imgUrl": "https://node1.sloudhost.ovh/sloudpl/minecraft.jpg",
|
||||
"btnText": "Minecraft Page",
|
||||
"btnUrl": "https://sloud.pl/mc/"
|
||||
},
|
||||
{
|
||||
"title": "Rust",
|
||||
"descr": "The only goal in Rust is survival. Everything wants you to die: the island's wildlife and other inhabitants, the environment, other survivors. Do whatever it takes to survive another night.",
|
||||
"imgUrl": "https://node1.sloudhost.ovh/sloudpl/rust.jpg",
|
||||
"btnText": "Join",
|
||||
"btnUrl": "steam://connect/node.sloud.pl:28017"
|
||||
},
|
||||
{
|
||||
"title": "CS2",
|
||||
"descr": "CS2 builds on the team-based action gameplay that the series pioneered when it launched over 20 years ago. CS:GO features new maps, characters, weapons, and game modes, and offers updated versions of classic CS and CS:GO content.",
|
||||
"imgUrl": "https://node1.sloudhost.ovh/sloudpl/cs2.jpg",
|
||||
"btnText": "List of our servers",
|
||||
"btnUrl": "https://gosetti.pl/serwery?HostnameIpPort=SLOUD.PL"
|
||||
},
|
||||
{
|
||||
"title": "Hosting Panel",
|
||||
"descr": "Hosting Panel is a tool that allows you to manage your server. With it, you can easily monitor and configure.",
|
||||
"imgUrl": "https://node1.sloudhost.ovh/sloudpl/servers.jpg",
|
||||
"btnText": "Hosting Panel",
|
||||
"btnUrl": "https://panel.sloudhost.ovh/"
|
||||
}
|
||||
]
|
||||
}
|
5
src/locales/en/header.json
Normal file
5
src/locales/en/header.json
Normal file
|
@ -0,0 +1,5 @@
|
|||
{
|
||||
"title": "Super fast and secure gaming server",
|
||||
"descr": "Experience unparalleled speed and top-notch security with our state-of-the-art gaming server. Designed for gamers who demand the best, our server ensures smooth gameplay and robust protection against threats.",
|
||||
"btnText": "Swipe down"
|
||||
}
|
22
src/locales/en/info.json
Normal file
22
src/locales/en/info.json
Normal file
|
@ -0,0 +1,22 @@
|
|||
{
|
||||
"title": "Finally, a better way to gaming servers",
|
||||
"descr": "Our main pillars to create the best gaming server experience.",
|
||||
"options": [
|
||||
{
|
||||
"title": "Low Latency",
|
||||
"descr": "Our servers are strategically located to ensure minimal ping for a seamless gaming experience."
|
||||
},
|
||||
{
|
||||
"title": "By players for players",
|
||||
"descr": "Servers were created by players for players!"
|
||||
},
|
||||
{
|
||||
"title": "High Security",
|
||||
"descr": "Our servers are protected with top-notch security measures to keep your data safe."
|
||||
},
|
||||
{
|
||||
"title": "Scalable",
|
||||
"descr": "We can easily scale server resources to meet the growing number of players and game demands."
|
||||
}
|
||||
]
|
||||
}
|
28
src/locales/en/navbar.json
Normal file
28
src/locales/en/navbar.json
Normal file
|
@ -0,0 +1,28 @@
|
|||
{
|
||||
"options": [
|
||||
{
|
||||
"title": "Home Page",
|
||||
"url": "#"
|
||||
},
|
||||
{
|
||||
"title": "Applications",
|
||||
"url": "https://apps.sloudhost.ovh/"
|
||||
},
|
||||
{
|
||||
"title": "Status",
|
||||
"url": "https://status.sloudhost.ovh/"
|
||||
},
|
||||
{
|
||||
"title": "Hosting",
|
||||
"url": "https://panel.sloudhost.ovh/"
|
||||
},
|
||||
{
|
||||
"title": "Discord",
|
||||
"url": "https://sloudhost.ovh/discord/"
|
||||
},
|
||||
{
|
||||
"title": "SloudClient",
|
||||
"url": "https://sloudhost.ovh/mc/client/"
|
||||
}
|
||||
]
|
||||
}
|
31
src/locales/pl/footer.json
Normal file
31
src/locales/pl/footer.json
Normal file
|
@ -0,0 +1,31 @@
|
|||
{
|
||||
"contact": "Kontakt:",
|
||||
"email": "E-Mail: pomoc@sloudhost.ovh",
|
||||
"options": [
|
||||
{
|
||||
"title": "Strona Główna",
|
||||
"url": "#"
|
||||
},
|
||||
{
|
||||
"title": "Aplikacje",
|
||||
"url": "https://apps.sloudhost.ovh/"
|
||||
},
|
||||
{
|
||||
"title": "Status",
|
||||
"url": "https://status.sloudhost.ovh/"
|
||||
},
|
||||
{
|
||||
"title": "Hosting",
|
||||
"url": "https://billing.sloudhost.ovh/"
|
||||
},
|
||||
{
|
||||
"title": "Discord",
|
||||
"url": "https://sloudhost.ovh/discord/"
|
||||
},
|
||||
{
|
||||
"title": "SloudClient",
|
||||
"url": "https://sloudhost.ovh/mc/client/"
|
||||
}
|
||||
],
|
||||
"copyright": "Copyright SLOUDHOST.OVH © 2024"
|
||||
}
|
32
src/locales/pl/games.json
Normal file
32
src/locales/pl/games.json
Normal file
|
@ -0,0 +1,32 @@
|
|||
{
|
||||
"options": [
|
||||
{
|
||||
"title": "Minecraft",
|
||||
"descr": "Minecraft to gra survivalowa z otwartym światem stworzona przez Markusa Perssona i rozwijana przez Mojang Studios. Minecraft pozwala graczom budować i niszczyć obiekty znajdujące się w losowo generowanym świecie gry. Gracz może atakować napotkane stworzenia, zbierać zasoby i tworzyć przedmioty.",
|
||||
"imgUrl": "https://node1.sloudhost.ovh/sloudpl/minecraft.jpg",
|
||||
"btnText": "Strona Minecraft",
|
||||
"btnUrl": "https://sloud.pl/mc/"
|
||||
},
|
||||
{
|
||||
"title": "Rust",
|
||||
"descr": "Jedynym celem w Rust jest przetrwanie. Wszystko chce, żebyś umarł: dzika przyroda wyspy i inni mieszkańcy, środowisko, inni ocaleni. Zrób wszystko, aby przetrwać kolejną noc.",
|
||||
"imgUrl": "https://node1.sloudhost.ovh/sloudpl/rust.jpg",
|
||||
"btnText": "Dołącz",
|
||||
"btnUrl": "steam://connect/node.sloudhost.ovh:28017"
|
||||
},
|
||||
{
|
||||
"title": "CS2",
|
||||
"descr": "CS2 opiera się na zespołowej rozgrywce akcji, którą seria zapoczątkowała ponad 20 lat temu. CS:GO oferuje nowe mapy, postacie, bronie i tryby gry oraz zaktualizowane wersje klasycznych treści CS i CS:GO.",
|
||||
"imgUrl": "https://node1.sloudhost.ovh/sloudpl/cs2.jpg",
|
||||
"btnText": "Lista naszych serwerów",
|
||||
"btnUrl": "https://gosetti.pl/serwery?HostnameIpPort=SLOUD.PL"
|
||||
},
|
||||
{
|
||||
"title": "Panel Hostingowy",
|
||||
"descr": "Panel Hostingowy to narzędzie umożliwiające zarządzanie serwerem. Dzięki niemu możesz łatwo monitorować i konfigurować.",
|
||||
"imgUrl": "https://node1.sloudhost.ovh/sloudpl/servers.jpg",
|
||||
"btnText": "Panel Hostingowy",
|
||||
"btnUrl": "https://panel.sloudhost.ovh/"
|
||||
}
|
||||
]
|
||||
}
|
5
src/locales/pl/header.json
Normal file
5
src/locales/pl/header.json
Normal file
|
@ -0,0 +1,5 @@
|
|||
{
|
||||
"title": "Super szybki i bezpieczny serwer do gier",
|
||||
"descr": "Doświadcz niezrównanej prędkości i najwyższej klasy bezpieczeństwa dzięki naszemu nowoczesnemu serwerowi do gier. Zaprojektowany dla graczy, którzy wymagają najlepszego, nasz serwer zapewnia płynną rozgrywkę i solidną ochronę przed zagrożeniami.",
|
||||
"btnText": "Przesuń w dół"
|
||||
}
|
22
src/locales/pl/info.json
Normal file
22
src/locales/pl/info.json
Normal file
|
@ -0,0 +1,22 @@
|
|||
{
|
||||
"title": "Wreszcie lepszy sposób na serwery gier",
|
||||
"descr": "Nasze główne filary tworzenia najlepszego doświadczenia serwera gier.",
|
||||
"options": [
|
||||
{
|
||||
"title": "Niskie opóźnienie",
|
||||
"descr": "Nasze serwery są strategicznie rozmieszczone, aby zapewnić minimalny ping dla płynnej rozgrywki."
|
||||
},
|
||||
{
|
||||
"title": "Od graczy dla graczy",
|
||||
"descr": "Serwery zostały stworzone przez graczy dla graczy!"
|
||||
},
|
||||
{
|
||||
"title": "Wysokie bezpieczeństwo",
|
||||
"descr": "Nasze serwery są chronione najwyższej klasy środkami bezpieczeństwa, aby chronić Twoje dane."
|
||||
},
|
||||
{
|
||||
"title": "Skalowalność",
|
||||
"descr": "Łatwo możemy skalować zasoby serwerów, aby sprostać rosnącej liczbie graczy i wymaganiom gry."
|
||||
}
|
||||
]
|
||||
}
|
28
src/locales/pl/navbar.json
Normal file
28
src/locales/pl/navbar.json
Normal file
|
@ -0,0 +1,28 @@
|
|||
{
|
||||
"options": [
|
||||
{
|
||||
"title": "Strona Główna",
|
||||
"url": "#"
|
||||
},
|
||||
{
|
||||
"title": "Aplikacje",
|
||||
"url": "https://apps.sloudhost.ovh/"
|
||||
},
|
||||
{
|
||||
"title": "Status",
|
||||
"url": "https://status.sloudhost.ovh/"
|
||||
},
|
||||
{
|
||||
"title": "Hosting",
|
||||
"url": "https://billing.sloudhost.ovh/"
|
||||
},
|
||||
{
|
||||
"title": "Discord",
|
||||
"url": "https://sloudhost.ovh/discord/"
|
||||
},
|
||||
{
|
||||
"title": "SloudClient",
|
||||
"url": "https://sloudhost.ovh/mc/client/"
|
||||
}
|
||||
]
|
||||
}
|
11
src/main.tsx
Normal file
11
src/main.tsx
Normal file
|
@ -0,0 +1,11 @@
|
|||
import { StrictMode } from "react";
|
||||
import { createRoot } from "react-dom/client";
|
||||
import "./style/index.scss";
|
||||
|
||||
import App from "./components/App.tsx";
|
||||
|
||||
createRoot(document.getElementById("root")!).render(
|
||||
<StrictMode>
|
||||
<App />
|
||||
</StrictMode>,
|
||||
);
|
3
src/style/index.scss
Normal file
3
src/style/index.scss
Normal file
|
@ -0,0 +1,3 @@
|
|||
@tailwind base;
|
||||
@tailwind components;
|
||||
@tailwind utilities;
|
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" />
|
16
tailwind.config.js
Normal file
16
tailwind.config.js
Normal file
|
@ -0,0 +1,16 @@
|
|||
// @type {import('tailwindcss').Config}
|
||||
export default {
|
||||
content: ["./index.html", "./src/**/*.{js,ts,jsx,tsx}"],
|
||||
darkMode: "class",
|
||||
theme: {
|
||||
extend: {
|
||||
colors: {
|
||||
"bright-blue": "#0096FF",
|
||||
"dark-mode-black": "#09090B",
|
||||
"dark-mode-gray": "#B5B5B6",
|
||||
"dark-mode-gray-2": "#27272A",
|
||||
},
|
||||
},
|
||||
},
|
||||
plugins: [],
|
||||
};
|
26
tsconfig.app.json
Normal file
26
tsconfig.app.json
Normal file
|
@ -0,0 +1,26 @@
|
|||
{
|
||||
"compilerOptions": {
|
||||
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo",
|
||||
"target": "ES2020",
|
||||
"useDefineForClassFields": true,
|
||||
"lib": ["ES2020", "DOM", "DOM.Iterable"],
|
||||
"module": "ESNext",
|
||||
"skipLibCheck": true,
|
||||
|
||||
/* Bundler mode */
|
||||
"moduleResolution": "bundler",
|
||||
"allowImportingTsExtensions": true,
|
||||
"isolatedModules": true,
|
||||
"moduleDetection": "force",
|
||||
"noEmit": true,
|
||||
"jsx": "react-jsx",
|
||||
|
||||
/* Linting */
|
||||
"strict": true,
|
||||
"noUnusedLocals": true,
|
||||
"noUnusedParameters": true,
|
||||
"noFallthroughCasesInSwitch": true,
|
||||
"noUncheckedSideEffectImports": true
|
||||
},
|
||||
"include": ["src"]
|
||||
}
|
7
tsconfig.json
Normal file
7
tsconfig.json
Normal file
|
@ -0,0 +1,7 @@
|
|||
{
|
||||
"files": [],
|
||||
"references": [
|
||||
{ "path": "./tsconfig.app.json" },
|
||||
{ "path": "./tsconfig.node.json" }
|
||||
]
|
||||
}
|
24
tsconfig.node.json
Normal file
24
tsconfig.node.json
Normal file
|
@ -0,0 +1,24 @@
|
|||
{
|
||||
"compilerOptions": {
|
||||
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo",
|
||||
"target": "ES2022",
|
||||
"lib": ["ES2023"],
|
||||
"module": "ESNext",
|
||||
"skipLibCheck": true,
|
||||
|
||||
/* Bundler mode */
|
||||
"moduleResolution": "bundler",
|
||||
"allowImportingTsExtensions": true,
|
||||
"isolatedModules": true,
|
||||
"moduleDetection": "force",
|
||||
"noEmit": true,
|
||||
|
||||
/* Linting */
|
||||
"strict": true,
|
||||
"noUnusedLocals": true,
|
||||
"noUnusedParameters": true,
|
||||
"noFallthroughCasesInSwitch": true,
|
||||
"noUncheckedSideEffectImports": true
|
||||
},
|
||||
"include": ["vite.config.ts"]
|
||||
}
|
7
vite.config.ts
Normal file
7
vite.config.ts
Normal file
|
@ -0,0 +1,7 @@
|
|||
import { defineConfig } from 'vite'
|
||||
import react from '@vitejs/plugin-react'
|
||||
|
||||
// https://vite.dev/config/
|
||||
export default defineConfig({
|
||||
plugins: [react()],
|
||||
})
|
Loading…
Add table
Reference in a new issue