ntc-dev-kit 1.0.0__py3-none-any.whl
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.
- ntc/__init__.py +5 -0
- ntc/app_creator.py +296 -0
- ntc/cli.py +4 -0
- ntc/cli_enhanced.py +820 -0
- ntc/composer/__init__.py +0 -0
- ntc/composer/main.py +443 -0
- ntc/deployment/__init__.py +0 -0
- ntc/templates/__init__.py +2 -0
- ntc/templates/auth_app/__init__.py +0 -0
- ntc/templates/auth_app/admin.py +24 -0
- ntc/templates/auth_app/apps.py +6 -0
- ntc/templates/auth_app/models.py +30 -0
- ntc/templates/auth_app/serializers.py +101 -0
- ntc/templates/auth_app/urls.py +19 -0
- ntc/templates/auth_app/views.py +175 -0
- ntc/templates/drf_structure/__init__.py +1 -0
- ntc/templates/drf_structure/drf_structure.md +83 -0
- ntc/templates/drf_structure/main.py +389 -0
- ntc/templates/drf_structure/structure.json +126 -0
- ntc/templates/drf_structure/templates/.entry/start_core_backend.sh +37 -0
- ntc/templates/drf_structure/templates/.entry/start_tasks_backend.sh +30 -0
- ntc/templates/drf_structure/templates/CLAUDE.md +194 -0
- ntc/templates/drf_structure/templates/README.md +117 -0
- ntc/templates/drf_structure/templates/apps/app_admin.py +3 -0
- ntc/templates/drf_structure/templates/apps/app_apps.py +6 -0
- ntc/templates/drf_structure/templates/apps/app_models.py +4 -0
- ntc/templates/drf_structure/templates/apps/app_urls.py +8 -0
- ntc/templates/drf_structure/templates/apps/app_views.py +6 -0
- ntc/templates/drf_structure/templates/apps/common_apps.py +6 -0
- ntc/templates/drf_structure/templates/apps/common_models.py +8 -0
- ntc/templates/drf_structure/templates/config/gunicorn_config.py +9 -0
- ntc/templates/drf_structure/templates/config/http.conf +33 -0
- ntc/templates/drf_structure/templates/core/base_model.py +9 -0
- ntc/templates/drf_structure/templates/core/formatter.py +5 -0
- ntc/templates/drf_structure/templates/core/logger.py +8 -0
- ntc/templates/drf_structure/templates/core/pagination.py +6 -0
- ntc/templates/drf_structure/templates/core/response_wrapper.py +7 -0
- ntc/templates/drf_structure/templates/core/services/azure/email/backend.py +108 -0
- ntc/templates/drf_structure/templates/core/services/azure/email/client.py +296 -0
- ntc/templates/drf_structure/templates/core/services/azure/email/notifier.py +102 -0
- ntc/templates/drf_structure/templates/core/services/object_storage.py +285 -0
- ntc/templates/drf_structure/templates/django_project/asgi.py +5 -0
- ntc/templates/drf_structure/templates/django_project/celery.py +8 -0
- ntc/templates/drf_structure/templates/django_project/dev_settings.py +2 -0
- ntc/templates/drf_structure/templates/django_project/django_settings.txt +322 -0
- ntc/templates/drf_structure/templates/django_project/management_command.py +114 -0
- ntc/templates/drf_structure/templates/django_project/prod_settings.py +3 -0
- ntc/templates/drf_structure/templates/django_project/schema.py +7 -0
- ntc/templates/drf_structure/templates/django_project/urls.py +6 -0
- ntc/templates/drf_structure/templates/django_project/wsgi.py +5 -0
- ntc/templates/drf_structure/templates/docker/docker-compose.yml +11 -0
- ntc/templates/drf_structure/templates/knowledge/knowledge_description.md +201 -0
- ntc/templates/drf_structure/templates/knowledge/knowledge_design_pattern.md +722 -0
- ntc/templates/drf_structure/templates/knowledge/knowledge_structure.md +151 -0
- ntc/templates/drf_structure/templates/root/README.md +307 -0
- ntc/templates/drf_structure/templates/root/django_env.txt +98 -0
- ntc/templates/drf_structure/templates/root/django_requirements.txt +24 -0
- ntc/templates/drf_structure/templates/root/gitignore.txt +6 -0
- ntc/templates/drf_structure/templates/root/manage.py +11 -0
- ntc/templates/flutter/.gitignore +44 -0
- ntc/templates/flutter/.knowledge/knowledge_description.md +215 -0
- ntc/templates/flutter/.knowledge/knowledge_design_pattern.md +310 -0
- ntc/templates/flutter/.knowledge/knowledge_structure.md +83 -0
- ntc/templates/flutter/CLAUDE.md +190 -0
- ntc/templates/flutter/__init__.py +0 -0
- ntc/templates/flutter/analysis_options.yaml +9 -0
- ntc/templates/flutter/main.py +187 -0
- ntc/templates/flutter/pubspec.yaml +65 -0
- ntc/templates/flutter/structure.json +51 -0
- ntc/templates/nextjs/.env.example +10 -0
- ntc/templates/nextjs/.gitignore +36 -0
- ntc/templates/nextjs/CLAUDE.md +181 -0
- ntc/templates/nextjs/README.md +94 -0
- ntc/templates/nextjs/__init__.py +0 -0
- ntc/templates/nextjs/knowledge/knowledge_description.md +208 -0
- ntc/templates/nextjs/knowledge/knowledge_design_pattern.md +460 -0
- ntc/templates/nextjs/knowledge/knowledge_structure.md +75 -0
- ntc/templates/nextjs/main.py +224 -0
- ntc/templates/nextjs/package.json +25 -0
- ntc/templates/nextjs/src/app/globals.css +26 -0
- ntc/templates/nextjs/src/app/layout.tsx +59 -0
- ntc/templates/nextjs/src/app/page.tsx +21 -0
- ntc/templates/nextjs/src/components/Header.tsx +16 -0
- ntc/templates/nextjs/src/services/api.ts +81 -0
- ntc/templates/nextjs/src/utils/constants.ts +1 -0
- ntc/templates/nextjs/structure.json +32 -0
- ntc/templates/nextjs/tsconfig.json +27 -0
- ntc/templates/react_admin/.env.example +1 -0
- ntc/templates/react_admin/.gitignore +10 -0
- ntc/templates/react_admin/CLAUDE.md +210 -0
- ntc/templates/react_admin/README.md +72 -0
- ntc/templates/react_admin/__init__.py +0 -0
- ntc/templates/react_admin/index.html +13 -0
- ntc/templates/react_admin/knowledge/knowledge_description.md +202 -0
- ntc/templates/react_admin/knowledge/knowledge_design_pattern.md +448 -0
- ntc/templates/react_admin/knowledge/knowledge_structure.md +97 -0
- ntc/templates/react_admin/main.py +208 -0
- ntc/templates/react_admin/package.json +35 -0
- ntc/templates/react_admin/src/App.tsx +60 -0
- ntc/templates/react_admin/src/components/ProtectedRoute.tsx +16 -0
- ntc/templates/react_admin/src/components/Sidebar.tsx +90 -0
- ntc/templates/react_admin/src/components/TopNav.tsx +44 -0
- ntc/templates/react_admin/src/context/AuthContext.tsx +107 -0
- ntc/templates/react_admin/src/context/ThemeContext.tsx +34 -0
- ntc/templates/react_admin/src/context/WorkspaceContext.tsx +28 -0
- ntc/templates/react_admin/src/hooks/useApi.ts +39 -0
- ntc/templates/react_admin/src/index.css +34 -0
- ntc/templates/react_admin/src/layouts/AuthLayout.tsx +23 -0
- ntc/templates/react_admin/src/layouts/DashboardLayout.tsx +24 -0
- ntc/templates/react_admin/src/main.tsx +5 -0
- ntc/templates/react_admin/src/pages/DashboardPage.tsx +10 -0
- ntc/templates/react_admin/src/pages/auth/LoginPage.tsx +79 -0
- ntc/templates/react_admin/src/pages/auth/RegisterPage.tsx +93 -0
- ntc/templates/react_admin/src/services/api.service.ts +44 -0
- ntc/templates/react_admin/src/services/base.service.ts +193 -0
- ntc/templates/react_admin/structure.json +52 -0
- ntc/templates/react_admin/tsconfig.app.json +25 -0
- ntc/templates/react_admin/tsconfig.json +7 -0
- ntc/templates/react_admin/tsconfig.node.json +19 -0
- ntc/templates/react_admin/vite.config.ts +13 -0
- ntc/templates/react_structure/CLAUDE.md +176 -0
- ntc/templates/react_structure/__init__.py +1 -0
- ntc/templates/react_structure/index.css +21 -0
- ntc/templates/react_structure/index.html +13 -0
- ntc/templates/react_structure/knowledge/knowledge_description.md +170 -0
- ntc/templates/react_structure/knowledge/knowledge_design_pattern.md +411 -0
- ntc/templates/react_structure/knowledge/knowledge_structure.md +74 -0
- ntc/templates/react_structure/main.py +217 -0
- ntc/templates/react_structure/package.json +32 -0
- ntc/templates/react_structure/src/App.tsx +63 -0
- ntc/templates/react_structure/src/components/Header.tsx +51 -0
- ntc/templates/react_structure/src/main.tsx +5 -0
- ntc/templates/react_structure/src/services/api.ts +90 -0
- ntc/templates/react_structure/src/utils/constants.ts +1 -0
- ntc/templates/react_structure/structure.json +65 -0
- ntc/templates/react_structure/tsconfig.app.json +25 -0
- ntc/templates/react_structure/tsconfig.json +7 -0
- ntc/templates/react_structure/tsconfig.node.json +19 -0
- ntc/templates/react_structure/vite.config.ts +12 -0
- ntc/utils/__init__.py +1 -0
- ntc/utils/environment.py +67 -0
- ntc/utils/output.py +41 -0
- ntc_dev_kit-1.0.0.dist-info/METADATA +188 -0
- ntc_dev_kit-1.0.0.dist-info/RECORD +148 -0
- ntc_dev_kit-1.0.0.dist-info/WHEEL +5 -0
- ntc_dev_kit-1.0.0.dist-info/entry_points.txt +2 -0
- ntc_dev_kit-1.0.0.dist-info/licenses/LICENSE +21 -0
- ntc_dev_kit-1.0.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,224 @@
|
|
|
1
|
+
import os
|
|
2
|
+
import subprocess
|
|
3
|
+
import sys
|
|
4
|
+
import json
|
|
5
|
+
import shutil
|
|
6
|
+
from colorama import Fore, Style
|
|
7
|
+
from ntc.utils.output import print_success, print_error, print_warning, print_info, print_progress, print_package, print_download
|
|
8
|
+
|
|
9
|
+
def replace_variables(content, variables):
|
|
10
|
+
"""Replace placeholders with actual variables."""
|
|
11
|
+
for key, value in variables.items():
|
|
12
|
+
content = content.replace(f"{{{key}}}", value)
|
|
13
|
+
return content
|
|
14
|
+
|
|
15
|
+
def get_template_content(template_name, variables):
|
|
16
|
+
"""Load template content and replace variables."""
|
|
17
|
+
# Remove 'nextjs/' prefix if present since we're already in that directory
|
|
18
|
+
if template_name.startswith("nextjs/"):
|
|
19
|
+
template_name = template_name[len("nextjs/"):]
|
|
20
|
+
|
|
21
|
+
template_path = os.path.join(os.path.dirname(__file__), template_name)
|
|
22
|
+
if not os.path.exists(template_path):
|
|
23
|
+
return ""
|
|
24
|
+
with open(template_path, "r", encoding="utf-8") as f:
|
|
25
|
+
content = f.read()
|
|
26
|
+
return replace_variables(content, variables)
|
|
27
|
+
|
|
28
|
+
def create_from_json(base_path, structure, variables):
|
|
29
|
+
"""Recursively create directories and files from JSON."""
|
|
30
|
+
for name, content in structure.items():
|
|
31
|
+
name = replace_variables(name, variables)
|
|
32
|
+
full_path = os.path.join(base_path, name)
|
|
33
|
+
|
|
34
|
+
if isinstance(content, dict):
|
|
35
|
+
if "template" in content:
|
|
36
|
+
os.makedirs(os.path.dirname(full_path), exist_ok=True)
|
|
37
|
+
with open(full_path, "w", encoding="utf-8") as f:
|
|
38
|
+
f.write(get_template_content(content["template"], variables))
|
|
39
|
+
else:
|
|
40
|
+
os.makedirs(full_path, exist_ok=True)
|
|
41
|
+
create_from_json(full_path, content, variables)
|
|
42
|
+
else:
|
|
43
|
+
os.makedirs(os.path.dirname(full_path), exist_ok=True)
|
|
44
|
+
with open(full_path, "w", encoding="utf-8") as f:
|
|
45
|
+
f.write(replace_variables(content or "", variables))
|
|
46
|
+
|
|
47
|
+
def install_npm_dependencies(project_root):
|
|
48
|
+
"""Install npm dependencies for Next.js project."""
|
|
49
|
+
print_package("Installing npm dependencies...")
|
|
50
|
+
|
|
51
|
+
# Check if npm is available
|
|
52
|
+
if not shutil.which("npm"):
|
|
53
|
+
print_error("npm not found. Please install Node.js and npm first.")
|
|
54
|
+
print_info("Visit https://nodejs.org/ to download Node.js")
|
|
55
|
+
return False
|
|
56
|
+
|
|
57
|
+
try:
|
|
58
|
+
# Change to project directory and install dependencies
|
|
59
|
+
result = subprocess.run(
|
|
60
|
+
["npm", "install"],
|
|
61
|
+
cwd=project_root,
|
|
62
|
+
check=True,
|
|
63
|
+
capture_output=True,
|
|
64
|
+
text=True
|
|
65
|
+
)
|
|
66
|
+
print_success("npm dependencies installed successfully!")
|
|
67
|
+
return True
|
|
68
|
+
except subprocess.CalledProcessError as e:
|
|
69
|
+
print_error(f"Failed to install npm dependencies: {e}")
|
|
70
|
+
print_info("You can manually run 'npm install' in the project directory later.")
|
|
71
|
+
return False
|
|
72
|
+
|
|
73
|
+
def init_nextjs_project(base_path, project_name):
|
|
74
|
+
"""Initialize Next.js project structure and setup environment."""
|
|
75
|
+
structure_file = os.path.join(os.path.dirname(__file__), "structure.json")
|
|
76
|
+
|
|
77
|
+
if not os.path.exists(structure_file):
|
|
78
|
+
print_error(f"Structure file not found: {structure_file}")
|
|
79
|
+
return
|
|
80
|
+
|
|
81
|
+
with open(structure_file, "r", encoding="utf-8") as f:
|
|
82
|
+
structure = json.load(f)
|
|
83
|
+
|
|
84
|
+
project_root = os.path.join(base_path, project_name)
|
|
85
|
+
os.makedirs(project_root, exist_ok=True)
|
|
86
|
+
|
|
87
|
+
variables = {
|
|
88
|
+
"project_name": project_name,
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
create_from_json(project_root, structure["{project_name}"], variables)
|
|
92
|
+
print_success(f"Next.js project '{project_name}' initialized at: {project_root}")
|
|
93
|
+
|
|
94
|
+
# Ask user for dependency installation
|
|
95
|
+
print(f"\n{Fore.CYAN}{Style.BRIGHT}📦 NODE.JS DEPENDENCY SETUP{Style.RESET_ALL}")
|
|
96
|
+
print("─" * 40)
|
|
97
|
+
print(f"{Fore.YELLOW}{Style.BRIGHT}[1]{Style.RESET_ALL} {Fore.WHITE}Install dependencies now (npm install){Style.RESET_ALL}")
|
|
98
|
+
print(f"{Fore.YELLOW}{Style.BRIGHT}[2]{Style.RESET_ALL} {Fore.WHITE}Use existing node_modules (if available){Style.RESET_ALL}")
|
|
99
|
+
print(f"{Fore.YELLOW}{Style.BRIGHT}[3]{Style.RESET_ALL} {Fore.WHITE}Skip dependency installation{Style.RESET_ALL}")
|
|
100
|
+
|
|
101
|
+
while True:
|
|
102
|
+
deps_choice = input(f"{Fore.WHITE}{Style.BRIGHT}❓ Select dependency option (1-3): {Style.RESET_ALL}").strip()
|
|
103
|
+
|
|
104
|
+
# Clear screen after selection
|
|
105
|
+
os.system('cls' if os.name == 'nt' else 'clear')
|
|
106
|
+
|
|
107
|
+
if deps_choice == "1":
|
|
108
|
+
# Install dependencies now
|
|
109
|
+
install_npm_dependencies(project_root)
|
|
110
|
+
break
|
|
111
|
+
|
|
112
|
+
elif deps_choice == "2":
|
|
113
|
+
# Check for existing node_modules
|
|
114
|
+
node_modules_path = os.path.join(project_root, "node_modules")
|
|
115
|
+
if os.path.exists(node_modules_path):
|
|
116
|
+
print_success("Found existing node_modules directory!")
|
|
117
|
+
print_info("Using existing dependencies. Run 'npm install' if you need to update them.")
|
|
118
|
+
else:
|
|
119
|
+
print_warning("No existing node_modules found in this location.")
|
|
120
|
+
print_info("You may need to run 'npm install' manually later.")
|
|
121
|
+
break
|
|
122
|
+
|
|
123
|
+
elif deps_choice == "3":
|
|
124
|
+
# Skip installation
|
|
125
|
+
print_info("Skipping dependency installation.")
|
|
126
|
+
print_info("Remember to run 'npm install' before starting development.")
|
|
127
|
+
break
|
|
128
|
+
|
|
129
|
+
else:
|
|
130
|
+
print_error("Invalid choice. Please select 1, 2, or 3.")
|
|
131
|
+
|
|
132
|
+
# Show next steps
|
|
133
|
+
print(f"\n{Fore.GREEN}{Style.BRIGHT}🎉 PROJECT READY!{Style.RESET_ALL}")
|
|
134
|
+
print("─" * 30)
|
|
135
|
+
print_info("Next steps:")
|
|
136
|
+
print(f" 1. cd {project_name}")
|
|
137
|
+
if deps_choice != "1":
|
|
138
|
+
print(" 2. npm install")
|
|
139
|
+
print(" 3. npm run dev")
|
|
140
|
+
else:
|
|
141
|
+
print(" 2. npm run dev")
|
|
142
|
+
print_info("Your Next.js app will be available at http://localhost:3000")
|
|
143
|
+
print_info("Make sure your backend API is running on http://localhost:8000")
|
|
144
|
+
|
|
145
|
+
def init_nextjs_project_in_current_dir(project_name):
|
|
146
|
+
"""Initialize Next.js project structure in the current directory."""
|
|
147
|
+
structure_file = os.path.join(os.path.dirname(__file__), "structure.json")
|
|
148
|
+
|
|
149
|
+
if not os.path.exists(structure_file):
|
|
150
|
+
print_error(f"Structure file not found: {structure_file}")
|
|
151
|
+
return
|
|
152
|
+
|
|
153
|
+
with open(structure_file, "r", encoding="utf-8") as f:
|
|
154
|
+
structure = json.load(f)
|
|
155
|
+
|
|
156
|
+
project_root = os.getcwd() # Use current directory
|
|
157
|
+
|
|
158
|
+
variables = {
|
|
159
|
+
"project_name": project_name,
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
# Check if current directory is empty or ask for confirmation
|
|
163
|
+
existing_files = [f for f in os.listdir(project_root) if not f.startswith('.')]
|
|
164
|
+
if existing_files:
|
|
165
|
+
print_warning(f"Current directory is not empty. Found {len(existing_files)} files/folders.")
|
|
166
|
+
print_info("Existing items: " + ", ".join(existing_files[:5]) + ("..." if len(existing_files) > 5 else ""))
|
|
167
|
+
|
|
168
|
+
confirm = input(f"{Fore.WHITE}{Style.BRIGHT}❓ Continue anyway? (y/N): {Style.RESET_ALL}").strip().lower()
|
|
169
|
+
if confirm != 'y':
|
|
170
|
+
print_info("Project initialization cancelled.")
|
|
171
|
+
return
|
|
172
|
+
|
|
173
|
+
create_from_json(project_root, structure["{project_name}"], variables)
|
|
174
|
+
print_success(f"Next.js project '{project_name}' initialized in current directory: {project_root}")
|
|
175
|
+
|
|
176
|
+
# Ask user for dependency installation
|
|
177
|
+
print(f"\n{Fore.CYAN}{Style.BRIGHT}📦 NODE.JS DEPENDENCY SETUP{Style.RESET_ALL}")
|
|
178
|
+
print("─" * 40)
|
|
179
|
+
print(f"{Fore.YELLOW}{Style.BRIGHT}[1]{Style.RESET_ALL} {Fore.WHITE}Install dependencies now (npm install){Style.RESET_ALL}")
|
|
180
|
+
print(f"{Fore.YELLOW}{Style.BRIGHT}[2]{Style.RESET_ALL} {Fore.WHITE}Use existing node_modules (if available){Style.RESET_ALL}")
|
|
181
|
+
print(f"{Fore.YELLOW}{Style.BRIGHT}[3]{Style.RESET_ALL} {Fore.WHITE}Skip dependency installation{Style.RESET_ALL}")
|
|
182
|
+
|
|
183
|
+
while True:
|
|
184
|
+
deps_choice = input(f"{Fore.WHITE}{Style.BRIGHT}❓ Select dependency option (1-3): {Style.RESET_ALL}").strip()
|
|
185
|
+
|
|
186
|
+
# Clear screen after selection
|
|
187
|
+
os.system('cls' if os.name == 'nt' else 'clear')
|
|
188
|
+
|
|
189
|
+
if deps_choice == "1":
|
|
190
|
+
# Install dependencies now
|
|
191
|
+
install_npm_dependencies(project_root)
|
|
192
|
+
break
|
|
193
|
+
|
|
194
|
+
elif deps_choice == "2":
|
|
195
|
+
# Check for existing node_modules
|
|
196
|
+
node_modules_path = os.path.join(project_root, "node_modules")
|
|
197
|
+
if os.path.exists(node_modules_path):
|
|
198
|
+
print_success("Found existing node_modules directory!")
|
|
199
|
+
print_info("Using existing dependencies. Run 'npm install' if you need to update them.")
|
|
200
|
+
else:
|
|
201
|
+
print_warning("No existing node_modules found in this location.")
|
|
202
|
+
print_info("You may need to run 'npm install' manually later.")
|
|
203
|
+
break
|
|
204
|
+
|
|
205
|
+
elif deps_choice == "3":
|
|
206
|
+
# Skip installation
|
|
207
|
+
print_info("Skipping dependency installation.")
|
|
208
|
+
print_info("Remember to run 'npm install' before starting development.")
|
|
209
|
+
break
|
|
210
|
+
|
|
211
|
+
else:
|
|
212
|
+
print_error("Invalid choice. Please select 1, 2, or 3.")
|
|
213
|
+
|
|
214
|
+
# Show next steps
|
|
215
|
+
print(f"\n{Fore.GREEN}{Style.BRIGHT}🎉 PROJECT READY!{Style.RESET_ALL}")
|
|
216
|
+
print("─" * 30)
|
|
217
|
+
print_info("Next steps:")
|
|
218
|
+
if deps_choice != "1":
|
|
219
|
+
print(" 1. npm install")
|
|
220
|
+
print(" 2. npm run dev")
|
|
221
|
+
else:
|
|
222
|
+
print(" 1. npm run dev")
|
|
223
|
+
print_info("Your Next.js app will be available at http://localhost:3000")
|
|
224
|
+
print_info("Make sure your backend API is running on http://localhost:8000")
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "{project_name}",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"private": true,
|
|
5
|
+
"scripts": {
|
|
6
|
+
"dev": "next dev",
|
|
7
|
+
"build": "next build",
|
|
8
|
+
"start": "next start",
|
|
9
|
+
"lint": "next lint"
|
|
10
|
+
},
|
|
11
|
+
"dependencies": {
|
|
12
|
+
"next": "^15.0.0",
|
|
13
|
+
"react": "^19.2.4",
|
|
14
|
+
"react-dom": "^19.2.4",
|
|
15
|
+
"axios": "^1.13.6"
|
|
16
|
+
},
|
|
17
|
+
"devDependencies": {
|
|
18
|
+
"@types/node": "^24.12.0",
|
|
19
|
+
"@types/react": "^19.2.14",
|
|
20
|
+
"@types/react-dom": "^19.2.3",
|
|
21
|
+
"typescript": "~5.9.3",
|
|
22
|
+
"eslint": "^9.39.4",
|
|
23
|
+
"eslint-config-next": "^15.0.0"
|
|
24
|
+
}
|
|
25
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
* {
|
|
2
|
+
box-sizing: border-box;
|
|
3
|
+
padding: 0;
|
|
4
|
+
margin: 0;
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
html,
|
|
8
|
+
body {
|
|
9
|
+
max-width: 100vw;
|
|
10
|
+
overflow-x: hidden;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
body {
|
|
14
|
+
background: #ffffff;
|
|
15
|
+
color: #000000;
|
|
16
|
+
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen',
|
|
17
|
+
'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue',
|
|
18
|
+
sans-serif;
|
|
19
|
+
-webkit-font-smoothing: antialiased;
|
|
20
|
+
-moz-osx-font-smoothing: grayscale;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
a {
|
|
24
|
+
color: inherit;
|
|
25
|
+
text-decoration: none;
|
|
26
|
+
}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import type { Metadata } from 'next'
|
|
2
|
+
import { Inter } from 'next/font/google'
|
|
3
|
+
import './globals.css'
|
|
4
|
+
|
|
5
|
+
const inter = Inter({ subsets: ['latin'] })
|
|
6
|
+
|
|
7
|
+
export const metadata: Metadata = {
|
|
8
|
+
title: '{project_name}',
|
|
9
|
+
description: process.env.NEXT_PUBLIC_SITE_DESCRIPTION || 'A modern website built with Next.js',
|
|
10
|
+
keywords: process.env.NEXT_PUBLIC_SITE_KEYWORDS?.split(',') || ['nextjs', 'react', 'typescript'],
|
|
11
|
+
authors: [{ name: '{project_name}' }],
|
|
12
|
+
creator: '{project_name}',
|
|
13
|
+
publisher: '{project_name}',
|
|
14
|
+
metadataBase: new URL(process.env.NEXT_PUBLIC_SITE_URL || 'http://localhost:3000'),
|
|
15
|
+
openGraph: {
|
|
16
|
+
type: 'website',
|
|
17
|
+
locale: 'en_US',
|
|
18
|
+
url: process.env.NEXT_PUBLIC_SITE_URL || 'http://localhost:3000',
|
|
19
|
+
title: '{project_name}',
|
|
20
|
+
description: process.env.NEXT_PUBLIC_SITE_DESCRIPTION || 'A modern website built with Next.js',
|
|
21
|
+
siteName: '{project_name}',
|
|
22
|
+
},
|
|
23
|
+
twitter: {
|
|
24
|
+
card: 'summary_large_image',
|
|
25
|
+
title: '{project_name}',
|
|
26
|
+
description: process.env.NEXT_PUBLIC_SITE_DESCRIPTION || 'A modern website built with Next.js',
|
|
27
|
+
},
|
|
28
|
+
robots: {
|
|
29
|
+
index: true,
|
|
30
|
+
follow: true,
|
|
31
|
+
googleBot: {
|
|
32
|
+
index: true,
|
|
33
|
+
follow: true,
|
|
34
|
+
'max-video-preview': -1,
|
|
35
|
+
'max-image-preview': 'large',
|
|
36
|
+
'max-snippet': -1,
|
|
37
|
+
},
|
|
38
|
+
},
|
|
39
|
+
verification: {
|
|
40
|
+
google: '',
|
|
41
|
+
yandex: '',
|
|
42
|
+
},
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export default function RootLayout({
|
|
46
|
+
children,
|
|
47
|
+
}: {
|
|
48
|
+
children: React.ReactNode
|
|
49
|
+
}) {
|
|
50
|
+
return (
|
|
51
|
+
<html lang="en">
|
|
52
|
+
<head>
|
|
53
|
+
<link rel="icon" href="/favicon.ico" />
|
|
54
|
+
<link rel="canonical" href={process.env.NEXT_PUBLIC_SITE_URL || 'http://localhost:3000'} />
|
|
55
|
+
</head>
|
|
56
|
+
<body className={inter.className}>{children}</body>
|
|
57
|
+
</html>
|
|
58
|
+
)
|
|
59
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { Metadata } from 'next'
|
|
2
|
+
import Header from '@/components/Header'
|
|
3
|
+
|
|
4
|
+
export const metadata: Metadata = {
|
|
5
|
+
title: 'Home - {project_name}',
|
|
6
|
+
description: 'Welcome to {project_name}',
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export default function Home() {
|
|
10
|
+
return (
|
|
11
|
+
<main>
|
|
12
|
+
<Header />
|
|
13
|
+
<section className="hero">
|
|
14
|
+
<div className="container">
|
|
15
|
+
<h1>Welcome to {process.env.NEXT_PUBLIC_SITE_NAME || '{project_name}'}</h1>
|
|
16
|
+
<p>A modern website built with Next.js, React, and TypeScript</p>
|
|
17
|
+
</div>
|
|
18
|
+
</section>
|
|
19
|
+
</main>
|
|
20
|
+
)
|
|
21
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
export default function Header() {
|
|
2
|
+
return (
|
|
3
|
+
<header>
|
|
4
|
+
<nav>
|
|
5
|
+
<div className="container">
|
|
6
|
+
<h1>{process.env.NEXT_PUBLIC_SITE_NAME || '{project_name}'}</h1>
|
|
7
|
+
<ul>
|
|
8
|
+
<li><a href="/">Home</a></li>
|
|
9
|
+
<li><a href="/about">About</a></li>
|
|
10
|
+
<li><a href="/contact">Contact</a></li>
|
|
11
|
+
</ul>
|
|
12
|
+
</div>
|
|
13
|
+
</nav>
|
|
14
|
+
</header>
|
|
15
|
+
)
|
|
16
|
+
}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import axios from 'axios'
|
|
2
|
+
import { API_BASE_URL } from '@/utils/constants'
|
|
3
|
+
|
|
4
|
+
const apiClient = axios.create({
|
|
5
|
+
baseURL: API_BASE_URL,
|
|
6
|
+
timeout: 10000,
|
|
7
|
+
headers: {
|
|
8
|
+
'Content-Type': 'application/json',
|
|
9
|
+
},
|
|
10
|
+
})
|
|
11
|
+
|
|
12
|
+
apiClient.interceptors.request.use(
|
|
13
|
+
(config) => {
|
|
14
|
+
const token = localStorage.getItem('authToken')
|
|
15
|
+
if (token) {
|
|
16
|
+
config.headers.Authorization = `Bearer ${token}`
|
|
17
|
+
}
|
|
18
|
+
return config
|
|
19
|
+
},
|
|
20
|
+
(error) => {
|
|
21
|
+
return Promise.reject(error)
|
|
22
|
+
}
|
|
23
|
+
)
|
|
24
|
+
|
|
25
|
+
apiClient.interceptors.response.use(
|
|
26
|
+
(response) => {
|
|
27
|
+
return response
|
|
28
|
+
},
|
|
29
|
+
(error) => {
|
|
30
|
+
if (error.response?.status === 401) {
|
|
31
|
+
localStorage.removeItem('authToken')
|
|
32
|
+
}
|
|
33
|
+
return Promise.reject(error)
|
|
34
|
+
}
|
|
35
|
+
)
|
|
36
|
+
|
|
37
|
+
export const apiService = {
|
|
38
|
+
get: (url: string, config = {}) => {
|
|
39
|
+
return apiClient.get(url, config)
|
|
40
|
+
},
|
|
41
|
+
|
|
42
|
+
post: (url: string, data = {}, config = {}) => {
|
|
43
|
+
return apiClient.post(url, data, config)
|
|
44
|
+
},
|
|
45
|
+
|
|
46
|
+
put: (url: string, data = {}, config = {}) => {
|
|
47
|
+
return apiClient.put(url, data, config)
|
|
48
|
+
},
|
|
49
|
+
|
|
50
|
+
patch: (url: string, data = {}, config = {}) => {
|
|
51
|
+
return apiClient.patch(url, data, config)
|
|
52
|
+
},
|
|
53
|
+
|
|
54
|
+
delete: (url: string, config = {}) => {
|
|
55
|
+
return apiClient.delete(url, config)
|
|
56
|
+
},
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
export const authService = {
|
|
60
|
+
login: async (credentials: any) => {
|
|
61
|
+
const response = await apiService.post('/auth/login/', credentials)
|
|
62
|
+
if (response.data.token) {
|
|
63
|
+
localStorage.setItem('authToken', response.data.token)
|
|
64
|
+
}
|
|
65
|
+
return response
|
|
66
|
+
},
|
|
67
|
+
|
|
68
|
+
logout: () => {
|
|
69
|
+
localStorage.removeItem('authToken')
|
|
70
|
+
},
|
|
71
|
+
|
|
72
|
+
getCurrentUser: () => {
|
|
73
|
+
return apiService.get('/auth/user/')
|
|
74
|
+
},
|
|
75
|
+
|
|
76
|
+
isAuthenticated: () => {
|
|
77
|
+
return !!localStorage.getItem('authToken')
|
|
78
|
+
},
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
export default apiService
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export const API_BASE_URL = process.env.NEXT_PUBLIC_API_BASE_URL || 'http://localhost:8000'
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
{
|
|
2
|
+
"{project_name}": {
|
|
3
|
+
"package.json": { "template": "nextjs/package.json" },
|
|
4
|
+
".gitignore": "node_modules/\n.next/\n.env.local\n.env.development.local\n.env.test.local\n.env.production.local\nnpm-debug.log*\nyarn-debug.log*\nyarn-error.log*\n.DS_Store\n",
|
|
5
|
+
"README.md": "# {project_name}\n\nA modern Next.js website with SEO best practices, initialized by `ntc init`.\n\n## Tech Stack\n\n- Next.js 15\n- React 19\n- TypeScript\n- Axios for API communication\n\n## Getting Started\n\n```bash\nnpm install\nnpm run dev\n```\n\nOpen [http://localhost:3000](http://localhost:3000) with your browser to see the result.\n\n## Available Scripts\n\n- `npm run dev` - Starts the development server\n- `npm run build` - Creates an optimized production build\n- `npm start` - Starts the production server\n- `npm run lint` - Runs ESLint\n\n## SEO Features\n\nThis template includes comprehensive SEO optimizations:\n\n- **Metadata API**: Next.js Metadata API for dynamic meta tags\n- **Open Graph**: Social media sharing optimization\n- **Twitter Cards**: Twitter card support\n- **Canonical URLs**: Prevent duplicate content issues\n",
|
|
6
|
+
"next.config.js": { "template": "nextjs/next.config.js" },
|
|
7
|
+
"tsconfig.json": { "template": "nextjs/tsconfig.json" },
|
|
8
|
+
".env.example": { "template": "nextjs/.env.example" },
|
|
9
|
+
"CLAUDE.md": { "template": "nextjs/CLAUDE.md" },
|
|
10
|
+
".knowledge": {
|
|
11
|
+
"knowledge_structure.md": { "template": "nextjs/knowledge/knowledge_structure.md" },
|
|
12
|
+
"knowledge_description.md": { "template": "nextjs/knowledge/knowledge_description.md" },
|
|
13
|
+
"knowledge_design_pattern.md": { "template": "nextjs/knowledge/knowledge_design_pattern.md" }
|
|
14
|
+
},
|
|
15
|
+
"src": {
|
|
16
|
+
"app": {
|
|
17
|
+
"layout.tsx": { "template": "nextjs/src/app/layout.tsx" },
|
|
18
|
+
"page.tsx": { "template": "nextjs/src/app/page.tsx" },
|
|
19
|
+
"globals.css": { "template": "nextjs/src/app/globals.css" }
|
|
20
|
+
},
|
|
21
|
+
"components": {
|
|
22
|
+
"Header.tsx": { "template": "nextjs/src/components/Header.tsx" }
|
|
23
|
+
},
|
|
24
|
+
"services": {
|
|
25
|
+
"api.ts": { "template": "nextjs/src/services/api.ts" }
|
|
26
|
+
},
|
|
27
|
+
"utils": {
|
|
28
|
+
"constants.ts": { "template": "nextjs/src/utils/constants.ts" }
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "ES2020",
|
|
4
|
+
"lib": ["dom", "dom.iterable", "esnext"],
|
|
5
|
+
"allowJs": true,
|
|
6
|
+
"skipLibCheck": true,
|
|
7
|
+
"strict": true,
|
|
8
|
+
"noEmit": true,
|
|
9
|
+
"esModuleInterop": true,
|
|
10
|
+
"module": "esnext",
|
|
11
|
+
"moduleResolution": "bundler",
|
|
12
|
+
"resolveJsonModule": true,
|
|
13
|
+
"isolatedModules": true,
|
|
14
|
+
"jsx": "preserve",
|
|
15
|
+
"incremental": true,
|
|
16
|
+
"plugins": [
|
|
17
|
+
{
|
|
18
|
+
"name": "next"
|
|
19
|
+
}
|
|
20
|
+
],
|
|
21
|
+
"paths": {
|
|
22
|
+
"@/*": ["./src/*"]
|
|
23
|
+
}
|
|
24
|
+
},
|
|
25
|
+
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],
|
|
26
|
+
"exclude": ["node_modules"]
|
|
27
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
VITE_API_BASE_URL=http://localhost:8000/v1
|