mirror of
https://github.com/Luchexx/wacrm.git
synced 2026-11-02 17:29:45 +00:00
Merge pull request #73 from ArnasDon/chore/contributor-experience
chore: fork-first contributor docs + housekeeping
This commit is contained in:
commit
9c25971c27
13
.editorconfig
Normal file
13
.editorconfig
Normal file
@ -0,0 +1,13 @@
|
||||
root = true
|
||||
|
||||
[*]
|
||||
charset = utf-8
|
||||
end_of_line = lf
|
||||
indent_style = space
|
||||
indent_size = 2
|
||||
insert_final_newline = true
|
||||
trim_trailing_whitespace = true
|
||||
|
||||
[*.md]
|
||||
# Markdown line breaks come from trailing spaces; don't strip them.
|
||||
trim_trailing_whitespace = false
|
||||
28
.github/CODE_OF_CONDUCT.md
vendored
Normal file
28
.github/CODE_OF_CONDUCT.md
vendored
Normal file
@ -0,0 +1,28 @@
|
||||
# Code of Conduct
|
||||
|
||||
This project adopts the **[Contributor Covenant, version 2.1][covenant]**.
|
||||
|
||||
By participating in this project — filing an issue, opening a PR, commenting
|
||||
on one, or interacting in any other community space — you agree to uphold
|
||||
that standard.
|
||||
|
||||
## Reporting
|
||||
|
||||
If you witness or experience behaviour that violates the Code, please
|
||||
report it privately to the project maintainer:
|
||||
|
||||
- Email: **a.donauskas@hostinger.com** with `[WaCRM conduct]` in the
|
||||
subject.
|
||||
|
||||
Reports are handled confidentially. Expect an acknowledgement within
|
||||
72 hours and a decision on next steps within a week.
|
||||
|
||||
## Enforcement
|
||||
|
||||
The maintainer is responsible for enforcement and will apply the community
|
||||
impact guidelines described in the [Contributor Covenant][covenant-enforce]
|
||||
— ranging from a private correction to a permanent ban, proportional to the
|
||||
behaviour.
|
||||
|
||||
[covenant]: https://www.contributor-covenant.org/version/2/1/code_of_conduct/
|
||||
[covenant-enforce]: https://www.contributor-covenant.org/version/2/1/code_of_conduct/#enforcement-guidelines
|
||||
76
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
Normal file
76
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
Normal file
@ -0,0 +1,76 @@
|
||||
name: Bug report
|
||||
description: Something in WaCRM isn't working the way the docs say it should.
|
||||
title: "[bug] "
|
||||
labels: ["bug", "triage"]
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
Thanks for reporting! The more specific you can be, the faster we
|
||||
can land a fix.
|
||||
|
||||
**Not a bug in the code?** If this is a security issue, close this
|
||||
form and follow [SECURITY.md](https://github.com/ArnasDon/wacrm/blob/main/.github/SECURITY.md)
|
||||
instead.
|
||||
|
||||
- type: textarea
|
||||
id: summary
|
||||
attributes:
|
||||
label: What happened?
|
||||
description: One or two sentences describing the symptom.
|
||||
placeholder: Clicking a conversation leaves the thread stuck on "No messages yet".
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: textarea
|
||||
id: steps
|
||||
attributes:
|
||||
label: Steps to reproduce
|
||||
description: The minimum steps we need to trigger the bug on our side.
|
||||
placeholder: |
|
||||
1. Sign in, go to /inbox.
|
||||
2. Click any conversation that has past messages.
|
||||
3. Thread pane shows "No messages yet" until hard refresh.
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: textarea
|
||||
id: expected
|
||||
attributes:
|
||||
label: What did you expect?
|
||||
placeholder: Messages load the first time, every time.
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: input
|
||||
id: version
|
||||
attributes:
|
||||
label: Commit / version
|
||||
description: |
|
||||
The commit SHA or release you're on. `git rev-parse --short HEAD`
|
||||
in the fork works.
|
||||
placeholder: "e.g. d6a4677 or v0.2.0"
|
||||
validations:
|
||||
required: false
|
||||
|
||||
- type: dropdown
|
||||
id: runtime
|
||||
attributes:
|
||||
label: Where is it running?
|
||||
options:
|
||||
- Local dev (npm run dev)
|
||||
- Hostinger Managed Node.js
|
||||
- Hostinger VPS
|
||||
- Vercel
|
||||
- Other Node host
|
||||
validations:
|
||||
required: false
|
||||
|
||||
- type: textarea
|
||||
id: logs
|
||||
attributes:
|
||||
label: Logs / screenshots
|
||||
description: Server logs, browser console errors, network tab — anything that looks suspicious. Scrub tokens before pasting.
|
||||
render: text
|
||||
validations:
|
||||
required: false
|
||||
11
.github/ISSUE_TEMPLATE/config.yml
vendored
Normal file
11
.github/ISSUE_TEMPLATE/config.yml
vendored
Normal file
@ -0,0 +1,11 @@
|
||||
blank_issues_enabled: false
|
||||
contact_links:
|
||||
- name: Security vulnerability (private)
|
||||
url: https://github.com/ArnasDon/wacrm/security/advisories/new
|
||||
about: Do not file security issues in public. Follow the private disclosure flow.
|
||||
- name: Setup / "how do I..." questions
|
||||
url: https://github.com/ArnasDon/wacrm/blob/main/docs/README.md
|
||||
about: Check the docs first — setup, deploy, troubleshooting are all covered.
|
||||
- name: Using WaCRM as a template (forking)
|
||||
url: https://github.com/ArnasDon/wacrm/blob/main/CONTRIBUTING.md
|
||||
about: WaCRM is a template. Most changes belong in your fork, not an upstream issue — here's how that works.
|
||||
68
.github/ISSUE_TEMPLATE/feature_request.yml
vendored
Normal file
68
.github/ISSUE_TEMPLATE/feature_request.yml
vendored
Normal file
@ -0,0 +1,68 @@
|
||||
name: Feature request
|
||||
description: Propose a new feature or a meaningful enhancement.
|
||||
title: "[feat] "
|
||||
labels: ["enhancement", "triage"]
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
Thanks for the idea — but read this first.
|
||||
|
||||
WaCRM is a **template**, not a collaborative product. The
|
||||
upstream scope is intentionally narrow, so most feature
|
||||
requests end up as *"build this in your fork"* rather than
|
||||
landing here. That's the point of a template.
|
||||
|
||||
When an upstream feature request *is* useful:
|
||||
|
||||
- It fixes a correctness problem in the template.
|
||||
- It makes the template cleaner for the next forker (reducing
|
||||
friction, removing footguns).
|
||||
- It's in scope for "a generic WhatsApp CRM template" rather
|
||||
than a bet on your specific workflow.
|
||||
|
||||
If the feature is really for your own deployment, fork and
|
||||
build it there — see
|
||||
[CONTRIBUTING.md](https://github.com/ArnasDon/wacrm/blob/main/CONTRIBUTING.md).
|
||||
|
||||
- type: textarea
|
||||
id: problem
|
||||
attributes:
|
||||
label: What's the problem?
|
||||
description: What are you trying to do today that WaCRM makes harder than it should?
|
||||
placeholder: |
|
||||
When a broadcast ends I have no way to see which recipients
|
||||
didn't reply so I can follow up manually.
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: textarea
|
||||
id: proposal
|
||||
attributes:
|
||||
label: What would you like to see?
|
||||
description: Describe the feature from the user's perspective, not the implementation.
|
||||
placeholder: |
|
||||
On the broadcast detail page, a "No reply" filter that lists
|
||||
recipients who received but didn't reply within 24 hours.
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: textarea
|
||||
id: alternatives
|
||||
attributes:
|
||||
label: Alternatives you considered
|
||||
description: Things that kinda work today, workarounds, related features in other tools.
|
||||
validations:
|
||||
required: false
|
||||
|
||||
- type: dropdown
|
||||
id: scope
|
||||
attributes:
|
||||
label: Scope
|
||||
description: Your guess — we'll re-scope if needed.
|
||||
options:
|
||||
- Small (a couple of hours)
|
||||
- Medium (a couple of days)
|
||||
- Large (a couple of weeks, probably breaks into multiple PRs)
|
||||
validations:
|
||||
required: false
|
||||
53
.github/dependabot.yml
vendored
Normal file
53
.github/dependabot.yml
vendored
Normal file
@ -0,0 +1,53 @@
|
||||
version: 2
|
||||
updates:
|
||||
# Runtime + dev dependencies. Weekly on Mondays — keeps the noise
|
||||
# predictable and aligns with a normal review cycle.
|
||||
- package-ecosystem: npm
|
||||
directory: "/"
|
||||
schedule:
|
||||
interval: weekly
|
||||
day: monday
|
||||
open-pull-requests-limit: 5
|
||||
reviewers:
|
||||
- ArnasDon
|
||||
labels:
|
||||
- dependencies
|
||||
groups:
|
||||
# Batch related upgrades into one PR so we're not closing six
|
||||
# independent Supabase-bumps per week.
|
||||
supabase:
|
||||
patterns:
|
||||
- "@supabase/*"
|
||||
types:
|
||||
patterns:
|
||||
- "@types/*"
|
||||
update-types:
|
||||
- minor
|
||||
- patch
|
||||
dev-dependencies:
|
||||
dependency-type: development
|
||||
update-types:
|
||||
- minor
|
||||
- patch
|
||||
ignore:
|
||||
# Next + React + Tailwind are pinned exactly on purpose. Let
|
||||
# them flow through manual major bumps when we're ready.
|
||||
- dependency-name: next
|
||||
- dependency-name: react
|
||||
- dependency-name: react-dom
|
||||
- dependency-name: tailwindcss
|
||||
- dependency-name: eslint-config-next
|
||||
|
||||
# GitHub Actions in .github/workflows/. Catches setup-node /
|
||||
# checkout version bumps that keep the CI matrix healthy.
|
||||
- package-ecosystem: github-actions
|
||||
directory: "/"
|
||||
schedule:
|
||||
interval: weekly
|
||||
day: monday
|
||||
open-pull-requests-limit: 3
|
||||
reviewers:
|
||||
- ArnasDon
|
||||
labels:
|
||||
- dependencies
|
||||
- github-actions
|
||||
42
.github/pull_request_template.md
vendored
Normal file
42
.github/pull_request_template.md
vendored
Normal file
@ -0,0 +1,42 @@
|
||||
<!--
|
||||
Heads up: WaCRM is a template, not a collaborative product. Most
|
||||
changes belong in your fork. See CONTRIBUTING.md for which kinds of
|
||||
upstream PRs tend to land (security, correctness, docs) vs. which
|
||||
belong in a fork (new features, stack swaps, opinionated refactors).
|
||||
If you haven't opened an issue yet for a non-trivial change, consider
|
||||
doing that first to check alignment.
|
||||
|
||||
Keep this short and specific. The commit message is where the "why"
|
||||
lives; this is where the reviewer gets the "what" and "how to try it".
|
||||
-->
|
||||
|
||||
## Summary
|
||||
|
||||
<!-- One or two sentences. What does this PR do? -->
|
||||
|
||||
## What changed
|
||||
|
||||
<!-- Bullet list of the actual changes. Link file paths when useful. -->
|
||||
|
||||
## Test plan
|
||||
|
||||
<!--
|
||||
How did you verify this works? How should the reviewer verify it?
|
||||
Tick the boxes as you go.
|
||||
-->
|
||||
|
||||
- [ ] `npm run typecheck` clean.
|
||||
- [ ] `npm run lint` — no new errors beyond the pre-existing backlog.
|
||||
- [ ] `npm run build` succeeds.
|
||||
- [ ] Feature / fix manually exercised in the browser (or the reason it can't be).
|
||||
|
||||
## Related
|
||||
|
||||
<!-- Link the issue this closes, or "Part of #N" for multi-PR work. -->
|
||||
|
||||
<!--
|
||||
Heads up:
|
||||
- Security issues: do not disclose here; see .github/SECURITY.md.
|
||||
- New deps: please justify briefly in the commit message or PR body.
|
||||
- Runtime behaviour changes affecting forkers: update docs/*.
|
||||
-->
|
||||
9
.prettierignore
Normal file
9
.prettierignore
Normal file
@ -0,0 +1,9 @@
|
||||
node_modules
|
||||
.next
|
||||
out
|
||||
build
|
||||
coverage
|
||||
next-env.d.ts
|
||||
package-lock.json
|
||||
# Generated / vendored
|
||||
supabase/migrations
|
||||
10
.prettierrc
Normal file
10
.prettierrc
Normal file
@ -0,0 +1,10 @@
|
||||
{
|
||||
"semi": true,
|
||||
"singleQuote": true,
|
||||
"trailingComma": "es5",
|
||||
"printWidth": 80,
|
||||
"tabWidth": 2,
|
||||
"arrowParens": "always",
|
||||
"endOfLine": "lf",
|
||||
"plugins": ["prettier-plugin-tailwindcss"]
|
||||
}
|
||||
124
CONTRIBUTING.md
Normal file
124
CONTRIBUTING.md
Normal file
@ -0,0 +1,124 @@
|
||||
# Using WaCRM
|
||||
|
||||
WaCRM is a **template repository**, not a collaborative product. The
|
||||
expected flow is:
|
||||
|
||||
1. **Fork** it to your own GitHub account or organisation.
|
||||
2. **Deploy** the fork — see [`docs/`](./docs/README.md).
|
||||
3. **Customise** your fork. Rebrand, add the features you need, remove
|
||||
the ones you don't, swap hosting, change the schema.
|
||||
|
||||
You **don't** need to send changes back upstream. The fact that your
|
||||
fork diverges is the whole point — the upstream is deliberately
|
||||
opinionated about stack, UX, and scope, and your fork is where those
|
||||
opinions become yours.
|
||||
|
||||
## Fork and run
|
||||
|
||||
```bash
|
||||
# 1. Fork on GitHub: https://github.com/ArnasDon/wacrm → Fork
|
||||
# 2. Clone your fork
|
||||
git clone https://github.com/<your-username>/wacrm.git
|
||||
cd wacrm
|
||||
|
||||
cp .env.local.example .env.local # fill in Supabase + Meta creds
|
||||
npm install
|
||||
npm run dev
|
||||
```
|
||||
|
||||
Full setup (Supabase migrations, WhatsApp Business API, deploy) lives in
|
||||
[`docs/`](./docs/README.md).
|
||||
|
||||
## Keeping your fork up to date
|
||||
|
||||
Pull in upstream bug fixes and security patches periodically:
|
||||
|
||||
```bash
|
||||
git remote add upstream https://github.com/ArnasDon/wacrm.git # once
|
||||
git fetch upstream
|
||||
git checkout main
|
||||
git merge upstream/main # or: git rebase upstream/main
|
||||
# Resolve any conflicts (likely in areas you've customised), then push
|
||||
git push origin main
|
||||
```
|
||||
|
||||
If you've made heavy local customisations, rebasing can surface
|
||||
conflicts every time you pull. Pinning to a specific upstream tag and
|
||||
updating on your schedule is a valid alternative.
|
||||
|
||||
## Reporting bugs in the upstream template
|
||||
|
||||
If you find a bug in the upstream code — not one you introduced in your
|
||||
fork — please file it using the
|
||||
[bug report](https://github.com/ArnasDon/wacrm/issues/new?template=bug_report.yml)
|
||||
template. Including the commit SHA, the runtime (Hostinger / Vercel /
|
||||
local / other), and logs will get to a fix fastest.
|
||||
|
||||
## Reporting security issues
|
||||
|
||||
**Do not file security issues publicly.** Follow the private flow in
|
||||
[SECURITY.md](./.github/SECURITY.md).
|
||||
|
||||
## Upstream pull requests
|
||||
|
||||
Not the primary flow, but welcome in specific cases:
|
||||
|
||||
- **Security fixes** — always welcome, please follow SECURITY.md first
|
||||
for disclosure.
|
||||
- **Bug fixes** that match upstream intent (crash, correctness,
|
||||
documentation errors, typos) — land quickly.
|
||||
- **Small improvements** (accessibility, obvious UX nits) — usually
|
||||
welcome, open an issue first to check alignment.
|
||||
|
||||
Less likely to land:
|
||||
|
||||
- **New features.** The template's scope is intentionally narrow. A
|
||||
"great idea for a CRM" is often a great idea for *your* CRM — i.e.
|
||||
your fork — but would dilute the template for the next forker.
|
||||
- **Stack changes** (different ORM, different UI kit, different auth
|
||||
provider). These belong in a fork, not upstream.
|
||||
- **Opinionated refactors** without a concrete correctness or
|
||||
performance motivation.
|
||||
|
||||
If you do send a PR, the usual rules apply:
|
||||
|
||||
- Branch off the latest `main` (don't push to a merged branch — commits
|
||||
end up orphaned).
|
||||
- Run `npm run typecheck` and `npm run format` locally first.
|
||||
- Fill in the PR template, especially the **Test plan**.
|
||||
- One logical change per PR.
|
||||
- Commit-message first line is imperative + terse; the body explains
|
||||
the *why*, the diff shows the *what*.
|
||||
|
||||
Expect a review within a few days. PRs opened without an issue may be
|
||||
closed — open the issue first to align.
|
||||
|
||||
## If you maintain a public fork
|
||||
|
||||
- Rebrand. The WaCRM name, favicon, and `wacrm.tech` URL belong to the
|
||||
upstream project; please swap them for your own before putting your
|
||||
deployment in front of users.
|
||||
- Keep the MIT [`LICENSE`](./LICENSE) file — that's how the template's
|
||||
permissions travel with the code. Attribution in a `README` section
|
||||
is appreciated but not required.
|
||||
- You are free to re-license additions to your fork however you like.
|
||||
|
||||
## Dev-loop reference
|
||||
|
||||
Even if you never send a PR upstream, these are the scripts you'll use
|
||||
in your fork:
|
||||
|
||||
| Command | What it does |
|
||||
| --- | --- |
|
||||
| `npm run dev` | Turbopack dev server on port 3000. |
|
||||
| `npm run build` | Production build. Next also runs its own typecheck here. |
|
||||
| `npm run typecheck` | `tsc --noEmit`. Fast TS-only pass. |
|
||||
| `npm run lint` | ESLint. |
|
||||
| `npm run format` | Prettier write. |
|
||||
| `npm run format:check` | Prettier in check-only mode. Useful in CI. |
|
||||
|
||||
## Licensing
|
||||
|
||||
This template is MIT ([`LICENSE`](./LICENSE)). Anything you contribute
|
||||
upstream is assumed to be MIT too. Your fork's additions are yours to
|
||||
license however you like.
|
||||
97
package-lock.json
generated
97
package-lock.json
generated
@ -35,6 +35,8 @@
|
||||
"@types/react-dom": "^19",
|
||||
"eslint": "^9",
|
||||
"eslint-config-next": "16.2.4",
|
||||
"prettier": "^3.8.3",
|
||||
"prettier-plugin-tailwindcss": "^0.7.2",
|
||||
"tailwindcss": "^4",
|
||||
"typescript": "^5"
|
||||
},
|
||||
@ -7939,6 +7941,101 @@
|
||||
"node": ">= 0.8.0"
|
||||
}
|
||||
},
|
||||
"node_modules/prettier": {
|
||||
"version": "3.8.3",
|
||||
"resolved": "https://registry.npmjs.org/prettier/-/prettier-3.8.3.tgz",
|
||||
"integrity": "sha512-7igPTM53cGHMW8xWuVTydi2KO233VFiTNyF5hLJqpilHfmn8C8gPf+PS7dUT64YcXFbiMGZxS9pCSxL/Dxm/Jw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"bin": {
|
||||
"prettier": "bin/prettier.cjs"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=14"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/prettier/prettier?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/prettier-plugin-tailwindcss": {
|
||||
"version": "0.7.2",
|
||||
"resolved": "https://registry.npmjs.org/prettier-plugin-tailwindcss/-/prettier-plugin-tailwindcss-0.7.2.tgz",
|
||||
"integrity": "sha512-LkphyK3Fw+q2HdMOoiEHWf93fNtYJwfamoKPl7UwtjFQdei/iIBoX11G6j706FzN3ymX9mPVi97qIY8328vdnA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=20.19"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@ianvs/prettier-plugin-sort-imports": "*",
|
||||
"@prettier/plugin-hermes": "*",
|
||||
"@prettier/plugin-oxc": "*",
|
||||
"@prettier/plugin-pug": "*",
|
||||
"@shopify/prettier-plugin-liquid": "*",
|
||||
"@trivago/prettier-plugin-sort-imports": "*",
|
||||
"@zackad/prettier-plugin-twig": "*",
|
||||
"prettier": "^3.0",
|
||||
"prettier-plugin-astro": "*",
|
||||
"prettier-plugin-css-order": "*",
|
||||
"prettier-plugin-jsdoc": "*",
|
||||
"prettier-plugin-marko": "*",
|
||||
"prettier-plugin-multiline-arrays": "*",
|
||||
"prettier-plugin-organize-attributes": "*",
|
||||
"prettier-plugin-organize-imports": "*",
|
||||
"prettier-plugin-sort-imports": "*",
|
||||
"prettier-plugin-svelte": "*"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@ianvs/prettier-plugin-sort-imports": {
|
||||
"optional": true
|
||||
},
|
||||
"@prettier/plugin-hermes": {
|
||||
"optional": true
|
||||
},
|
||||
"@prettier/plugin-oxc": {
|
||||
"optional": true
|
||||
},
|
||||
"@prettier/plugin-pug": {
|
||||
"optional": true
|
||||
},
|
||||
"@shopify/prettier-plugin-liquid": {
|
||||
"optional": true
|
||||
},
|
||||
"@trivago/prettier-plugin-sort-imports": {
|
||||
"optional": true
|
||||
},
|
||||
"@zackad/prettier-plugin-twig": {
|
||||
"optional": true
|
||||
},
|
||||
"prettier-plugin-astro": {
|
||||
"optional": true
|
||||
},
|
||||
"prettier-plugin-css-order": {
|
||||
"optional": true
|
||||
},
|
||||
"prettier-plugin-jsdoc": {
|
||||
"optional": true
|
||||
},
|
||||
"prettier-plugin-marko": {
|
||||
"optional": true
|
||||
},
|
||||
"prettier-plugin-multiline-arrays": {
|
||||
"optional": true
|
||||
},
|
||||
"prettier-plugin-organize-attributes": {
|
||||
"optional": true
|
||||
},
|
||||
"prettier-plugin-organize-imports": {
|
||||
"optional": true
|
||||
},
|
||||
"prettier-plugin-sort-imports": {
|
||||
"optional": true
|
||||
},
|
||||
"prettier-plugin-svelte": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/pretty-ms": {
|
||||
"version": "9.3.0",
|
||||
"resolved": "https://registry.npmjs.org/pretty-ms/-/pretty-ms-9.3.0.tgz",
|
||||
|
||||
@ -32,7 +32,9 @@
|
||||
"build": "next build",
|
||||
"start": "next start",
|
||||
"lint": "eslint",
|
||||
"typecheck": "tsc --noEmit"
|
||||
"typecheck": "tsc --noEmit",
|
||||
"format": "prettier --write .",
|
||||
"format:check": "prettier --check ."
|
||||
},
|
||||
"dependencies": {
|
||||
"@base-ui/react": "^1.4.0",
|
||||
@ -61,6 +63,8 @@
|
||||
"@types/react-dom": "^19",
|
||||
"eslint": "^9",
|
||||
"eslint-config-next": "16.2.4",
|
||||
"prettier": "^3.8.3",
|
||||
"prettier-plugin-tailwindcss": "^0.7.2",
|
||||
"tailwindcss": "^4",
|
||||
"typescript": "^5"
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user