joys-fonts 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +105 -0
- package/bin/cli.js +250 -0
- package/fonts/joys-inter/joys-inter.css +47 -0
- package/fonts/joys-inter/woff2/joys-inter-300.woff2 +0 -0
- package/fonts/joys-inter/woff2/joys-inter-400.woff2 +0 -0
- package/fonts/joys-inter/woff2/joys-inter-500.woff2 +0 -0
- package/fonts/joys-inter/woff2/joys-inter-600.woff2 +0 -0
- package/fonts/joys-inter/woff2/joys-inter-700.woff2 +0 -0
- package/fonts/joys-inter/woff2/joys-inter-800.woff2 +0 -0
- package/fonts/joys-iran-sans-x/joys-iran-sans-x.css +201 -0
- package/fonts/joys-iran-sans-x/woff2/joys-iran-sans-x-100.woff2 +0 -0
- package/fonts/joys-iran-sans-x/woff2/joys-iran-sans-x-200.woff2 +0 -0
- package/fonts/joys-iran-sans-x/woff2/joys-iran-sans-x-300.woff2 +0 -0
- package/fonts/joys-iran-sans-x/woff2/joys-iran-sans-x-400.woff2 +0 -0
- package/fonts/joys-iran-sans-x/woff2/joys-iran-sans-x-500.woff2 +0 -0
- package/fonts/joys-iran-sans-x/woff2/joys-iran-sans-x-600.woff2 +0 -0
- package/fonts/joys-iran-sans-x/woff2/joys-iran-sans-x-700.woff2 +0 -0
- package/fonts/joys-iran-sans-x/woff2/joys-iran-sans-x-800.woff2 +0 -0
- package/fonts/joys-iran-sans-x/woff2/joys-iran-sans-x-900.woff2 +0 -0
- package/fonts/joys-iran-sans-x/woff2/joys-iran-sans-x-fanum-100.woff2 +0 -0
- package/fonts/joys-iran-sans-x/woff2/joys-iran-sans-x-fanum-200.woff2 +0 -0
- package/fonts/joys-iran-sans-x/woff2/joys-iran-sans-x-fanum-300.woff2 +0 -0
- package/fonts/joys-iran-sans-x/woff2/joys-iran-sans-x-fanum-400.woff2 +0 -0
- package/fonts/joys-iran-sans-x/woff2/joys-iran-sans-x-fanum-500.woff2 +0 -0
- package/fonts/joys-iran-sans-x/woff2/joys-iran-sans-x-fanum-600.woff2 +0 -0
- package/fonts/joys-iran-sans-x/woff2/joys-iran-sans-x-fanum-700.woff2 +0 -0
- package/fonts/joys-iran-sans-x/woff2/joys-iran-sans-x-fanum-800.woff2 +0 -0
- package/fonts/joys-iran-sans-x/woff2/joys-iran-sans-x-fanum-900.woff2 +0 -0
- package/fonts/joys-iran-sans-x/woff2/joys-iran-sans-x-noen-100.woff2 +0 -0
- package/fonts/joys-iran-sans-x/woff2/joys-iran-sans-x-noen-200.woff2 +0 -0
- package/fonts/joys-iran-sans-x/woff2/joys-iran-sans-x-noen-300.woff2 +0 -0
- package/fonts/joys-iran-sans-x/woff2/joys-iran-sans-x-noen-400.woff2 +0 -0
- package/fonts/joys-iran-sans-x/woff2/joys-iran-sans-x-noen-500.woff2 +0 -0
- package/fonts/joys-iran-sans-x/woff2/joys-iran-sans-x-noen-600.woff2 +0 -0
- package/fonts/joys-iran-sans-x/woff2/joys-iran-sans-x-noen-700.woff2 +0 -0
- package/fonts/joys-iran-sans-x/woff2/joys-iran-sans-x-noen-800.woff2 +0 -0
- package/fonts/joys-iran-sans-x/woff2/joys-iran-sans-x-noen-900.woff2 +0 -0
- package/fonts/joys-iran-yekan-x/joys-iran-yekan-x.css +81 -0
- package/fonts/joys-iran-yekan-x/woff2/joys-iran-yekan-x-100.woff2 +0 -0
- package/fonts/joys-iran-yekan-x/woff2/joys-iran-yekan-x-1000.woff2 +0 -0
- package/fonts/joys-iran-yekan-x/woff2/joys-iran-yekan-x-200.woff2 +0 -0
- package/fonts/joys-iran-yekan-x/woff2/joys-iran-yekan-x-300.woff2 +0 -0
- package/fonts/joys-iran-yekan-x/woff2/joys-iran-yekan-x-400.woff2 +0 -0
- package/fonts/joys-iran-yekan-x/woff2/joys-iran-yekan-x-500.woff2 +0 -0
- package/fonts/joys-iran-yekan-x/woff2/joys-iran-yekan-x-600.woff2 +0 -0
- package/fonts/joys-iran-yekan-x/woff2/joys-iran-yekan-x-700.woff2 +0 -0
- package/fonts/joys-iran-yekan-x/woff2/joys-iran-yekan-x-800.woff2 +0 -0
- package/fonts/joys-iran-yekan-x/woff2/joys-iran-yekan-x-900.woff2 +0 -0
- package/fonts/joys-iran-yekan-x/woff2/joys-iran-yekan-x-950.woff2 +0 -0
- package/fonts/joys-kalameh/joys-kalameh.css +201 -0
- package/fonts/joys-kalameh/woff2/joys-kalameh-100.woff2 +0 -0
- package/fonts/joys-kalameh/woff2/joys-kalameh-200.woff2 +0 -0
- package/fonts/joys-kalameh/woff2/joys-kalameh-300.woff2 +0 -0
- package/fonts/joys-kalameh/woff2/joys-kalameh-400.woff2 +0 -0
- package/fonts/joys-kalameh/woff2/joys-kalameh-500.woff2 +0 -0
- package/fonts/joys-kalameh/woff2/joys-kalameh-600.woff2 +0 -0
- package/fonts/joys-kalameh/woff2/joys-kalameh-700.woff2 +0 -0
- package/fonts/joys-kalameh/woff2/joys-kalameh-800.woff2 +0 -0
- package/fonts/joys-kalameh/woff2/joys-kalameh-900.woff2 +0 -0
- package/fonts/joys-kalameh/woff2/joys-kalameh-fanum-100.woff2 +0 -0
- package/fonts/joys-kalameh/woff2/joys-kalameh-fanum-200.woff2 +0 -0
- package/fonts/joys-kalameh/woff2/joys-kalameh-fanum-300.woff2 +0 -0
- package/fonts/joys-kalameh/woff2/joys-kalameh-fanum-400.woff2 +0 -0
- package/fonts/joys-kalameh/woff2/joys-kalameh-fanum-500.woff2 +0 -0
- package/fonts/joys-kalameh/woff2/joys-kalameh-fanum-600.woff2 +0 -0
- package/fonts/joys-kalameh/woff2/joys-kalameh-fanum-700.woff2 +0 -0
- package/fonts/joys-kalameh/woff2/joys-kalameh-fanum-800.woff2 +0 -0
- package/fonts/joys-kalameh/woff2/joys-kalameh-fanum-900.woff2 +0 -0
- package/fonts/joys-kalameh/woff2/joys-kalameh-noen-100.woff2 +0 -0
- package/fonts/joys-kalameh/woff2/joys-kalameh-noen-200.woff2 +0 -0
- package/fonts/joys-kalameh/woff2/joys-kalameh-noen-300.woff2 +0 -0
- package/fonts/joys-kalameh/woff2/joys-kalameh-noen-400.woff2 +0 -0
- package/fonts/joys-kalameh/woff2/joys-kalameh-noen-500.woff2 +0 -0
- package/fonts/joys-kalameh/woff2/joys-kalameh-noen-600.woff2 +0 -0
- package/fonts/joys-kalameh/woff2/joys-kalameh-noen-700.woff2 +0 -0
- package/fonts/joys-kalameh/woff2/joys-kalameh-noen-800.woff2 +0 -0
- package/fonts/joys-kalameh/woff2/joys-kalameh-noen-900.woff2 +0 -0
- package/fonts/joys-morabba/joys-morabba.css +77 -0
- package/fonts/joys-morabba/woff2/joys-morabba-200.woff2 +0 -0
- package/fonts/joys-morabba/woff2/joys-morabba-300.woff2 +0 -0
- package/fonts/joys-morabba/woff2/joys-morabba-400.woff2 +0 -0
- package/fonts/joys-morabba/woff2/joys-morabba-500.woff2 +0 -0
- package/fonts/joys-morabba/woff2/joys-morabba-600.woff2 +0 -0
- package/fonts/joys-morabba/woff2/joys-morabba-700.woff2 +0 -0
- package/fonts/joys-morabba/woff2/joys-morabba-800.woff2 +0 -0
- package/fonts/joys-morabba/woff2/joys-morabba-900.woff2 +0 -0
- package/fonts/joys-morabba/woff2/joys-morabba-950.woff2 +0 -0
- package/fonts/joys-vazir/joys-vazir.css +68 -0
- package/fonts/joys-vazir/woff2/joys-vazir-100.woff2 +0 -0
- package/fonts/joys-vazir/woff2/joys-vazir-200.woff2 +0 -0
- package/fonts/joys-vazir/woff2/joys-vazir-300.woff2 +0 -0
- package/fonts/joys-vazir/woff2/joys-vazir-400.woff2 +0 -0
- package/fonts/joys-vazir/woff2/joys-vazir-500.woff2 +0 -0
- package/fonts/joys-vazir/woff2/joys-vazir-600.woff2 +0 -0
- package/fonts/joys-vazir/woff2/joys-vazir-700.woff2 +0 -0
- package/fonts/joys-vazir/woff2/joys-vazir-800.woff2 +0 -0
- package/fonts/joys-vazir/woff2/joys-vazir-900.woff2 +0 -0
- package/fonts/joys-yekan-bakh/joys-yekan-bakh.css +48 -0
- package/fonts/joys-yekan-bakh/woff2/joys-yekan-bakh-fanum-vf.woff2 +0 -0
- package/fonts/joys-yekan-bakh/woff2/joys-yekan-bakh-noen-vf.woff2 +0 -0
- package/fonts/joys-yekan-bakh/woff2/joys-yekan-bakh-vf.woff2 +0 -0
- package/fonts.manifest.json +734 -0
- package/package.json +35 -0
- package/src/index.d.ts +42 -0
- package/src/index.js +189 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 joys
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
# Joys Fonts
|
|
2
|
+
|
|
3
|
+
Joys Fonts is a modern platform and CLI utility designed to package and install Persian web fonts into Tailwind CSS projects (specifically targeting **Tailwind CSS v4+**).
|
|
4
|
+
|
|
5
|
+
Instead of manual setup or adding the entire font collection as a dependency, the Joys Fonts CLI allows you to download and configure only the specific fonts you need.
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## Features
|
|
10
|
+
|
|
11
|
+
- **Tailwind CSS v4+ Native**: Automatically updates your main CSS file, injecting `@import` statements and registering theme variables inside the Tailwind `@theme` block.
|
|
12
|
+
- **Zero-Dependency CLI**: Written in native Node.js ES Modules. Extremely fast and lightweight.
|
|
13
|
+
- **WOFF2 Optimized**: Only keeps modern, optimized WOFF2 font assets for maximum web performance.
|
|
14
|
+
- **Supports Static & Variable Fonts**: Installs and maps font weights (including custom axes) appropriately.
|
|
15
|
+
|
|
16
|
+
---
|
|
17
|
+
|
|
18
|
+
## Installation & Usage
|
|
19
|
+
|
|
20
|
+
You don't need to install this package. You can run the installer CLI in the root of your project using your preferred package manager:
|
|
21
|
+
|
|
22
|
+
### npm
|
|
23
|
+
```bash
|
|
24
|
+
npx joys-fonts add <font-slug>
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
### pnpm
|
|
28
|
+
```bash
|
|
29
|
+
pnpm dlx joys-fonts add <font-slug>
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
### yarn
|
|
33
|
+
```bash
|
|
34
|
+
yarn dlx joys-fonts add <font-slug>
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
### bun
|
|
38
|
+
```bash
|
|
39
|
+
bunx joys-fonts add <font-slug>
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
For example, to install the `joys-iran-sans-x` font using pnpm:
|
|
43
|
+
|
|
44
|
+
```bash
|
|
45
|
+
pnpm dlx joys-fonts add joys-iran-sans-x
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
### Options
|
|
49
|
+
|
|
50
|
+
The CLI can be run non-interactively using options for automation and CI/CD:
|
|
51
|
+
|
|
52
|
+
```bash
|
|
53
|
+
npx joys-fonts add <font-slug> [options]
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
- `-d, --dest <path>`: Specify the directory where the font files should be copied.
|
|
57
|
+
- `-c, --css <path>`: Specify your project's global/Tailwind CSS stylesheet to update.
|
|
58
|
+
- `-y, --yes`: Auto-confirm all prompts with default settings.
|
|
59
|
+
|
|
60
|
+
---
|
|
61
|
+
|
|
62
|
+
## How It Works
|
|
63
|
+
|
|
64
|
+
When you run `npx joys-fonts add joys-iran-sans-x`, the CLI will:
|
|
65
|
+
1. Copy the font's WOFF2 files and its stylesheet (`joys-iran-sans-x.css`) to your project (e.g., `./src/fonts/joys-iran-sans-x`).
|
|
66
|
+
2. Inject the stylesheet `@import` at the top of your global CSS:
|
|
67
|
+
```css
|
|
68
|
+
@import "./fonts/joys-iran-sans-x/joys-iran-sans-x.css";
|
|
69
|
+
```
|
|
70
|
+
3. Update your Tailwind CSS v4 `@theme` block to declare the corresponding CSS font-family variables:
|
|
71
|
+
```css
|
|
72
|
+
@theme {
|
|
73
|
+
--font-iran-sans-x: "JoysIranSansX", sans-serif;
|
|
74
|
+
--font-iran-sans-x-fanum: "JoysIranSansXFaNum", sans-serif;
|
|
75
|
+
--font-iran-sans-x-noen: "JoysIranSansXNoEn", sans-serif;
|
|
76
|
+
}
|
|
77
|
+
```
|
|
78
|
+
4. Now, you can use standard Tailwind classes anywhere in your HTML or React code:
|
|
79
|
+
- `font-iran-sans-x` (Default Regular weight)
|
|
80
|
+
- `font-iran-sans-x-fanum` (Persian numbers version)
|
|
81
|
+
- `font-iran-sans-x-noen` (No English letters version)
|
|
82
|
+
|
|
83
|
+
---
|
|
84
|
+
|
|
85
|
+
## Available Fonts
|
|
86
|
+
|
|
87
|
+
The following fonts are packaged and available for installation:
|
|
88
|
+
|
|
89
|
+
- `joys-iran-sans-x`
|
|
90
|
+
- `joys-iran-yekan-x`
|
|
91
|
+
- `joys-kalameh`
|
|
92
|
+
- `joys-morabba`
|
|
93
|
+
- `joys-yekan-bakh`
|
|
94
|
+
|
|
95
|
+
---
|
|
96
|
+
|
|
97
|
+
## Contributing & Adding Fonts
|
|
98
|
+
|
|
99
|
+
If you want to contribute, add new Persian fonts, or edit existing ones, please follow our step-by-step guidelines in [CONTRIBUTING.md](./CONTRIBUTING.md) to keep the repository clean and standardized.
|
|
100
|
+
|
|
101
|
+
---
|
|
102
|
+
|
|
103
|
+
## License
|
|
104
|
+
|
|
105
|
+
MIT
|
package/bin/cli.js
ADDED
|
@@ -0,0 +1,250 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Joys Fonts Installer CLI
|
|
4
|
+
* Usage:
|
|
5
|
+
* npx joys-fonts [command] [options]
|
|
6
|
+
* node bin/cli.js [command] [options]
|
|
7
|
+
*
|
|
8
|
+
* Commands:
|
|
9
|
+
* add <font-slug> Install a font into your project
|
|
10
|
+
* list, ls List all available fonts
|
|
11
|
+
* help, -h, --help Show help screen
|
|
12
|
+
*
|
|
13
|
+
* Options:
|
|
14
|
+
* -d, --dest <path> Install destination directory
|
|
15
|
+
* -c, --css <path> Global CSS file path to update
|
|
16
|
+
* -y, --yes Auto-confirm with default options
|
|
17
|
+
*/
|
|
18
|
+
|
|
19
|
+
import fs from 'fs';
|
|
20
|
+
import path from 'path';
|
|
21
|
+
import readline from 'readline/promises';
|
|
22
|
+
import { stdin as input, stdout as output } from 'process';
|
|
23
|
+
import { manifest, installFont, detectTailwindVersion } from '../src/index.js';
|
|
24
|
+
|
|
25
|
+
// Parse command line arguments
|
|
26
|
+
function parseArgs(args) {
|
|
27
|
+
const options = {
|
|
28
|
+
command: null,
|
|
29
|
+
slug: null,
|
|
30
|
+
dest: null,
|
|
31
|
+
css: null,
|
|
32
|
+
yes: false,
|
|
33
|
+
help: false
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
const positionals = [];
|
|
37
|
+
for (let i = 0; i < args.length; i++) {
|
|
38
|
+
const arg = args[i];
|
|
39
|
+
if (arg === '--dest' || arg === '-d') {
|
|
40
|
+
options.dest = args[++i];
|
|
41
|
+
} else if (arg === '--css' || arg === '-c') {
|
|
42
|
+
options.css = args[++i];
|
|
43
|
+
} else if (arg === '--yes' || arg === '-y') {
|
|
44
|
+
options.yes = true;
|
|
45
|
+
} else if (arg === '--help' || arg === '-h' || arg === 'help') {
|
|
46
|
+
options.help = true;
|
|
47
|
+
} else {
|
|
48
|
+
positionals.push(arg);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
if (options.help) {
|
|
53
|
+
options.command = 'help';
|
|
54
|
+
} else if (positionals[0] === 'list' || positionals[0] === 'ls') {
|
|
55
|
+
options.command = 'list';
|
|
56
|
+
} else if (positionals[0] === 'add') {
|
|
57
|
+
options.command = 'add';
|
|
58
|
+
options.slug = positionals[1] || null;
|
|
59
|
+
} else if (positionals[0]) {
|
|
60
|
+
options.command = 'add';
|
|
61
|
+
options.slug = positionals[0];
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
return options;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
function printHelp() {
|
|
68
|
+
console.log(`
|
|
69
|
+
\x1b[35m=======================================\x1b[0m
|
|
70
|
+
\x1b[36m\x1b[1m Joys Fonts Installer CLI\x1b[0m
|
|
71
|
+
\x1b[35m=======================================\x1b[0m
|
|
72
|
+
|
|
73
|
+
Usage:
|
|
74
|
+
npx joys-fonts [command] [options]
|
|
75
|
+
|
|
76
|
+
Commands:
|
|
77
|
+
\x1b[32madd <font-slug>\x1b[0m Install a specific font
|
|
78
|
+
\x1b[32mlist, ls\x1b[0m List all available fonts
|
|
79
|
+
\x1b[32mhelp, -h, --help\x1b[0m Show this help screen
|
|
80
|
+
|
|
81
|
+
Options:
|
|
82
|
+
\x1b[33m-d, --dest <path>\x1b[0m Install destination directory
|
|
83
|
+
\x1b[33m-c, --css <path>\x1b[0m Global CSS file path to update
|
|
84
|
+
\x1b[33m-y, --yes\x1b[0m Auto-confirm with default options
|
|
85
|
+
|
|
86
|
+
Examples:
|
|
87
|
+
npx joys-fonts add joys-iran-sans-x
|
|
88
|
+
pnpm dlx joys-fonts list
|
|
89
|
+
yarn dlx joys-fonts add joys-kalameh --yes
|
|
90
|
+
`);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
function printList() {
|
|
94
|
+
console.log('\n\x1b[36mAvailable fonts in Joys Fonts:\x1b[0m');
|
|
95
|
+
console.log('\x1b[90m---------------------------------------\x1b[0m');
|
|
96
|
+
manifest.forEach((f, idx) => {
|
|
97
|
+
const families = f.families.map(fa => fa.family).join(', ');
|
|
98
|
+
console.log(` ${idx + 1}. \x1b[32m\x1b[1m${f.slug}\x1b[0m`);
|
|
99
|
+
console.log(` Families: \x1b[37m${families}\x1b[0m`);
|
|
100
|
+
console.log(` CSS Path: \x1b[90m${f.css}\x1b[0m`);
|
|
101
|
+
console.log('\x1b[90m---------------------------------------\x1b[0m');
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
async function main() {
|
|
106
|
+
const options = parseArgs(process.argv.slice(2));
|
|
107
|
+
|
|
108
|
+
if (options.command === 'help') {
|
|
109
|
+
printHelp();
|
|
110
|
+
process.exit(0);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
if (options.command === 'list') {
|
|
114
|
+
printList();
|
|
115
|
+
process.exit(0);
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
let slug = options.slug;
|
|
119
|
+
const rl = readline.createInterface({ input, output });
|
|
120
|
+
|
|
121
|
+
// If no slug is specified, prompt interactively
|
|
122
|
+
if (!slug) {
|
|
123
|
+
console.log('\n\x1b[35m=======================================\x1b[0m');
|
|
124
|
+
console.log('\x1b[36m\x1b[1m Joys Fonts Installer CLI\x1b[0m');
|
|
125
|
+
console.log('\x1b[35m=======================================\x1b[0m\n');
|
|
126
|
+
console.log('Available fonts:');
|
|
127
|
+
manifest.forEach((f, idx) => {
|
|
128
|
+
console.log(` [${idx + 1}] \x1b[32m${f.slug}\x1b[0m (${f.families.map(fa => fa.family).join(', ')})`);
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
const choice = await rl.question('\nSelect a font number or type slug (e.g. joys-kalameh): ');
|
|
132
|
+
const idxChoice = parseInt(choice, 10);
|
|
133
|
+
let selected = null;
|
|
134
|
+
|
|
135
|
+
if (!isNaN(idxChoice) && idxChoice >= 1 && idxChoice <= manifest.length) {
|
|
136
|
+
selected = manifest[idxChoice - 1];
|
|
137
|
+
} else {
|
|
138
|
+
const cleanChoice = choice.trim();
|
|
139
|
+
selected = manifest.find(f => f.slug === cleanChoice || f.slug === `joys-${cleanChoice}`);
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
if (!selected) {
|
|
143
|
+
console.error('\x1b[31m❌ Invalid selection.\x1b[0m');
|
|
144
|
+
rl.close();
|
|
145
|
+
process.exit(1);
|
|
146
|
+
}
|
|
147
|
+
slug = selected.slug;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
const fontEntry = manifest.find(f => f.slug === slug);
|
|
151
|
+
if (!fontEntry) {
|
|
152
|
+
console.error(`\x1b[31m❌ Font slug "${slug}" not found in manifest.\x1b[0m`);
|
|
153
|
+
console.log(`Run \x1b[32mnpx joys-fonts list\x1b[0m to see all available fonts.`);
|
|
154
|
+
rl.close();
|
|
155
|
+
process.exit(1);
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
console.log(`\nSelected font: \x1b[36m${fontEntry.slug}\x1b[0m`);
|
|
159
|
+
|
|
160
|
+
// Determine default destination
|
|
161
|
+
let defaultDest = `./fonts/${slug}`;
|
|
162
|
+
if (fs.existsSync('src') && fs.statSync('src').isDirectory()) {
|
|
163
|
+
defaultDest = `./src/fonts/${slug}`;
|
|
164
|
+
} else if (fs.existsSync('app') && fs.statSync('app').isDirectory()) {
|
|
165
|
+
defaultDest = `./app/fonts/${slug}`;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
let chosenDest = '';
|
|
169
|
+
if (options.dest) {
|
|
170
|
+
chosenDest = options.dest;
|
|
171
|
+
} else if (options.yes) {
|
|
172
|
+
chosenDest = defaultDest;
|
|
173
|
+
} else {
|
|
174
|
+
const destPathInput = await rl.question(`Install destination [\x1b[32m${defaultDest}\x1b[0m]: `);
|
|
175
|
+
chosenDest = destPathInput.trim() || defaultDest;
|
|
176
|
+
}
|
|
177
|
+
const destPath = path.resolve(chosenDest);
|
|
178
|
+
|
|
179
|
+
// Detect main CSS file
|
|
180
|
+
const commonCssPaths = [
|
|
181
|
+
'src/index.css',
|
|
182
|
+
'src/app.css',
|
|
183
|
+
'src/global.css',
|
|
184
|
+
'src/main.css',
|
|
185
|
+
'app/globals.css',
|
|
186
|
+
'app/global.css',
|
|
187
|
+
'index.css',
|
|
188
|
+
'global.css'
|
|
189
|
+
];
|
|
190
|
+
let defaultCss = '';
|
|
191
|
+
for (const p of commonCssPaths) {
|
|
192
|
+
if (fs.existsSync(p)) {
|
|
193
|
+
defaultCss = p;
|
|
194
|
+
break;
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
let chosenCss = '';
|
|
199
|
+
if (options.css) {
|
|
200
|
+
chosenCss = options.css;
|
|
201
|
+
} else if (options.yes) {
|
|
202
|
+
chosenCss = defaultCss;
|
|
203
|
+
} else {
|
|
204
|
+
const cssPathInput = await rl.question(`Tailwind/Global CSS file path to update${defaultCss ? ` [\x1b[32m${defaultCss}\x1b[0m]` : ''} (press Enter to skip): `);
|
|
205
|
+
chosenCss = cssPathInput.trim() || defaultCss;
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
let mainCssPath = null;
|
|
209
|
+
if (chosenCss) {
|
|
210
|
+
const resolvedCss = path.resolve(chosenCss);
|
|
211
|
+
if (fs.existsSync(resolvedCss)) {
|
|
212
|
+
mainCssPath = resolvedCss;
|
|
213
|
+
} else {
|
|
214
|
+
console.log(`\x1b[33m⚠️ Warning: File "${chosenCss}" does not exist. CSS/Tailwind configuration will be skipped.\x1b[0m`);
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
rl.close();
|
|
219
|
+
|
|
220
|
+
console.log('\nInstalling font files...');
|
|
221
|
+
try {
|
|
222
|
+
const tailwindVersion = detectTailwindVersion();
|
|
223
|
+
|
|
224
|
+
await installFont({
|
|
225
|
+
slug,
|
|
226
|
+
destPath,
|
|
227
|
+
cssPath: mainCssPath || undefined,
|
|
228
|
+
tailwindVersion
|
|
229
|
+
});
|
|
230
|
+
|
|
231
|
+
console.log(`\x1b[32m✅ Copied font files to: ${chosenDest}\x1b[0m`);
|
|
232
|
+
|
|
233
|
+
if (mainCssPath) {
|
|
234
|
+
console.log(`\x1b[32m✅ Successfully updated CSS configuration in ${path.relative(process.cwd(), mainCssPath)}\x1b[0m`);
|
|
235
|
+
if (tailwindVersion === 3) {
|
|
236
|
+
console.log(`\x1b[32m✅ Successfully extended fontFamily in tailwind.config file\x1b[0m`);
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
console.log(`\n\x1b[32m\x1b[1m🎉 Font ${slug} successfully installed! You can now use it in your project.\x1b[0m`);
|
|
241
|
+
} catch (err) {
|
|
242
|
+
console.error(`\x1b[31m❌ Installation failed: ${err.message}\x1b[0m`);
|
|
243
|
+
process.exit(1);
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
main().catch(err => {
|
|
248
|
+
console.error(`\x1b[31m❌ Unexpected error: ${err.message}\x1b[0m`);
|
|
249
|
+
process.exit(1);
|
|
250
|
+
});
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
@font-face {
|
|
2
|
+
font-family: 'JoysInter';
|
|
3
|
+
src: url('./woff2/joys-inter-300.woff2') format('woff2');
|
|
4
|
+
font-weight: 300;
|
|
5
|
+
font-style: normal;
|
|
6
|
+
font-display: swap;
|
|
7
|
+
}
|
|
8
|
+
@font-face {
|
|
9
|
+
font-family: 'JoysInter';
|
|
10
|
+
src: url('./woff2/joys-inter-400.woff2') format('woff2');
|
|
11
|
+
font-weight: 400;
|
|
12
|
+
font-style: normal;
|
|
13
|
+
font-display: swap;
|
|
14
|
+
}
|
|
15
|
+
@font-face {
|
|
16
|
+
font-family: 'JoysInter';
|
|
17
|
+
src: url('./woff2/joys-inter-500.woff2') format('woff2');
|
|
18
|
+
font-weight: 500;
|
|
19
|
+
font-style: normal;
|
|
20
|
+
font-display: swap;
|
|
21
|
+
}
|
|
22
|
+
@font-face {
|
|
23
|
+
font-family: 'JoysInter';
|
|
24
|
+
src: url('./woff2/joys-inter-600.woff2') format('woff2');
|
|
25
|
+
font-weight: 600;
|
|
26
|
+
font-style: normal;
|
|
27
|
+
font-display: swap;
|
|
28
|
+
}
|
|
29
|
+
@font-face {
|
|
30
|
+
font-family: 'JoysInter';
|
|
31
|
+
src: url('./woff2/joys-inter-700.woff2') format('woff2');
|
|
32
|
+
font-weight: 700;
|
|
33
|
+
font-style: normal;
|
|
34
|
+
font-display: swap;
|
|
35
|
+
}
|
|
36
|
+
@font-face {
|
|
37
|
+
font-family: 'JoysInter';
|
|
38
|
+
src: url('./woff2/joys-inter-800.woff2') format('woff2');
|
|
39
|
+
font-weight: 800;
|
|
40
|
+
font-style: normal;
|
|
41
|
+
font-display: swap;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
.font-inter {
|
|
45
|
+
font-family: 'JoysInter', sans-serif;
|
|
46
|
+
font-weight: 400;
|
|
47
|
+
}
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
@font-face {
|
|
2
|
+
font-family: 'JoysIranSansX';
|
|
3
|
+
src: url('./woff2/joys-iran-sans-x-100.woff2') format('woff2');
|
|
4
|
+
font-weight: 100;
|
|
5
|
+
font-style: normal;
|
|
6
|
+
font-display: swap;
|
|
7
|
+
}
|
|
8
|
+
@font-face {
|
|
9
|
+
font-family: 'JoysIranSansX';
|
|
10
|
+
src: url('./woff2/joys-iran-sans-x-200.woff2') format('woff2');
|
|
11
|
+
font-weight: 200;
|
|
12
|
+
font-style: normal;
|
|
13
|
+
font-display: swap;
|
|
14
|
+
}
|
|
15
|
+
@font-face {
|
|
16
|
+
font-family: 'JoysIranSansX';
|
|
17
|
+
src: url('./woff2/joys-iran-sans-x-300.woff2') format('woff2');
|
|
18
|
+
font-weight: 300;
|
|
19
|
+
font-style: normal;
|
|
20
|
+
font-display: swap;
|
|
21
|
+
}
|
|
22
|
+
@font-face {
|
|
23
|
+
font-family: 'JoysIranSansX';
|
|
24
|
+
src: url('./woff2/joys-iran-sans-x-400.woff2') format('woff2');
|
|
25
|
+
font-weight: 400;
|
|
26
|
+
font-style: normal;
|
|
27
|
+
font-display: swap;
|
|
28
|
+
}
|
|
29
|
+
@font-face {
|
|
30
|
+
font-family: 'JoysIranSansX';
|
|
31
|
+
src: url('./woff2/joys-iran-sans-x-500.woff2') format('woff2');
|
|
32
|
+
font-weight: 500;
|
|
33
|
+
font-style: normal;
|
|
34
|
+
font-display: swap;
|
|
35
|
+
}
|
|
36
|
+
@font-face {
|
|
37
|
+
font-family: 'JoysIranSansX';
|
|
38
|
+
src: url('./woff2/joys-iran-sans-x-600.woff2') format('woff2');
|
|
39
|
+
font-weight: 600;
|
|
40
|
+
font-style: normal;
|
|
41
|
+
font-display: swap;
|
|
42
|
+
}
|
|
43
|
+
@font-face {
|
|
44
|
+
font-family: 'JoysIranSansX';
|
|
45
|
+
src: url('./woff2/joys-iran-sans-x-700.woff2') format('woff2');
|
|
46
|
+
font-weight: 700;
|
|
47
|
+
font-style: normal;
|
|
48
|
+
font-display: swap;
|
|
49
|
+
}
|
|
50
|
+
@font-face {
|
|
51
|
+
font-family: 'JoysIranSansX';
|
|
52
|
+
src: url('./woff2/joys-iran-sans-x-800.woff2') format('woff2');
|
|
53
|
+
font-weight: 800;
|
|
54
|
+
font-style: normal;
|
|
55
|
+
font-display: swap;
|
|
56
|
+
}
|
|
57
|
+
@font-face {
|
|
58
|
+
font-family: 'JoysIranSansX';
|
|
59
|
+
src: url('./woff2/joys-iran-sans-x-900.woff2') format('woff2');
|
|
60
|
+
font-weight: 900;
|
|
61
|
+
font-style: normal;
|
|
62
|
+
font-display: swap;
|
|
63
|
+
}
|
|
64
|
+
@font-face {
|
|
65
|
+
font-family: 'JoysIranSansXFaNum';
|
|
66
|
+
src: url('./woff2/joys-iran-sans-x-fanum-100.woff2') format('woff2');
|
|
67
|
+
font-weight: 100;
|
|
68
|
+
font-style: normal;
|
|
69
|
+
font-display: swap;
|
|
70
|
+
}
|
|
71
|
+
@font-face {
|
|
72
|
+
font-family: 'JoysIranSansXFaNum';
|
|
73
|
+
src: url('./woff2/joys-iran-sans-x-fanum-200.woff2') format('woff2');
|
|
74
|
+
font-weight: 200;
|
|
75
|
+
font-style: normal;
|
|
76
|
+
font-display: swap;
|
|
77
|
+
}
|
|
78
|
+
@font-face {
|
|
79
|
+
font-family: 'JoysIranSansXFaNum';
|
|
80
|
+
src: url('./woff2/joys-iran-sans-x-fanum-300.woff2') format('woff2');
|
|
81
|
+
font-weight: 300;
|
|
82
|
+
font-style: normal;
|
|
83
|
+
font-display: swap;
|
|
84
|
+
}
|
|
85
|
+
@font-face {
|
|
86
|
+
font-family: 'JoysIranSansXFaNum';
|
|
87
|
+
src: url('./woff2/joys-iran-sans-x-fanum-400.woff2') format('woff2');
|
|
88
|
+
font-weight: 400;
|
|
89
|
+
font-style: normal;
|
|
90
|
+
font-display: swap;
|
|
91
|
+
}
|
|
92
|
+
@font-face {
|
|
93
|
+
font-family: 'JoysIranSansXFaNum';
|
|
94
|
+
src: url('./woff2/joys-iran-sans-x-fanum-500.woff2') format('woff2');
|
|
95
|
+
font-weight: 500;
|
|
96
|
+
font-style: normal;
|
|
97
|
+
font-display: swap;
|
|
98
|
+
}
|
|
99
|
+
@font-face {
|
|
100
|
+
font-family: 'JoysIranSansXFaNum';
|
|
101
|
+
src: url('./woff2/joys-iran-sans-x-fanum-600.woff2') format('woff2');
|
|
102
|
+
font-weight: 600;
|
|
103
|
+
font-style: normal;
|
|
104
|
+
font-display: swap;
|
|
105
|
+
}
|
|
106
|
+
@font-face {
|
|
107
|
+
font-family: 'JoysIranSansXFaNum';
|
|
108
|
+
src: url('./woff2/joys-iran-sans-x-fanum-700.woff2') format('woff2');
|
|
109
|
+
font-weight: 700;
|
|
110
|
+
font-style: normal;
|
|
111
|
+
font-display: swap;
|
|
112
|
+
}
|
|
113
|
+
@font-face {
|
|
114
|
+
font-family: 'JoysIranSansXFaNum';
|
|
115
|
+
src: url('./woff2/joys-iran-sans-x-fanum-800.woff2') format('woff2');
|
|
116
|
+
font-weight: 800;
|
|
117
|
+
font-style: normal;
|
|
118
|
+
font-display: swap;
|
|
119
|
+
}
|
|
120
|
+
@font-face {
|
|
121
|
+
font-family: 'JoysIranSansXFaNum';
|
|
122
|
+
src: url('./woff2/joys-iran-sans-x-fanum-900.woff2') format('woff2');
|
|
123
|
+
font-weight: 900;
|
|
124
|
+
font-style: normal;
|
|
125
|
+
font-display: swap;
|
|
126
|
+
}
|
|
127
|
+
@font-face {
|
|
128
|
+
font-family: 'JoysIranSansXNoEn';
|
|
129
|
+
src: url('./woff2/joys-iran-sans-x-noen-100.woff2') format('woff2');
|
|
130
|
+
font-weight: 100;
|
|
131
|
+
font-style: normal;
|
|
132
|
+
font-display: swap;
|
|
133
|
+
}
|
|
134
|
+
@font-face {
|
|
135
|
+
font-family: 'JoysIranSansXNoEn';
|
|
136
|
+
src: url('./woff2/joys-iran-sans-x-noen-200.woff2') format('woff2');
|
|
137
|
+
font-weight: 200;
|
|
138
|
+
font-style: normal;
|
|
139
|
+
font-display: swap;
|
|
140
|
+
}
|
|
141
|
+
@font-face {
|
|
142
|
+
font-family: 'JoysIranSansXNoEn';
|
|
143
|
+
src: url('./woff2/joys-iran-sans-x-noen-300.woff2') format('woff2');
|
|
144
|
+
font-weight: 300;
|
|
145
|
+
font-style: normal;
|
|
146
|
+
font-display: swap;
|
|
147
|
+
}
|
|
148
|
+
@font-face {
|
|
149
|
+
font-family: 'JoysIranSansXNoEn';
|
|
150
|
+
src: url('./woff2/joys-iran-sans-x-noen-400.woff2') format('woff2');
|
|
151
|
+
font-weight: 400;
|
|
152
|
+
font-style: normal;
|
|
153
|
+
font-display: swap;
|
|
154
|
+
}
|
|
155
|
+
@font-face {
|
|
156
|
+
font-family: 'JoysIranSansXNoEn';
|
|
157
|
+
src: url('./woff2/joys-iran-sans-x-noen-500.woff2') format('woff2');
|
|
158
|
+
font-weight: 500;
|
|
159
|
+
font-style: normal;
|
|
160
|
+
font-display: swap;
|
|
161
|
+
}
|
|
162
|
+
@font-face {
|
|
163
|
+
font-family: 'JoysIranSansXNoEn';
|
|
164
|
+
src: url('./woff2/joys-iran-sans-x-noen-600.woff2') format('woff2');
|
|
165
|
+
font-weight: 600;
|
|
166
|
+
font-style: normal;
|
|
167
|
+
font-display: swap;
|
|
168
|
+
}
|
|
169
|
+
@font-face {
|
|
170
|
+
font-family: 'JoysIranSansXNoEn';
|
|
171
|
+
src: url('./woff2/joys-iran-sans-x-noen-700.woff2') format('woff2');
|
|
172
|
+
font-weight: 700;
|
|
173
|
+
font-style: normal;
|
|
174
|
+
font-display: swap;
|
|
175
|
+
}
|
|
176
|
+
@font-face {
|
|
177
|
+
font-family: 'JoysIranSansXNoEn';
|
|
178
|
+
src: url('./woff2/joys-iran-sans-x-noen-800.woff2') format('woff2');
|
|
179
|
+
font-weight: 800;
|
|
180
|
+
font-style: normal;
|
|
181
|
+
font-display: swap;
|
|
182
|
+
}
|
|
183
|
+
@font-face {
|
|
184
|
+
font-family: 'JoysIranSansXNoEn';
|
|
185
|
+
src: url('./woff2/joys-iran-sans-x-noen-900.woff2') format('woff2');
|
|
186
|
+
font-weight: 900;
|
|
187
|
+
font-style: normal;
|
|
188
|
+
font-display: swap;
|
|
189
|
+
}
|
|
190
|
+
.font-iran-sans-x {
|
|
191
|
+
font-family: 'JoysIranSansX', sans-serif;
|
|
192
|
+
font-weight: 400;
|
|
193
|
+
}
|
|
194
|
+
.font-iran-sans-x-fanum {
|
|
195
|
+
font-family: 'JoysIranSansXFaNum', sans-serif;
|
|
196
|
+
font-weight: 400;
|
|
197
|
+
}
|
|
198
|
+
.font-iran-sans-x-noen {
|
|
199
|
+
font-family: 'JoysIranSansXNoEn', sans-serif;
|
|
200
|
+
font-weight: 400;
|
|
201
|
+
}
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|