chore: update ESLint and Prettier configurations for improved code quality

- Removed the outdated .eslintrc.json file and replaced it with a new eslint.config.mjs file for better configuration management.
- Added .prettierrc.json to enforce consistent code formatting and included a .prettierignore file to exclude specific directories from formatting.
- Updated components.json to streamline alias definitions and ensure proper icon library usage.
- Enhanced package.json with new linting, formatting, and validation scripts to improve development workflow.
- Made various formatting adjustments across multiple files for consistency and clarity.
This commit is contained in:
Daniel Luiz Alves
2025-07-02 12:01:59 -03:00
parent 2c6699b604
commit 4fb7007db2
65 changed files with 3592 additions and 2821 deletions

View File

@@ -1,3 +0,0 @@
{
"extends": ["next/core-web-vitals", "next/typescript"]
}

View File

@@ -0,0 +1,4 @@
/node_modules
/.next
/out
/build

View File

@@ -0,0 +1,16 @@
{
"importOrder": [
"^(react/(.*)$)|^(react$)",
"^(next/(.*)$)|^(next$)",
"<THIRD_PARTY_MODULES>",
"",
"^@/(.*)$",
"^[./]"
],
"importOrderParserPlugins": ["typescript", "jsx", "decorators-legacy"],
"plugins": ["@ianvs/prettier-plugin-sort-imports", "prettier-plugin-sort-json"],
"printWidth": 120,
"singleQuote": false,
"tabWidth": 2,
"trailingComma": "es5"
}

View File

@@ -1,15 +1,5 @@
{
"$schema": "https://ui.shadcn.com/schema.json",
"style": "new-york",
"rsc": true,
"tsx": true,
"tailwind": {
"config": "",
"css": "src/app/global.css",
"baseColor": "neutral",
"cssVariables": true,
"prefix": ""
},
"aliases": {
"components": "@/components",
"utils": "@/lib/utils",
@@ -17,5 +7,15 @@
"lib": "@/lib",
"hooks": "@/hooks"
},
"iconLibrary": "lucide"
"iconLibrary": "lucide",
"rsc": true,
"style": "new-york",
"tailwind": {
"config": "",
"css": "src/app/global.css",
"baseColor": "neutral",
"cssVariables": true,
"prefix": ""
},
"tsx": true
}

View File

@@ -18,7 +18,6 @@ The API documentation is powered by **[Scalar](https://scalar.com/)**, which pro
![Palmr API Documentation](/assets/v2/api-docs/scalar.png)
We have made a deliberate decision to **not provide an online version** of the API documentation, as the endpoints and functionality may vary significantly depending on the specific version of Palmr. you have deployed in your environment. To ensure you're always working with accurate and version-specific documentation, we strongly recommend accessing the documentation only after initializing your API service. It's important to note that the API service is specifically designated as the **server** component within the official Palmr. GitHub repository.
We strongly recommend utilizing **Scalar** as your primary tool for querying and testing the API, as the entire documentation system has been carefully optimized and designed with Scalar integration in mind. Scalar provides developers with an exceptionally intuitive and feature-rich interactive environment that streamlines the process of exploring endpoints, constructing and sending requests, and analyzing responses directly within its sophisticated interface.

View File

@@ -12,51 +12,50 @@ Understanding the architecture of Palmr. is crucial for both deploying and scali
Each component in the Palmr. architecture plays a vital role in ensuring reliability, performance, and scalability. The stack is built with simplicity, performance, and flexibility in mind, everything is self-hosted, developer-friendly, and designed to scale without adding unnecessary complexity.
### 💾 PostgreSQL
Palmr. uses **PostgreSQL** as the primary database solution. It's a powerful, open-source relational database thats trusted by developers around the world. PostgreSQL is fully ACID-compliant, which means it handles transactions safely and reliably. Its perfect for storing structured data like user accounts, file metadata, transfer logs, and anything else that requires consistency. With advanced features like full-text search, custom data types (like JSONB), and strong indexing capabilities, PostgreSQL gives us the tools to scale efficiently without giving up query performance or flexibility.
- Provides reliable and secure data storage, ensuring consistency and high performance for all database operations.
- Powerful indexing, query optimization, and support for complex data types.
- Ideal for handling large amounts of metadata and transactional data in a predictable and scalable way.
### 🎨 Next.js 15 + React + TypeScript
The frontend of Palmr. is built using **Next.js 15**, along with **React** and **TypeScript**, forming a modern stack thats easy to maintain and super fast for end users. Next.js 15 brings server components, server actions, and a new app router system that makes rendering dynamic content incredibly efficient. This allows us to load only whats needed, when its needed which makes the app feel snappy even under load. React provides a clean, component-based structure that makes it easy to break the UI into reusable pieces, and TypeScript helps prevent bugs before they even happen by enforcing static typing and better code navigation. Whether it's SSR, static pages, or dynamic user interactions, this trio handles it all seamlessly.
- **React** enables the creation of a dynamic and responsive user interface with a component-based architecture.
- **TypeScript** adds static typing, enhancing code quality and reducing runtime errors.
- **Next.js 15** handles routing, server-side rendering, and server components for performance at scale.
### 📦 MinIO
Palmr. uses **MinIO** for object storage. MinIO is a lightweight, high-performance, S3-compatible storage solution that makes file handling simple and scalable. Every file uploaded to Palmr. Whether it's a personal file transfer or a shared asset is stored in MinIO. Its built to handle huge amounts of data and can be deployed locally, on-premise, or in the cloud. Because it speaks the same API as Amazon S3, integrating with it is straightforward and familiar to most developers. And since its self-hosted, we have full control over performance, redundancy, and security.
- Supports high-throughput file storage and retrieval.
- Ensures data integrity and redundancy.
- Compatible with AWS S3 APIs, making integration seamless.
### ⚡ Fastify
The backend of Palmr. is powered by **Fastify**, a super-fast Node.js web framework optimized for performance and low overhead. Its designed to handle lots of concurrent requests with minimal resource usage, which is key for scalable backend services. Fastify also has a built-in schema validation system that ensures all incoming data is properly validated before reaching business logic, which helps prevent bugs and security issues. It follows a plugin-based architecture, making it easy to keep route handlers, services, and middlewares cleanly separated and easy to extend as the project grows.
- Provides fast request handling with a lightweight core.
- Built-in schema-based validation for secure and reliable API handling.
- Supports plugin-based architecture for easy extensibility.
### 🔄 How It Works
1. **Frontend** — React + TypeScript + Next.js 15 handle the user interface and user interactions.
2. **Backend** — Fastify processes requests and communicates with the database and storage layers.
3. **Database** — PostgreSQL stores metadata and transactional data.
4. **Object Storage** — MinIO stores the actual files and ensures scalable, high-performance storage.
### 📚 Useful Links
- [PostgreSQL Documentation](https://www.postgresql.org/docs/)
- [Next.js Documentation](https://nextjs.org/docs)
- [React Documentation](https://react.dev/)
- [TypeScript Handbook](https://www.typescriptlang.org/docs/)
- [MinIO Documentation](https://min.io/docs/minio/container/index.html)
- [Fastify Documentation](https://fastify.dev/docs/latest/)

View File

@@ -9,7 +9,7 @@ The project leverages next-intl, a powerful and flexible internationalization (i
---
| Language | Code | Description | Translation |
|----------|------|-------------|-------------|
| ------------- | ----- | -------------------------------------------------------- | ----------- |
| 🇺🇸 English | en-US | Primary development language and default fallback option | 100% |
| 🇧🇷 Portuguese | pt-BR | Standard Brazilian Portuguese support | 100% |
| 🇫🇷 French | fr-FR | Standard French language support | 100% |

View File

@@ -7,6 +7,7 @@ For Palmr to function with all its best features, we need to configure our email
## ❓ Why Configure SMTP?
The main functionalities that depend on SMTP configuration are:
- 🔑 **Password Reset** Users who forget their password and cannot access the **Settings** panel need this feature.
- 📧 **Email Notifications** Recipients will receive emails when new shares are sent to them.
@@ -53,6 +54,7 @@ Once SMTP is enabled, you can configure the other necessary fields:
### 🔐 Generating a Gmail App Password
To generate an App Password for Gmail:
1. Go to [Google My Account](https://myaccount.google.com/).
2. Select **Security**.
3. Scroll down to **App Passwords**.

View File

@@ -15,6 +15,7 @@ Before you can contribute, you need to be logged into your GitHub account. If yo
---
### 🔍 Access the Repository
Once you're logged in, go to the Palmr repository by clicking on this link: **[https://github.com/kyantech/Palmr](https://github.com/kyantech/Palmr)**. The repository contains all the source code, documentation, and resources for the Palmr project. Take a moment to explore the repository structure, including the README file, which provides an overview of the project.
Alternatively, you can search for "Palmr" in the GitHub search bar and click on the repository owned by **kyantech**. When searching, make sure you're looking at the official repository by checking the owner and repository name. The repository should have a description that matches the Palmr project and show recent activity from the maintainers. You can also check the number of stars, forks, and watchers to verify you're accessing the correct repository.
@@ -32,6 +33,7 @@ To contribute to the project, you'll need to create your own copy of the reposit
5. You'll be automatically redirected to your forked repository once it's ready.
The fork will maintain a connection to the original repository, allowing you to:
- Keep your fork synchronized with the original repository
- Submit pull requests from your fork to the original repository
- Work independently on your own copy without affecting the original
@@ -41,6 +43,7 @@ The fork will maintain a connection to the original repository, allowing you to:
### 📥 Clone the Fork
Next, youll need to clone your forked repository to your local machine. Heres how:
1. On your forked repository page, click the **Code** button.
2. Copy the repository URL (HTTPS or SSH).
3. Open your terminal or command prompt and run the following command to clone the repository:
@@ -60,6 +63,7 @@ Next, youll need to clone your forked repository to your local machine. Here
### 🔄 Set up Base Branch
Before making changes, ensure your local repository is set up to track the `next` branch from the original Palmr repository. Heres how:
1. Add the original Palmr repository as a remote:
```bash
@@ -81,7 +85,9 @@ Before making changes, ensure your local repository is set up to track the `next
---
### ✏️ Make Local Changes
Now you're ready to make your contributions! This could include:
- Fixing a bug
- Adding a new feature
- Improving documentation
@@ -113,12 +119,14 @@ Once youve made your changes, commit them to your branch using **Conventional
`<type>(<scope>): <description>`
**Examples:**
- `feat: add user authentication`
- `fix(api): resolve null pointer exception`
- `docs: update README file`
- `chore: update dependencies`
**Steps to Commit:**
1. Stage your changes:
```bash
@@ -138,6 +146,7 @@ Once youve made your changes, commit them to your branch using **Conventional
After committing your changes, you'll need to push them to your forked repository on GitHub. This step synchronizes your local changes with your remote repository. Here's how to do it:
1. First, ensure your branch is up-to-date with any remote changes:
```bash
git pull origin your-branch-name
```
@@ -148,11 +157,13 @@ After committing your changes, you'll need to push them to your forked repositor
```
If this is the first time pushing this branch, you might need to set the upstream branch:
```bash
git push -u origin your-branch-name
```
```bash
git push -u origin your-branch-name
```
If you encounter any errors while pushing:
- Make sure you have the correct permissions on your fork
- Verify your remote URL is correct using `git remote -v`
- Check if you need to authenticate with GitHub
@@ -162,6 +173,7 @@ If you encounter any errors while pushing:
### 🔀 Create Pull Request
Now that your changes are on GitHub, you can open a **Pull Request (PR)** to propose your changes to the `next` branch of the Palmr repository. Heres how:
1. Go to your forked repository on GitHub.
2. Click the **Pull Request** button.
3. On the PR creation page:
@@ -191,6 +203,7 @@ Remember that code review is a collaborative process aimed at ensuring code qual
## 💡 Contribution Tips
To ensure your contribution is accepted, follow these tips:
- **Use Conventional Commits**: Write clear and consistent commit messages using the Conventional Commits format.
- **Keep Your PRs Small**: Focus on one issue or feature per PR to make it easier to review.
- **Be Patient**: Maintainers are often volunteers and may take some time to review your PR.
@@ -206,6 +219,7 @@ To ensure your contribution is accepted, follow these tips:
## ⭐ Why Contribute?
Contributing to open-source projects like Palmr has many benefits:
1. **Improves the Project**: Your contributions help make the project better for everyone.
2. **Builds Your Skills**: Youll gain experience working with Git, GitHub, and collaborative coding.
3. **Supports the Community**: Open-source thrives on community contributions. Your work helps sustain the project.

View File

@@ -6,7 +6,7 @@ title: 🔗 Managing shares
Creating a share in Palmr is designed to be a straightforward and user-friendly experience that anyone can master quickly. While the platform offers several methods for share creation, we recommend beginning with the most accessible approach: utilizing the **Home Page**, particularly through the well-organized **Recent Shares** section.
___
---
### Home Page
@@ -19,7 +19,6 @@ For first-time users, the interface features a prominently positioned **"Create
![](/assets/v1/main/shares/create-first-share.png)
> Note: One of Palmr's unique features is its flexibility - you don't need to upload files to create a share! This might seem counterintuitive at first, but it's a deliberately designed feature that many users find invaluable for their specific workflows and use cases. This approach allows you to set up the sharing framework first and add content later.
>
This design philosophy reflects Palmr's user-centric approach: you can establish your share's parameters and settings first, then populate it with files at your convenience. Furthermore, all aspects of your share remain fully editable at any time, providing maximum flexibility.
@@ -78,7 +77,7 @@ Each share has an **Actions** column with the following options:
![](/assets/v1/main/shares/actions-column.png)
___
---
## ✏️ Edit Share
@@ -88,24 +87,23 @@ The **Edit** button provides access to a comprehensive interface where you can m
## 📁 Manage Files
___
---
Through the **Manage Files** button, you gain complete control over the content of your share, with the ability to both add new files and remove existing ones.
![](/assets/v1/main/shares/manage-files-modal.png)
___
---
## 👥 Manage Recipients
The **Manage Recipients** button opens an interface where you can maintain your recipient list, adding or removing access as needed.
> Note: For email notifications to function properly, please ensure that your system's SMTP settings are correctly configured and active.
>
![](/assets/v1/main/shares/manage-recipients-modal.png)
___
---
## 👀 View Share Details
@@ -113,7 +111,7 @@ The **View Details** option provides a comprehensive overview of all aspects and
![](/assets/v1/main/shares/share-details-modal.png)
___
---
## 🔗 Generate Share Link
@@ -133,7 +131,7 @@ When recipients access your generated link, they'll be able to both **view and d
![](/assets/v1/main/shares/share-screen.png)
___
---
## Delete Share

View File

@@ -34,6 +34,7 @@ Once you're logged in, go to the Palmr. repository by clicking on this link: [ht
Alternatively, you can search for "Palmr" in the GitHub search bar and click on the repository owned by **Kyantech**.
You can also:
- Star the repository to show your support
- Watch it for updates
- Fork it if you want to contribute
@@ -75,25 +76,26 @@ Once done, you'll officially be a **Palmr sponsor**! 🙌
### ⭐ Why Sponsoring Matters
- 🧱 Supports Sustainability
Your sponsorship helps keep the project alive and maintained long-term.
Your sponsorship helps keep the project alive and maintained long-term.
- 🚀 Encourages Innovation
Financial support gives developers the freedom to try new ideas and push boundaries.
Financial support gives developers the freedom to try new ideas and push boundaries.
- 🫶 Shows Deep Appreciation
Sponsoring is a meaningful, tangible way to thank developers for their work.
Sponsoring is a meaningful, tangible way to thank developers for their work.
- 🏆 Earns You Recognition
Many projects publicly thank their sponsors — you might appear in the README or on the site!
Many projects publicly thank their sponsors — you might appear in the README or on the site!
- 🌱 Helps Open Source Thrive
Open-source projects rely on community support. Sponsoring helps the ecosystem grow.
Open-source projects rely on community support. Sponsoring helps the ecosystem grow.
---
## 🎁 What Happens After Sponsoring
Once you become a sponsor:
1. You'll receive a confirmation email from GitHub
2. Your name will appear in our sponsors list
3. You'll get access to sponsor-only updates and content
@@ -107,4 +109,3 @@ Once you become a sponsor:
That's it! You've successfully sponsored the **Palmr.** project on GitHub.
Your support will help ensure this open-source project continues to evolve and thrive.
**We appreciate you and welcome you to our community!** 🎉

View File

@@ -66,6 +66,7 @@ After clicking the "Star" button, several things will happen:
4. The repository will be added to your starred repositories list
You can access your starred repositories anytime by:
- Clicking your profile picture
- Selecting "Your stars" from the dropdown menu
- Or visiting: https://github.com/[your-username]?tab=stars
@@ -81,22 +82,22 @@ To remove your star, simply click the "Unstar" button at any time.
Starring a repository on GitHub is more than just a bookmarking tool—its a way to support the project and its developers. Heres why starring is so important:
- 🙌 Shows Appreciation
Starring a repository is a simple way to show your appreciation for the hard work and effort that goes into maintaining and developing a project.
Starring a repository is a simple way to show your appreciation for the hard work and effort that goes into maintaining and developing a project.
- 📈 Increases Visibility
The more stars a repository has, the more visible it becomes on GitHub.
The more stars a repository has, the more visible it becomes on GitHub.
- 💪 Encourages Developers
Seeing stars motivates developers to continue improving the project.
Seeing stars motivates developers to continue improving the project.
- 🔍 Helps with Discovery
GitHub prioritizes repositories with more stars in trending and recommendations.
GitHub prioritizes repositories with more stars in trending and recommendations.
- 📚 Tracks Your Interests
Starred repositories are saved to your list for easy access later.
Starred repositories are saved to your list for easy access later.
- 🌍 Supports Open Source
Your stars help sustain the open-source community and the Palmr project.
Your stars help sustain the open-source community and the Palmr project.
---
@@ -119,6 +120,7 @@ Your star is more than just a number - it's a vote of confidence in our vision a
That's it! You've successfully starred the **Palmr** project on GitHub. Thank you for supporting Palmr and becoming part of our growing community! Your support helps us continue improving and expanding the project for everyone.
Feel free to explore our other ways to contribute, like:
- Sharing Palmr with others
- Reporting issues
- Contributing code

View File

@@ -2,31 +2,30 @@
title: </> Github Architecture
---
import { File, Folder, Files } from "fumadocs-ui/components/files";
import { File, Files, Folder } from "fumadocs-ui/components/files";
## Project Structure
<Files>
<Folder name="apps" defaultOpen>
<Folder name="docs" >
<Folder name="docs">
<File name="all documentation files" />
</Folder>
<Folder name="server" >
<Folder name="server">
<File name="all backend files" />
</Folder>
<Folder name="web" >
<Folder name="web">
<File name="all frontend files" />
</Folder>
</Folder>
<File name="other project files" />
</Files>
## Core Components
### 🖥️ Frontend Application (apps/web)
**Technology Stack:**
**Technology Stack:**
- Next.js 15 (App Router)
- React 18
@@ -52,7 +51,7 @@ The frontend is organized with:
### ⚙️ Backend Service (apps/server)
**Technology Stack:**
**Technology Stack:**
- Fastify
- PostgreSQL
@@ -76,7 +75,7 @@ Key features include:
### 📚 Documentation (apps/docs)
**Technology Stack:**
**Technology Stack:**
- Fumadocs
- MDX (Markdown + JSX)

View File

@@ -2,13 +2,12 @@
title: 🐳 Installation (Docker Compose)
---
Installation via Docker Compose is the simplest way to run the project across different environments. For it to run correctly, we need two main tools installed in our environment:
- Docker ([https://docs.docker.com](https://docs.docker.com/))
- Docker Compose ([https://docs.docker.com/compose](https://docs.docker.com/compose/))
> *It's worth emphasizing that Palmr. was fully developed in a MacOS environment and extensively tested on Linux servers. Therefore, we can guarantee the best system performance in these environments. Windows and other environments have not been tested yet, and potential bugs may occur during execution. However, remember that we are still in a beta version of Palmr., and errors or bugs can occur in any operating system. If you identify any issues, we appreciate your help in notifying us through our GitHub [issues page](https://github.com/kyantech/Palmr/issues).*
> _It's worth emphasizing that Palmr. was fully developed in a MacOS environment and extensively tested on Linux servers. Therefore, we can guarantee the best system performance in these environments. Windows and other environments have not been tested yet, and potential bugs may occur during execution. However, remember that we are still in a beta version of Palmr., and errors or bugs can occur in any operating system. If you identify any issues, we appreciate your help in notifying us through our GitHub [issues page](https://github.com/kyantech/Palmr/issues)._
---
@@ -25,6 +24,7 @@ Next, let's look at the content of our `docker-compose.yaml`.
---
## 🐳 Docker Compose Content
Below is the complete content of our `docker-compose.yaml` that can be copied directly from here or from our official repository ([Docker Compose](https://github.com/kyantech/Palmr/blob/main/docker-compose.yaml)).
```yaml
@@ -61,7 +61,17 @@ services:
- "${APP_EXTERNAL_PORT:-5487}:5487" # Web port
restart: unless-stopped
healthcheck:
test: ["CMD", "wget", "--no-verbose", "http://palmr:${API_INTERNAL_PORT:-3333}/health", "&&", "wget", "--no-verbose", "http://palmr:${APP_INTERNAL_PORT:-5487}"]
test:
[
"CMD",
"wget",
"--no-verbose",
"http://palmr:${API_INTERNAL_PORT:-3333}/health",
"&&",
"wget",
"--no-verbose",
"http://palmr:${APP_INTERNAL_PORT:-5487}",
]
interval: 30s
timeout: 10s
retries: 3
@@ -127,7 +137,6 @@ services:
volumes:
minio_data:
postgres_data:
```
Notice that the `docker-compose.yaml` has several comments that help you configure your own compose to meet your environment's needs. Let's give an overview of some changes we can make.
@@ -139,7 +148,7 @@ Notice that the `docker-compose.yaml` has several comments that help you configu
Palmr. consists of four main services, each with specific responsibilities. Below, we present a detailed view of each component:
| **Service** | **Image** | **Exposed Ports** | **Main Features** |
| --- | --- | --- | --- |
| ------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------- |
| palmr | [kyantech/palmr:latest](https://hub.docker.com/repository/docker/kyantech/palmr/general) | **3333** (API)<br/>**5487** (Web) | • Combined backend API and frontend service<br/>• Depends on services: postgres and minio<br/>• Has healthcheck to ensure availability |
| minio (Storage) | [minio/minio:RELEASE.2025-03-12T18-04-18Z](https://hub.docker.com/layers/minio/minio/RELEASE.2025-03-12T18-04-18Z/images/sha256-85f3e4cd1ca92a2711553ab79f222bcd8b75aa2c77a1a0b0ccf80d38e8ab2fe5) | **6421**(API)<br/>**6422**(Console) | • File storage service<br/>• Persistent volume for data |
| minio-init (Config) | [minio/mc:RELEASE.2025-03-12T17-29-24Z](https://hub.docker.com/layers/minio/mc/RELEASE.2025-03-12T17-29-24Z/images/sha256-68d8c80f43908b02daa285e55547131870a1d36b3ffe272c26d7d8f4d52d1e5c) | N/A | • Initially configures the "files" bucket<br/>• Runs only once during initialization |
@@ -152,7 +161,7 @@ Palmr. consists of four main services, each with specific responsibilities. Belo
The table below shows all environment variables that can be set
| **Variable** | **Default Value** | **Description** |
| --- | --- | --- |
| --------------------------- | --------------------- | ------------------------------------------------- |
| API_INTERNAL_PORT | 3333 | Internal API port in container |
| API_EXTERNAL_PORT | 3333 | Exposed port on host for API |
| POSTGRES_PASSWORD | postgresRootPassword | PostgreSQL database password |
@@ -169,9 +178,7 @@ The table below shows all environment variables that can be set
| POSTGRESQL_DATABASE | palmr_db | Database name |
| MAX_FILESIZE | 1073741824 | Max Uploadsize per file. Unit in Bytes |
> *All these variables can be configured through a .env file in the project root or defined directly in the environment where docker-compose will be executed. The best way to do this is up to you. But be careful to replace correctly if doing directly in the compose instead of providing an environment var.*
>
> _All these variables can be configured through a .env file in the project root or defined directly in the environment where docker-compose will be executed. The best way to do this is up to you. But be careful to replace correctly if doing directly in the compose instead of providing an environment var._
#### 🗂️ Persistent Volumes
@@ -196,8 +203,7 @@ This will execute all necessary services and give you access to the following UR
- **MinIO Console:** [http://localhost:6422](http://localhost:6422)
- **Postgres Database:** [http://localhost:5432](http://localhost:5432/) (Connection only)
> *If you have changed any port, simply access the URL with the port you configured.*
>
> _If you have changed any port, simply access the URL with the port you configured._
---
@@ -217,6 +223,7 @@ To generate a .env file with just the `server_ip` configuration, you can run thi
```bash
curl -fsSL https://gist.githubusercontent.com/danielalves96/5a68913d70e5e31b68b7331dc17dfa9c/raw | bash
```
> execute this command in your server terminal, at same path of docker-compose.yaml.
Basically, by paying attention to these points, you can quickly execute the project with the same command we used for localhost:
@@ -229,8 +236,7 @@ docker compose pull && docker compose up -d
At this stage, if you encounter any errors, it's worth reviewing your `docker-compose.yaml` and trying again, paying close attention to the points mentioned above.
> *First test without using reverse proxies like Caddy, Traefik, etc... if you plan to use them. Access the services via `server_ip:port` after confirming they work, then make the necessary routing configurations as desired.*
>
> _First test without using reverse proxies like Caddy, Traefik, etc... if you plan to use them. Access the services via `server_ip:port` after confirming they work, then make the necessary routing configurations as desired._
If you haven't changed the execution ports, you'll have access on your server at:
@@ -240,8 +246,7 @@ If you haven't changed the execution ports, you'll have access on your server at
- **MinIO Console:** `[server_ip]:6422`
- **Postgres Database:** `[server_ip]:5432` (Connection only)
> *If you've changed any port, simply access the URL with the port you configured.*
>
> _If you've changed any port, simply access the URL with the port you configured._
It's worth noting that this is just a quick start and we're not going into details about any of the developed services, but it's recommended for execution in any environment. However, if your focus is on using Palmr. with high availability in mind, it's recommended to use a container orchestrator prepared for this, such as Kubernetes or similar, but we don't cover this type of configuration in our documentation.

View File

@@ -31,7 +31,6 @@ Before proceeding with the installation, it's essential to ensure that your deve
⚠️ <strong>A critical note regarding package management:</strong> This repository has been specifically developed and thoroughly tested using the pnpm package manager. While technically possible to use alternative package managers such as `npm`, `yarn`, or `bun`, we strongly advise against this approach.
---
## Running the Application

View File

@@ -1,7 +1,5 @@
{
"title": "v2.0.0-beta",
"description": "(Deprecated)",
"root": true,
"icon": "Trash2",
"pages": [
"---Introduction---",
@@ -25,5 +23,7 @@
"gh-star",
"gh-sponsor",
"..."
]
],
"root": true,
"title": "v2.0.0-beta"
}

View File

@@ -53,6 +53,7 @@ To access the issues section:
4. You'll see a list of all existing issues, both open and closed
The issues tab shows important information like:
- Number of open issues
- Issue labels and categories
- Issue status (open/closed)
@@ -74,6 +75,7 @@ To start creating a new issue:
5. Make sure you have all necessary information ready before starting
Pro Tips:
- Before creating a new issue, search existing issues to avoid duplicates
- Review any contribution guidelines or issue templates
- Consider adding relevant labels when creating your issue
@@ -107,6 +109,7 @@ Once you've filled out the form, click the **Create** button at the bottom of th
### 💡 Tips for Issues
To ensure your issue is addressed quickly and effectively, follow these tips:
- **Be Clear and Specific**: Provide as much detail as possible.
- **Use a Descriptive Title**: A good title helps maintainers understand the issue at a glance.
- **Include Steps to Reproduce**: If its a bug, explain how to reproduce it.
@@ -117,6 +120,7 @@ To ensure your issue is addressed quickly and effectively, follow these tips:
### ⭐ Why Issues Matter
Opening issues is a key part of contributing to open-source projects. Heres why it matters:
1. **Improves the Project**: Your feedback helps identify bugs and suggest new features.
2. **Helps Maintainers**: Clear and detailed issues make it easier for maintainers to address problems.
3. **Encourages Collaboration**: Issues can spark discussions and attract contributors to help solve problems.

View File

@@ -20,7 +20,6 @@ To begin the upload process, locate and click the "Upload File" button. This act
![Upload File Button](/assets/v1/main/upload/upload-file-button.png)
**Example with an image:**
![Preview Example](/assets/v1/main/upload/preview-example.png)

View File

@@ -9,10 +9,7 @@ import { ZoomableImage } from "@/components/ui/zoomable-image";
Understanding the architecture of Palmr. is crucial for both deploying and scaling the application. The platform is designed with simplicity and flexibility in mind, offering a streamlined setup that can grow with your needs.
<ZoomableImage
src="/assets/v3/architecture/architecture.png"
alt="Palmr. Architecture"
/>
<ZoomableImage src="/assets/v3/architecture/architecture.png" alt="Palmr. Architecture" />
## Technologies used

View File

@@ -3,7 +3,7 @@ title: GitHub Architecture
icon: Github
---
import { File, Folder, Files } from "fumadocs-ui/components/files";
import { File, Files, Folder } from "fumadocs-ui/components/files";
This guide provides a comprehensive overview of Palmr.'s GitHub repository structure, explaining how the different components are organized in the codebase. Understanding this architecture will help you navigate the repository, contribute effectively, and understand how the project is structured.

View File

@@ -3,7 +3,7 @@ title: Welcome to Palmr.
icon: TreePalm
---
import { Ban, Star, Shield, Palette, Users, Zap } from "lucide-react";
import { Ban, Palette, Shield, Star, Users, Zap } from "lucide-react";
![Palmr Banner](/assets/v2.1/general/banner.png)

View File

@@ -23,8 +23,7 @@ We've broken down each step below feel free to jump to the section you're workin
Let's make sure your environment is ready to roll. Check that you've got these tools installed and set up on your system:
- <span style={{ color: "#16a34a" }}>Node.js</span> *(Powers our JavaScript/TypeScript
apps)*
- <span style={{ color: "#16a34a" }}>Node.js</span> *(Powers our JavaScript/TypeScript apps)*
- <span style={{ color: "#16a34a" }}>pnpm</span> *(Our go-to package manager)*
- <span style={{ color: "#16a34a" }}>Git</span> *(For cloning and managing the repo)*

View File

@@ -1,7 +1,5 @@
{
"title": "v3.1-beta",
"description": "Latest version",
"root": true,
"icon": "Sparkles",
"pages": [
"---Introduction---",
@@ -28,5 +26,7 @@
"---Sponsor this project---",
"gh-star",
"gh-sponsor"
]
],
"root": true,
"title": "v3.1-beta"
}

View File

@@ -1,17 +1,6 @@
{
"title": "OIDC Authentication",
"defaultOpen": false,
"icon": "Key",
"pages": [
"index",
"google",
"discord",
"github",
"zitadel",
"auth0",
"authentik",
"frontegg",
"kinde-auth",
"other"
],
"defaultOpen": false
"pages": ["index", "google", "discord", "github", "zitadel", "auth0", "authentik", "frontegg", "kinde-auth", "other"],
"title": "OIDC Authentication"
}

View File

@@ -131,7 +131,6 @@ If you encounter issues while running the script, refer to the following solutio
- **Error: "Database connection failed"**
If the script cannot connect to the database, check the following:
- Ensure the database service is running within the container.
- Confirm that the `prisma/palmr.db` file exists and has the correct permissions.
- Verify that the container has access to the database volume.

View File

@@ -67,7 +67,6 @@ If you experience authentication issues behind a reverse proxy:
### Diagnostic Steps
1. **Check Browser Developer Tools**:
- Look for cookies in Application/Storage tab
- Verify cookie has `Secure` flag when using HTTPS
- Check if `SameSite` attribute is appropriate

View File

@@ -17,28 +17,19 @@ Here you can find a collection of screenshots showcasing various features and in
The main landing page where users can access the platform and learn about Palmr.'s features.
<ZoomableImage
src="/assets/v3/screenshots/home.png"
alt="Home Page - Main landing page of Palmr"
/>
<ZoomableImage src="/assets/v3/screenshots/home.png" alt="Home Page - Main landing page of Palmr" />
#### Login page
Secure authentication interface where users enter their credentials to access their Palmr account.
<ZoomableImage
src="/assets/v3/screenshots/login.png"
alt="Login Page - User authentication interface"
/>
<ZoomableImage src="/assets/v3/screenshots/login.png" alt="Login Page - User authentication interface" />
#### Forgot password
Password recovery interface that allows users to reset their passwords when they can't access their accounts.
<ZoomableImage
src="/assets/v3/screenshots/forgot-password.png"
alt="Forgot Password - Password recovery interface"
/>
<ZoomableImage src="/assets/v3/screenshots/forgot-password.png" alt="Forgot Password - Password recovery interface" />
### Main Application Interface

View File

@@ -3,8 +3,8 @@ title: Translation Management
icon: Languages
---
import { Tab, Tabs } from "fumadocs-ui/components/tabs";
import { Callout } from "fumadocs-ui/components/callout";
import { Tab, Tabs } from "fumadocs-ui/components/tabs";
Palmr includes a comprehensive translation key management system that automates synchronization and validation of the application's internationalization files.
@@ -80,17 +80,13 @@ When you add new text to the application:
4. **Test in UI**: Verify translations work correctly in the application interface
<Callout type="important">
**Manual translation required**: All strings marked with `[TO_TRANSLATE]` must
be manually translated by native speakers or professional translators for
accuracy.
**Manual translation required**: All strings marked with `[TO_TRANSLATE]` must be manually translated by native
speakers or professional translators for accuracy.
</Callout>
### 2. Checking Translation Status
<Callout>
Always run `pnpm run translations:check` before releases to ensure
completeness.
</Callout>
<Callout>Always run `pnpm run translations:check` before releases to ensure completeness.</Callout>
```bash
# Generate detailed translation report
@@ -301,9 +297,8 @@ Translation files use nested JSON structure:
## Manual Translation
<Callout type="warning">
**Professional translation recommended**: For production applications,
consider using professional translation services or native speakers to ensure
high-quality, culturally appropriate translations.
**Professional translation recommended**: For production applications, consider using professional translation
services or native speakers to ensure high-quality, culturally appropriate translations.
</Callout>
The system marks strings that need translation with the `[TO_TRANSLATE]` prefix:
@@ -345,8 +340,8 @@ After manual translation:
## Development Guidelines
<Callout type="important">
**Primary Language**: Always use `en-US.json` as the parent language for
development. All new translation keys must be added to English first.
**Primary Language**: Always use `en-US.json` as the parent language for development. All new translation keys must be
added to English first.
</Callout>
### Translation Workflow for Development

View File

@@ -1,6 +1,3 @@
{
"pages": [
"3.1-beta",
"2.0.0-beta"
]
"pages": ["3.1-beta", "2.0.0-beta"]
}

View File

@@ -0,0 +1,67 @@
/* eslint-disable import/no-anonymous-default-export */
import path from "node:path";
import { fileURLToPath } from "node:url";
import { FlatCompat } from "@eslint/eslintrc";
import js from "@eslint/js";
import typescriptEslintEslintPlugin from "@typescript-eslint/eslint-plugin";
import tsParser from "@typescript-eslint/parser";
import prettier from "eslint-plugin-prettier";
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
const compat = new FlatCompat({
baseDirectory: __dirname,
recommendedConfig: js.configs.recommended,
allConfig: js.configs.all,
});
export default [
...compat.extends("next", "next/core-web-vitals", "prettier"),
{
plugins: {
prettier,
},
rules: {
"prettier/prettier": "error",
camelcase: "off",
"import/prefer-default-export": "off",
"react/jsx-filename-extension": "off",
"react/jsx-props-no-spreading": "off",
"react/no-unused-prop-types": "off",
"react/require-default-props": "off",
"react/no-unescaped-entities": "off",
"@next/next/no-img-element": "off",
"import/extensions": [
"error",
"ignorePackages",
{
ts: "never",
tsx: "never",
js: "never",
jsx: "never",
},
],
},
},
{
files: ["**/*.+(ts|tsx)"],
plugins: {
"@typescript-eslint": typescriptEslintEslintPlugin,
},
languageOptions: {
parser: tsParser,
},
rules: {
"@typescript-eslint/explicit-function-return-type": "off",
"@typescript-eslint/explicit-module-boundary-types": "off",
"no-use-before-define": [0],
"@typescript-eslint/no-use-before-define": [1],
"@typescript-eslint/no-explicit-any": "off",
"@typescript-eslint/no-var-requires": "off",
},
},
// Ignore ESLint errors in @/ui directory
{
ignores: ["src/components/ui/**/*"],
},
];

View File

@@ -1,4 +1,4 @@
import { createMDX } from 'fumadocs-mdx/next';
import { createMDX } from "fumadocs-mdx/next";
const withMDX = createMDX();
@@ -15,15 +15,15 @@ const config = {
qualities: [100],
remotePatterns: [
{
protocol: 'https',
hostname: '**'
protocol: "https",
hostname: "**",
},
{
protocol: 'http',
hostname: '**'
}
]
}
protocol: "http",
hostname: "**",
},
],
},
};
export default withMDX(config);

View File

@@ -19,7 +19,13 @@
"build": "next build",
"dev": "next dev --turbo",
"start": "next start",
"postinstall": "fumadocs-mdx"
"postinstall": "fumadocs-mdx",
"lint": "eslint \"src/**/*.+(ts|tsx)\"",
"lint:fix": "eslint \"src/**/*.+(ts|tsx)\" --fix",
"format": "prettier . --write",
"format:check": "prettier . --check",
"type-check": "npx tsc --noEmit",
"validate": "pnpm format && pnpm lint:fix && pnpm type-check"
},
"dependencies": {
"class-variance-authority": "^0.7.1",
@@ -35,14 +41,23 @@
"tailwind-merge": "^3.2.0"
},
"devDependencies": {
"@eslint/eslintrc": "3.3.1",
"@eslint/js": "9.30.0",
"@ianvs/prettier-plugin-sort-imports": "4.4.2",
"@tailwindcss/postcss": "^4.1.11",
"@types/mdx": "^2.0.13",
"@types/node": "22.14.0",
"@types/react": "^19.1.8",
"@types/react-dom": "^19.1.6",
"eslint": "^8",
"@typescript-eslint/eslint-plugin": "8.35.1",
"@typescript-eslint/parser": "8.35.1",
"eslint": "9.30.0",
"eslint-config-next": "15.3.4",
"eslint-config-prettier": "9.1.0",
"eslint-plugin-prettier": "5.5.1",
"postcss": "^8.5.6",
"prettier": "3.6.2",
"prettier-plugin-sort-json": "4.1.1",
"tailwindcss": "^4.1.11",
"tw-animate-css": "^1.2.8",
"typescript": "^5.8.3"

5199
apps/docs/pnpm-lock.yaml generated

File diff suppressed because it is too large Load Diff

View File

@@ -1,5 +1,5 @@
export default {
plugins: {
'@tailwindcss/postcss': {},
"@tailwindcss/postcss": {},
},
};

View File

@@ -1,4 +1,4 @@
import { defineDocs, defineConfig } from "fumadocs-mdx/config";
import { defineConfig, defineDocs } from "fumadocs-mdx/config";
// Options: https://fumadocs.vercel.app/docs/mdx/collections#define-docs
export const docs = defineDocs({

View File

@@ -1,11 +1,12 @@
import type { ReactNode } from "react";
import { HomeLayout } from "fumadocs-ui/layouts/home";
import { baseOptions } from "@/app/layout.config";
import { Particles } from "@/components/magicui/particles";
export default function Layout({ children }: { children: ReactNode }) {
return (
<HomeLayout {...baseOptions} >
<HomeLayout {...baseOptions}>
<Particles className="absolute w-full" />
{children}
</HomeLayout>

View File

@@ -1,31 +1,29 @@
import {
type LucideIcon,
MousePointer,
UploadIcon,
GithubIcon,
BookOpenText,
CloudIcon,
LockIcon,
DatabaseIcon,
} from "lucide-react";
import type { ReactNode } from "react";
import Link from "next/link";
import {
BatteryChargingIcon,
BookOpenText,
CloudIcon,
DatabaseIcon,
GithubIcon,
KeyboardIcon,
LayoutIcon,
LockIcon,
MousePointer,
RocketIcon,
SearchIcon,
TimerIcon,
UploadIcon,
type LucideIcon,
} from "lucide-react";
import Link from "next/link";
import type { ReactNode } from "react";
import { ThreeDMarquee } from "@/components/ui/3d-marquee";
import { AnimatedGridPattern } from "@/components/magicui/animated-grid-pattern";
import { TypingAnimation } from "@/components/magicui/typing-animation";
import { TextHoverEffect } from "@/components/ui/text-hover-effect";
import { PulsatingButton } from "@/components/magicui/pulsating-button";
import { RippleButton } from "@/components/magicui/ripple-button";
import { TypingAnimation } from "@/components/magicui/typing-animation";
import { WordRotate } from "@/components/magicui/word-rotate";
import { ThreeDMarquee } from "@/components/ui/3d-marquee";
import { TextHoverEffect } from "@/components/ui/text-hover-effect";
const images = [
"https://res.cloudinary.com/technical-intelligence/image/upload/v1745546004/Palmr./dash_wt_kqtzxi.png",
@@ -82,17 +80,11 @@ function Hero() {
return (
<section className="relative z-[2] flex flex-col border-x border-t px-6 pt-12 pb-10 md:px-12 md:pt-16 max-md:text-center">
<h1 className="mb-8 text-6xl font-bold">
Palmr.{" "}
<span className="text-[13px] font-light text-muted-foreground/50 font-mono">
v3.1-beta
</span>
</h1>
<h1 className="hidden text-4xl font-medium max-w-[600px] md:block mb-4">
Modern & efficient file sharing
Palmr. <span className="text-[13px] font-light text-muted-foreground/50 font-mono">v3.1-beta</span>
</h1>
<h1 className="hidden text-4xl font-medium max-w-[600px] md:block mb-4">Modern & efficient file sharing</h1>
<p className="mb-8 text-fd-muted-foreground md:max-w-[80%] md:text-xl">
Palmr is a fast and secure platform for sharing files, built with
performance and privacy in mind.
Palmr is a fast and secure platform for sharing files, built with performance and privacy in mind.
</p>
<div className="hidden h-[10rem] lg:flex items-center justify-center absolute right-0 top-10">
<TextHoverEffect text="Palmr." />
@@ -136,13 +128,7 @@ function Feedback() {
A modern way to share files
<WordRotate
duration={4000}
words={[
"efficiently",
"securely",
"privately",
"reliably",
"seamlessly",
]}
words={["efficiently", "securely", "privately", "reliably", "seamlessly"]}
className="min-w-[100px] inline-block"
/>
</p>
@@ -163,8 +149,7 @@ function Features() {
<h3 className="text-2xl font-semibold">Upload & Share</h3>
</div>
<p className="text-muted-foreground">
Send your files quickly and safely. Share easily with anyone through
secure links.
Send your files quickly and safely. Share easily with anyone through secure links.
</p>
</div>
<div className="flex flex-col gap-4 border-r p-8 md:p-12">
@@ -174,9 +159,7 @@ function Features() {
</div>
<h3 className="text-2xl font-semibold">Secure & Private</h3>
</div>
<p className="text-muted-foreground">
Files are encrypted and protected. You control your data completely.
</p>
<p className="text-muted-foreground">Files are encrypted and protected. You control your data completely.</p>
</div>
</section>
@@ -192,9 +175,7 @@ function Features() {
<p className="mb-4 w-fit bg-fd-primary px-3 py-1 text-sm font-bold font-mono text-fd-primary-foreground mx-auto">
Open Source & Self-Hosted
</p>
<h2 className="text-center text-2xl font-semibold sm:text-3xl mb-4">
Complete File Sharing Solution
</h2>
<h2 className="text-center text-2xl font-semibold sm:text-3xl mb-4">Complete File Sharing Solution</h2>
<TypingAnimation className="text-center text-xl text-muted-foreground">
Built with Next.js, Fastify, and SQLite
</TypingAnimation>
@@ -205,9 +186,7 @@ function Features() {
{/* Technical Features Grid */}
<section className="grid grid-cols-1 border-r md:grid-cols-2 lg:grid-cols-3">
<div className="col-span-full flex items-start justify-center border-l border-t p-8 pb-2 text-center">
<h2 className="bg-fd-primary px-1 text-2xl font-semibold text-fd-primary-foreground">
Key Features
</h2>
<h2 className="bg-fd-primary px-1 text-2xl font-semibold text-fd-primary-foreground">Key Features</h2>
<MousePointer className="-ml-1 mt-8" />
</div>
@@ -239,15 +218,7 @@ function Features() {
);
}
function Highlight({
icon: Icon,
heading,
children,
}: {
icon: LucideIcon;
heading: ReactNode;
children: ReactNode;
}) {
function Highlight({ icon: Icon, heading, children }: { icon: LucideIcon; heading: ReactNode; children: ReactNode }) {
return (
<div className="border-l border-t px-6 py-12">
<div className="mb-4 flex items-center gap-2 text-fd-muted-foreground">
@@ -264,12 +235,10 @@ function GetStarted() {
<section className="flex w-full flex-1">
<div className="w-full flex flex-col gap-8 overflow-hidden border px-8 py-14">
<div className="text-center mb-6">
<h2 className="text-4xl font-extrabold font-mono uppercase mb-3">
Get Started Today
</h2>
<h2 className="text-4xl font-extrabold font-mono uppercase mb-3">Get Started Today</h2>
<p className="text-lg text-muted-foreground max-w-2xl mx-auto">
Deploy your own secure file sharing platform in minutes. Take
control of your data with our self-hosted solution.
Deploy your own secure file sharing platform in minutes. Take control of your data with our self-hosted
solution.
</p>
</div>
@@ -282,8 +251,7 @@ function GetStarted() {
</div>
<h3 className="text-xl font-semibold">Quick Setup</h3>
<p className="text-muted-foreground">
Docker deployment or direct installation - get running in under 5
minutes
Docker deployment or direct installation - get running in under 5 minutes
</p>
</div>
@@ -295,8 +263,7 @@ function GetStarted() {
</div>
<h3 className="text-xl font-semibold">Full Control</h3>
<p className="text-muted-foreground">
Self-hosted means you own your data and control every aspect of
the platform
Self-hosted means you own your data and control every aspect of the platform
</p>
</div>
@@ -307,9 +274,7 @@ function GetStarted() {
</div>
</div>
<h3 className="text-xl font-semibold">Production Ready</h3>
<p className="text-muted-foreground">
Latest technologies optimized for performance and security
</p>
<p className="text-muted-foreground">Latest technologies optimized for performance and security</p>
</div>
</div>

View File

@@ -3,17 +3,10 @@ import { NextResponse } from "next/server";
export async function GET() {
try {
const key = execSync(
"openssl rand -base64 48 | tr -dc 'A-Za-z0-9' | head -c 64"
)
.toString()
.trim();
const key = execSync("openssl rand -base64 48 | tr -dc 'A-Za-z0-9' | head -c 64").toString().trim();
return NextResponse.json({ key });
} catch (error) {
console.error("Failed to generate key:", error);
return NextResponse.json(
{ error: "Failed to generate key" },
{ status: 500 }
);
return NextResponse.json({ error: "Failed to generate key" }, { status: 500 });
}
}

View File

@@ -1,6 +1,7 @@
import { source } from "@/lib/source";
import { createFromSource } from "fumadocs-core/search/server";
import { source } from "@/lib/source";
export const { GET } = createFromSource(source, (page) => {
return {
title: page.data.title,

View File

@@ -1,20 +1,14 @@
import { source } from "@/lib/source";
import {
DocsPage,
DocsBody,
DocsDescription,
DocsTitle,
} from "fumadocs-ui/page";
import { redirect } from "next/navigation";
import { createRelativeLink } from "fumadocs-ui/mdx";
import { DocsBody, DocsDescription, DocsPage, DocsTitle } from "fumadocs-ui/page";
import { VersionWarning } from "@/components/version-warning";
import { source } from "@/lib/source";
import { getMDXComponents } from "@/mdx-components";
import { Footer } from "../components/footer";
import { Sponsor } from "../components/sponsor";
import { VersionWarning } from "@/components/version-warning";
export default async function Page(props: {
params: Promise<{ slug?: string[] }>;
}) {
export default async function Page(props: { params: Promise<{ slug?: string[] }> }) {
const params = await props.params;
const page = source.getPage(params.slug);
if (!page) redirect("/docs/3.1-beta");
@@ -53,9 +47,7 @@ export async function generateStaticParams() {
return source.generateParams();
}
export async function generateMetadata(props: {
params: Promise<{ slug?: string[] }>;
}) {
export async function generateMetadata(props: { params: Promise<{ slug?: string[] }> }) {
const params = await props.params;
const page = source.getPage(params.slug);
if (!page) redirect("/docs/3.1-beta");

View File

@@ -1,4 +1,4 @@
import Link from 'fumadocs-core/link';
import Link from "fumadocs-core/link";
export function Footer() {
return (

View File

@@ -1,16 +1,12 @@
import { DocsLayout } from "fumadocs-ui/layouts/docs";
import type { ReactNode } from "react";
import { DocsLayout } from "fumadocs-ui/layouts/docs";
import { baseOptions } from "@/app/layout.config";
import { source } from "@/lib/source";
export default function Layout({ children }: { children: ReactNode }) {
return (
<DocsLayout
tree={source.pageTree}
{...baseOptions}
githubUrl="https://github.com/kyantech/Palmr"
links={[]}
>
<DocsLayout tree={source.pageTree} {...baseOptions} githubUrl="https://github.com/kyantech/Palmr" links={[]}>
{children}
</DocsLayout>
);

View File

@@ -57,23 +57,24 @@ h4 {
--color-sidebar-accent-foreground: var(--sidebar-accent-foreground);
--color-sidebar-border: var(--sidebar-border);
--color-sidebar-ring: var(--sidebar-ring);
--animate-ripple: ripple var(--duration,2s) ease calc(var(--i, 0)*.2s) infinite;
--animate-ripple: ripple var(--duration, 2s) ease calc(var(--i, 0) * 0.2s) infinite;
@keyframes ripple {
0%, 100% {
0%,
100% {
transform: translate(-50%, -50%) scale(1);
}
50% {
transform: translate(-50%, -50%) scale(0.9);
}
}
--animate-pulse: pulse var(--duration) ease-out infinite
;
--animate-pulse: pulse var(--duration) ease-out infinite;
@keyframes pulse {
0%, 100% {
boxShadow: 0 0 0 0 var(--pulse-color);
0%,
100% {
boxshadow: 0 0 0 0 var(--pulse-color);
}
50% {
boxShadow: 0 0 0 8px var(--pulse-color);
boxshadow: 0 0 0 8px var(--pulse-color);
}
}
--animate-rippling: rippling var(--duration) ease-out;
@@ -85,7 +86,8 @@ h4 {
transform: scale(2);
opacity: 0;
}
}}
}
}
:root {
--radius: 0.625rem;
@@ -202,7 +204,6 @@ h4 {
}
}
@theme inline {
--animate-rippling: rippling var(--duration) ease-out;

View File

@@ -1,7 +1,8 @@
import { LATEST_VERSION_PATH } from "@/config/constants";
import type { BaseLayoutProps } from "fumadocs-ui/layouts/shared";
import { Github, Palmtree } from "lucide-react";
import { LATEST_VERSION_PATH } from "@/config/constants";
export const baseOptions: BaseLayoutProps = {
nav: {
title: (

View File

@@ -1,9 +1,12 @@
import { Banner } from "fumadocs-ui/components/banner";
import "./global.css";
import { RootProvider } from "fumadocs-ui/provider";
import { Inter } from "next/font/google";
import type { ReactNode } from "react";
import { Inter } from "next/font/google";
import Link from "fumadocs-core/link";
import { RootProvider } from "fumadocs-ui/provider";
import { LATEST_VERSION, LATEST_VERSION_PATH } from "@/config/constants";
const inter = Inter({
@@ -12,8 +15,7 @@ const inter = Inter({
export const metadata = {
title: "Palmr. | Official Website",
description:
"Palmr. is a fast, simple and powerful document sharing platform.",
description: "Palmr. is a fast, simple and powerful document sharing platform.",
};
export default function Layout({ children }: { children: ReactNode }) {
@@ -21,9 +23,7 @@ export default function Layout({ children }: { children: ReactNode }) {
<html lang="en" className={inter.className} suppressHydrationWarning>
<body className="flex flex-col min-h-screen">
<Banner variant="rainbow" id="banner-21-beta">
<Link href={LATEST_VERSION_PATH}>
Palmr. {LATEST_VERSION} has released!
</Link>
<Link href={LATEST_VERSION_PATH}>Palmr. {LATEST_VERSION} has released!</Link>
</Banner>
<RootProvider
search={{

View File

@@ -2,6 +2,7 @@
import { useState } from "react";
import { Copy, X } from "lucide-react";
import { Button } from "@/components/ui/button";
import { Toast } from "@/components/ui/toast";
@@ -49,9 +50,7 @@ export function KeyGenerator() {
<code className="block w-full p-3 bg-gray-100 dark:bg-black/80 rounded-md font-mono text-sm min-h-[2.5rem] border border-gray-200 dark:border-gray-700">
{key ? (
<>
<span className="select-none text-gray-500 dark:text-gray-400">
ENCRYPTION_KEY=
</span>
<span className="select-none text-gray-500 dark:text-gray-400">ENCRYPTION_KEY=</span>
<span className="text-green-900 dark:text-green-600">{key}</span>
</>
) : (
@@ -73,17 +72,11 @@ export function KeyGenerator() {
{key && (
<p className="text-sm text-gray-500 dark:text-gray-400">
Copy the key and paste it into your <code>docker-compose.yml</code>{" "}
file.
Copy the key and paste it into your <code>docker-compose.yml</code> file.
</p>
)}
{showToast && (
<Toast
message="Key copied to clipboard!"
onClose={() => setShowToast(false)}
/>
)}
{showToast && <Toast message="Key copied to clipboard!" onClose={() => setShowToast(false)} />}
</div>
);
}

View File

@@ -1,15 +1,6 @@
import { Chrome, Egg, Github, Key, Lock, MessageSquare, Settings, Shield, Users } from "lucide-react";
import { Card, CardGrid } from "@/components/ui/card";
import {
Chrome,
MessageSquare,
Github,
Shield,
Lock,
Key,
Users,
Settings,
Egg,
} from "lucide-react";
const providers = [
{

View File

@@ -1,18 +1,11 @@
"use client";
import { ComponentPropsWithoutRef, useEffect, useId, useRef, useState } from "react";
import { motion } from "motion/react";
import {
ComponentPropsWithoutRef,
useEffect,
useId,
useRef,
useState,
} from "react";
import { cn } from "@/lib/utils";
export interface AnimatedGridPatternProps
extends ComponentPropsWithoutRef<"svg"> {
export interface AnimatedGridPatternProps extends ComponentPropsWithoutRef<"svg"> {
width?: number;
height?: number;
x?: number;
@@ -66,8 +59,8 @@ export function AnimatedGridPattern({
...sq,
pos: getPos(),
}
: sq,
),
: sq
)
);
};
@@ -106,24 +99,13 @@ export function AnimatedGridPattern({
aria-hidden="true"
className={cn(
"pointer-events-none absolute inset-0 h-full w-full fill-gray-400/30 stroke-gray-400/30",
className,
className
)}
{...props}
>
<defs>
<pattern
id={id}
width={width}
height={height}
patternUnits="userSpaceOnUse"
x={x}
y={y}
>
<path
d={`M.5 ${height}V.5H${width}`}
fill="none"
strokeDasharray={strokeDasharray}
/>
<pattern id={id} width={width} height={height} patternUnits="userSpaceOnUse" x={x} y={y}>
<path d={`M.5 ${height}V.5H${width}`} fill="none" strokeDasharray={strokeDasharray} />
</pattern>
</defs>
<rect width="100%" height="100%" fill={`url(#${id})`} />

View File

@@ -1,12 +1,8 @@
"use client";
import React, { ComponentPropsWithoutRef, useEffect, useRef, useState } from "react";
import { cn } from "@/lib/utils";
import React, {
ComponentPropsWithoutRef,
useEffect,
useRef,
useState,
} from "react";
interface MousePosition {
x: number;
@@ -220,12 +216,7 @@ export const Particles: React.FC<ParticlesProps> = ({
const clearContext = () => {
if (context.current) {
context.current.clearRect(
0,
0,
canvasSize.current.w,
canvasSize.current.h,
);
context.current.clearRect(0, 0, canvasSize.current.w, canvasSize.current.h);
}
};
@@ -238,15 +229,8 @@ export const Particles: React.FC<ParticlesProps> = ({
}
};
const remapValue = (
value: number,
start1: number,
end1: number,
start2: number,
end2: number,
): number => {
const remapped =
((value - start1) * (end2 - start2)) / (end1 - start1) + start2;
const remapValue = (value: number, start1: number, end1: number, start2: number, end2: number): number => {
const remapped = ((value - start1) * (end2 - start2)) / (end1 - start1) + start2;
return remapped > 0 ? remapped : 0;
};
@@ -261,9 +245,7 @@ export const Particles: React.FC<ParticlesProps> = ({
canvasSize.current.h - circle.y - circle.translateY - circle.size, // distance from bottom edge
];
const closestEdge = edge.reduce((a, b) => Math.min(a, b));
const remapClosestEdge = parseFloat(
remapValue(closestEdge, 0, 20, 0, 1).toFixed(2),
);
const remapClosestEdge = parseFloat(remapValue(closestEdge, 0, 20, 0, 1).toFixed(2));
if (remapClosestEdge > 1) {
circle.alpha += 0.02;
if (circle.alpha > circle.targetAlpha) {
@@ -274,12 +256,8 @@ export const Particles: React.FC<ParticlesProps> = ({
}
circle.x += circle.dx + vx;
circle.y += circle.dy + vy;
circle.translateX +=
(mouse.current.x / (staticity / circle.magnetism) - circle.translateX) /
ease;
circle.translateY +=
(mouse.current.y / (staticity / circle.magnetism) - circle.translateY) /
ease;
circle.translateX += (mouse.current.x / (staticity / circle.magnetism) - circle.translateX) / ease;
circle.translateY += (mouse.current.y / (staticity / circle.magnetism) - circle.translateY) / ease;
drawCircle(circle, true);
@@ -301,12 +279,7 @@ export const Particles: React.FC<ParticlesProps> = ({
};
return (
<div
className={cn("pointer-events-none", className)}
ref={canvasContainerRef}
aria-hidden="true"
{...props}
>
<div className={cn("pointer-events-none", className)} ref={canvasContainerRef} aria-hidden="true" {...props}>
<canvas ref={canvasRef} className="size-full" />
</div>
);

View File

@@ -1,32 +1,20 @@
import React from "react";
import { cn } from "@/lib/utils";
interface PulsatingButtonProps
extends React.ButtonHTMLAttributes<HTMLButtonElement> {
interface PulsatingButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {
pulseColor?: string;
duration?: string;
}
export const PulsatingButton = React.forwardRef<
HTMLButtonElement,
PulsatingButtonProps
>(
(
{
className,
children,
pulseColor = "#808080",
duration = "1.5s",
...props
},
ref,
) => {
export const PulsatingButton = React.forwardRef<HTMLButtonElement, PulsatingButtonProps>(
({ className, children, pulseColor = "#808080", duration = "1.5s", ...props }, ref) => {
return (
<button
ref={ref}
className={cn(
"relative flex cursor-pointer items-center justify-center rounded-lg bg-primary px-4 py-2 text-center text-primary-foreground",
className,
className
)}
style={
{
@@ -40,7 +28,7 @@ export const PulsatingButton = React.forwardRef<
<div className="absolute left-1/2 top-1/2 size-full -translate-x-1/2 -translate-y-1/2 animate-pulse rounded-lg bg-inherit" />
</button>
);
},
}
);
PulsatingButton.displayName = "PulsatingButton";

View File

@@ -1,32 +1,17 @@
"use client";
import { cn } from "@/lib/utils";
import React, { MouseEvent, useEffect, useState } from "react";
interface RippleButtonProps
extends React.ButtonHTMLAttributes<HTMLButtonElement> {
import { cn } from "@/lib/utils";
interface RippleButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {
rippleColor?: string;
duration?: string;
}
export const RippleButton = React.forwardRef<
HTMLButtonElement,
RippleButtonProps
>(
(
{
className,
children,
rippleColor = "#ffffff",
duration = "600ms",
onClick,
...props
},
ref,
) => {
const [buttonRipples, setButtonRipples] = useState<
Array<{ x: number; y: number; size: number; key: number }>
>([]);
export const RippleButton = React.forwardRef<HTMLButtonElement, RippleButtonProps>(
({ className, children, rippleColor = "#ffffff", duration = "600ms", onClick, ...props }, ref) => {
const [buttonRipples, setButtonRipples] = useState<Array<{ x: number; y: number; size: number; key: number }>>([]);
const handleClick = (event: MouseEvent<HTMLButtonElement>) => {
createRipple(event);
@@ -48,9 +33,7 @@ export const RippleButton = React.forwardRef<
if (buttonRipples.length > 0) {
const lastRipple = buttonRipples[buttonRipples.length - 1];
const timeout = setTimeout(() => {
setButtonRipples((prevRipples) =>
prevRipples.filter((ripple) => ripple.key !== lastRipple.key),
);
setButtonRipples((prevRipples) => prevRipples.filter((ripple) => ripple.key !== lastRipple.key));
}, parseInt(duration));
return () => clearTimeout(timeout);
}
@@ -60,7 +43,7 @@ export const RippleButton = React.forwardRef<
<button
className={cn(
"relative flex cursor-pointer items-center justify-center overflow-hidden rounded-lg border-2 bg-background px-4 py-2 text-center text-primary",
className,
className
)}
onClick={handleClick}
ref={ref}
@@ -85,7 +68,7 @@ export const RippleButton = React.forwardRef<
</span>
</button>
);
},
}
);
RippleButton.displayName = "RippleButton";

View File

@@ -1,8 +1,9 @@
"use client";
import { cn } from "@/lib/utils";
import { motion, MotionProps } from "motion/react";
import { useEffect, useRef, useState } from "react";
import { motion, MotionProps } from "motion/react";
import { cn } from "@/lib/utils";
interface TypingAnimationProps extends MotionProps {
children: string;
@@ -47,7 +48,7 @@ export function TypingAnimation({
observer.disconnect();
}
},
{ threshold: 0.1 },
{ threshold: 0.1 }
);
if (elementRef.current) {
@@ -78,10 +79,7 @@ export function TypingAnimation({
return (
<MotionComponent
ref={elementRef}
className={cn(
"text-4xl font-bold leading-[5rem] tracking-[-0.02em]",
className,
)}
className={cn("text-4xl font-bold leading-[5rem] tracking-[-0.02em]", className)}
{...props}
>
{displayedText}

View File

@@ -1,7 +1,7 @@
"use client";
import { AnimatePresence, motion, MotionProps } from "motion/react";
import { useEffect, useState } from "react";
import { AnimatePresence, motion, MotionProps } from "motion/react";
import { cn } from "@/lib/utils";
@@ -37,11 +37,7 @@ export function WordRotate({
return (
<div className="overflow-hidden py-2">
<AnimatePresence mode="wait">
<motion.h1
key={words[index]}
className={cn(className)}
{...motionProps}
>
<motion.h1 key={words[index]} className={cn(className)} {...motionProps}>
{words[index]}
</motion.h1>
</AnimatePresence>

View File

@@ -1,14 +1,10 @@
"use client";
import { motion } from "motion/react";
import { cn } from "@/lib/utils";
export const ThreeDMarquee = ({
images,
className,
}: {
images: string[];
className?: string;
}) => {
export const ThreeDMarquee = ({ images, className }: { images: string[]; className?: string }) => {
// Split the images array into 4 equal parts
const chunkSize = Math.ceil(images.length / 4);
const chunks = Array.from({ length: 4 }, (_, colIndex) => {
@@ -16,12 +12,7 @@ export const ThreeDMarquee = ({
return images.slice(start, start + chunkSize);
});
return (
<div
className={cn(
"mx-auto block h-[600px] overflow-hidden rounded-2xl max-sm:h-100",
className,
)}
>
<div className={cn("mx-auto block h-[600px] overflow-hidden rounded-2xl max-sm:h-100", className)}>
<div className="flex size-full items-center justify-center">
<div className="size-[1720px] shrink-0 scale-50 sm:scale-75 lg:scale-100">
<div
@@ -71,13 +62,7 @@ export const ThreeDMarquee = ({
);
};
const GridLineHorizontal = ({
className,
offset,
}: {
className?: string;
offset?: string;
}) => {
const GridLineHorizontal = ({ className, offset }: { className?: string; offset?: string }) => {
return (
<div
style={
@@ -100,19 +85,13 @@ const GridLineHorizontal = ({
"[mask-composite:exclude]",
"z-30",
"dark:bg-[linear-gradient(to_right,var(--color-dark),var(--color-dark)_50%,transparent_0,transparent)]",
className,
className
)}
></div>
);
};
const GridLineVertical = ({
className,
offset,
}: {
className?: string;
offset?: string;
}) => {
const GridLineVertical = ({ className, offset }: { className?: string; offset?: string }) => {
return (
<div
style={
@@ -135,7 +114,7 @@ const GridLineVertical = ({
"[mask-composite:exclude]",
"z-30",
"dark:bg-[linear-gradient(to_bottom,var(--color-dark),var(--color-dark)_50%,transparent_0,transparent)]",
className,
className
)}
></div>
);

View File

@@ -1,12 +1,12 @@
import { ButtonHTMLAttributes, forwardRef } from "react";
import { cn } from "@/lib/utils";
interface ButtonProps extends ButtonHTMLAttributes<HTMLButtonElement> {
className?: string;
}
export const Button = forwardRef<HTMLButtonElement, ButtonProps>(
({ className, children, ...props }, ref) => {
export const Button = forwardRef<HTMLButtonElement, ButtonProps>(({ className, children, ...props }, ref) => {
return (
<button
ref={ref}
@@ -28,7 +28,6 @@ export const Button = forwardRef<HTMLButtonElement, ButtonProps>(
{children}
</button>
);
}
);
});
Button.displayName = "Button";

View File

@@ -1,6 +1,7 @@
import Link from "next/link";
import { cn } from "@/lib/utils";
import { ReactNode } from "react";
import Link from "next/link";
import { cn } from "@/lib/utils";
interface CardProps {
title: string;
@@ -11,14 +12,7 @@ interface CardProps {
onClick?: () => void;
}
export const Card = ({
title,
description,
href,
icon,
className,
onClick,
}: CardProps) => {
export const Card = ({ title, description, href, icon, className, onClick }: CardProps) => {
const cardContent = (
<div
className={cn(
@@ -55,12 +49,7 @@ export const Card = ({
stroke="currentColor"
viewBox="0 0 24 24"
>
<path
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth={2.5}
d="M9 5l7 7-7 7"
/>
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2.5} d="M9 5l7 7-7 7" />
</svg>
</div>
</div>
@@ -93,15 +82,5 @@ interface CardGridProps {
}
export const CardGrid = ({ children, className }: CardGridProps) => {
return (
<div
className={cn(
"grid grid-cols-1 sm:grid-cols-2 gap-2.5 mt-5",
"max-w-4xl",
className
)}
>
{children}
</div>
);
return <div className={cn("grid grid-cols-1 sm:grid-cols-2 gap-2.5 mt-5", "max-w-4xl", className)}>{children}</div>;
};

View File

@@ -1,15 +1,9 @@
"use client";
import React, { useRef, useEffect, useState } from "react";
import React, { useEffect, useRef, useState } from "react";
import { motion } from "motion/react";
export const TextHoverEffect = ({
text,
duration,
}: {
text: string;
duration?: number;
automatic?: boolean;
}) => {
export const TextHoverEffect = ({ text, duration }: { text: string; duration?: number; automatic?: boolean }) => {
const svgRef = useRef<SVGSVGElement>(null);
const [cursor, setCursor] = useState({ x: 0, y: 0 });
const [hovered, setHovered] = useState(false);
@@ -40,13 +34,7 @@ export const TextHoverEffect = ({
className="select-none"
>
<defs>
<linearGradient
id="textGradient"
gradientUnits="userSpaceOnUse"
cx="50%"
cy="50%"
r="25%"
>
<linearGradient id="textGradient" gradientUnits="userSpaceOnUse" cx="50%" cy="50%" r="25%">
{hovered && (
<>
<stop offset="0%" stopColor="#eab308" />
@@ -78,13 +66,7 @@ export const TextHoverEffect = ({
<stop offset="100%" stopColor="black" />
</motion.radialGradient>
<mask id="textMask">
<rect
x="0"
y="0"
width="100%"
height="100%"
fill="url(#revealMask)"
/>
<rect x="0" y="0" width="100%" height="100%" fill="url(#revealMask)" />
</mask>
</defs>
<text

View File

@@ -1,8 +1,8 @@
"use client";
import { useEffect } from "react";
import { createPortal } from "react-dom";
import { CheckCircle } from "lucide-react";
import { createPortal } from "react-dom";
interface ToastProps {
message: string;

View File

@@ -1,20 +1,17 @@
"use client";
import React, { useState, useEffect } from "react";
import { cn } from "@/lib/utils";
import React, { useEffect, useState } from "react";
import { X, ZoomIn } from "lucide-react";
import { cn } from "@/lib/utils";
interface ZoomableImageProps {
src: string;
alt: string;
className?: string;
}
export const ZoomableImage: React.FC<ZoomableImageProps> = ({
src,
alt,
className,
}) => {
export const ZoomableImage: React.FC<ZoomableImageProps> = ({ src, alt, className }) => {
const [isZoomed, setIsZoomed] = useState(false);
const handleImageClick = () => {

View File

@@ -1,20 +1,19 @@
"use client";
import { LATEST_VERSION, LATEST_VERSION_PATH } from "@/config/constants";
import { AlertTriangle, ArrowRightIcon, X } from "lucide-react";
import { useEffect, useRef, useState } from "react";
import Link from "next/link";
import { useState, useEffect, useRef } from "react";
import { AlertTriangle, ArrowRightIcon, X } from "lucide-react";
function useIntersectionObserver(
targetRef: React.RefObject<HTMLDivElement | null>
) {
import { LATEST_VERSION, LATEST_VERSION_PATH } from "@/config/constants";
function useIntersectionObserver(targetRef: React.RefObject<HTMLDivElement | null>) {
const [isIntersecting, setIsIntersecting] = useState(true);
useEffect(() => {
const observer = new IntersectionObserver(
([entry]) => setIsIntersecting(entry.isIntersecting),
{ threshold: 0, rootMargin: "-10px 0px 0px 0px" }
);
const observer = new IntersectionObserver(([entry]) => setIsIntersecting(entry.isIntersecting), {
threshold: 0,
rootMargin: "-10px 0px 0px 0px",
});
if (targetRef.current) {
observer.observe(targetRef.current);
@@ -26,10 +25,7 @@ function useIntersectionObserver(
return isIntersecting;
}
function useClickOutside(
ref: React.RefObject<HTMLDivElement | null>,
callback: () => void
) {
function useClickOutside(ref: React.RefObject<HTMLDivElement | null>, callback: () => void) {
useEffect(() => {
const handleClickOutside = (event: MouseEvent) => {
if (ref.current && !ref.current.contains(event.target as Node)) {
@@ -59,16 +55,14 @@ function WarningContent({ onClose }: { onClose: () => void }) {
Deprecated version documentation
</h3>
<p className="text-[15px] text-amber-700 dark:text-amber-300 mb-3">
This documentation refers to a previous version of Palmr. It may
contain more complex configurations and bugs that have already been
fixed.
This documentation refers to a previous version of Palmr. It may contain more complex configurations and
bugs that have already been fixed.
</p>
<Link
href={LATEST_VERSION_PATH}
className="inline-flex items-center text-base font-medium text-amber-800 dark:text-amber-100 hover:text-amber-900 dark:hover:text-amber-200"
>
View latest documentation ({LATEST_VERSION}){" "}
<ArrowRightIcon className="w-4 h-4 ml-1 mt-0.5" />
View latest documentation ({LATEST_VERSION}) <ArrowRightIcon className="w-4 h-4 ml-1 mt-0.5" />
</Link>
</div>
</div>
@@ -85,10 +79,7 @@ function FloatingWarning({ onClose }: { onClose: () => void }) {
const toggleContent = () => setShowContent(!showContent);
return (
<div
className="fixed bottom-6 z-50"
style={{ right: "max(1.5rem, calc((100vw - 1024px) / 2 + 1.5rem))" }}
>
<div className="fixed bottom-6 z-50" style={{ right: "max(1.5rem, calc((100vw - 1024px) / 2 + 1.5rem))" }}>
<div className="relative" ref={floatingRef}>
<button
onClick={toggleContent}

View File

@@ -1,7 +1,8 @@
import { docs } from "@/.source";
import { createElement } from "react";
import { loader } from "fumadocs-core/source";
import { icons } from "lucide-react";
import { createElement } from "react";
import { docs } from "@/.source";
// See https://fumadocs.vercel.app/docs/headless/source-api for more info
export const source = loader({

View File

@@ -1,4 +1,4 @@
import { type ClassValue, clsx } from "clsx";
import { clsx, type ClassValue } from "clsx";
import { twMerge } from "tailwind-merge";
export function cn(...inputs: ClassValue[]) {

View File

@@ -1,5 +1,6 @@
import defaultMdxComponents from "fumadocs-ui/mdx";
import type { MDXComponents } from "mdx/types";
import { KeyGenerator } from "@/components/KeyGenerator";
import { OIDCProviderCards } from "@/components/OIDCProviderCards";
import { Card, CardGrid } from "@/components/ui/card";

View File

@@ -2,11 +2,7 @@
"compilerOptions": {
"baseUrl": ".",
"target": "ESNext",
"lib": [
"dom",
"dom.iterable",
"esnext"
],
"lib": ["dom", "dom.iterable", "esnext"],
"allowJs": true,
"skipLibCheck": true,
"strict": true,
@@ -20,12 +16,8 @@
"jsx": "preserve",
"incremental": true,
"paths": {
"@/.source": [
"./.source/index.ts"
],
"@/*": [
"./src/*"
]
"@/.source": ["./.source/index.ts"],
"@/*": ["./src/*"]
},
"plugins": [
{
@@ -33,13 +25,6 @@
}
]
},
"include": [
"next-env.d.ts",
"**/*.ts",
"**/*.tsx",
".next/types/**/*.ts"
],
"exclude": [
"node_modules"
]
"exclude": ["node_modules"],
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"]
}