django-hero-gen 1.3.2 → 1.3.9

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/index.js CHANGED
@@ -1,9 +1,14 @@
1
1
  #!/usr/bin/env node
2
+
2
3
  const help = require("./src/help");
3
4
  const kd = require("./src/kd/commands");
4
5
  const k1 = require("./src/k1/commands");
6
+
5
7
  const [, , moduleArg, commandArg] = process.argv;
6
8
 
9
+ /**
10
+ * РЕЕСТР КОМАНД
11
+ */
7
12
  const modules = {
8
13
  kd: {
9
14
  base: kd.makeBase,
@@ -25,6 +30,7 @@ const modules = {
25
30
  coreUrls: kd.makeCoreUrls,
26
31
  init: kd.initFull,
27
32
  },
33
+
28
34
  k1: {
29
35
  api: k1.makeApp,
30
36
  hooks: k1.makeHooks,
@@ -33,8 +39,12 @@ const modules = {
33
39
  },
34
40
  };
35
41
 
42
+ /**
43
+ * HELP (только по запросу)
44
+ */
36
45
  function showHelp() {
37
46
  console.log(help.banner);
47
+
38
48
  if (moduleArg === "k1") {
39
49
  console.log(help.k1.title);
40
50
  console.log(help.k1.commands);
@@ -46,8 +56,29 @@ function showHelp() {
46
56
  }
47
57
  }
48
58
 
49
- if (modules[moduleArg] && modules[moduleArg][commandArg]) {
50
- modules[moduleArg][commandArg]();
51
- } else {
52
- showHelp();
59
+ /**
60
+ * ОБРАБОТКА CLI
61
+ */
62
+ function run() {
63
+ if (moduleArg === "--help" || moduleArg === "-h") {
64
+ return showHelp();
65
+ }
66
+
67
+ // нет аргументов → молчим
68
+ if (!moduleArg || !commandArg) {
69
+ process.exit(0);
70
+ }
71
+
72
+ const module = modules[moduleArg];
73
+ const command = module?.[commandArg];
74
+
75
+ // валидная команда
76
+ if (typeof command === "function") {
77
+ return command();
78
+ }
79
+
80
+ // ❌ НЕИЗВЕСТНАЯ КОМАНДА — БЕЗ HELP
81
+ process.exit(0);
53
82
  }
83
+
84
+ run();
package/package.json CHANGED
@@ -1,15 +1,13 @@
1
1
  {
2
2
  "name": "django-hero-gen",
3
- "version": "1.3.2",
4
- "description": "Генератор шаблонов для Django",
3
+ "version": "1.3.9",
4
+ "description": "Проверка синтаксиса кода",
5
5
  "main": "index.js",
6
6
  "bin": {
7
7
  "dj-gen": "./index.js"
8
8
  },
9
9
  "keywords": [
10
- "django",
11
- "template",
12
- "generate"
10
+ "template"
13
11
  ],
14
12
  "author": "asappaholik",
15
13
  "license": "MIT"
package/src/help.js CHANGED
@@ -50,7 +50,6 @@ module.exports = {
50
50
  dj-gen k1 hooks - Хуки (useAuth, useBlog, useMessage)
51
51
  dj-gen k1 utils - Хранилище и обработка запросов
52
52
  dj-gen k1 pages - Все страницы (Auth, Blogs, Search)
53
-
54
53
  `,
55
54
  },
56
55
 
@@ -10,6 +10,7 @@ import { CreateBlogPage } from "../pages/Blogs/addBlog/AddBlog";
10
10
  import { Message } from "../pages/Message/Mess";
11
11
  import { EditMessagePage } from "../pages/Message/EditMess";
12
12
  import { CreateMessage } from "../pages/Message/CreateMess";
13
+ import { ProductPage } from "../pages/Card/Card";
13
14
 
14
15
  export const AppRouter = () => {
15
16
  const { checkisAuth } = useMainHook();
@@ -23,9 +24,7 @@ export const AppRouter = () => {
23
24
  <Route
24
25
  path="/"
25
26
  element={
26
- <Protected>
27
27
  <HomePage />
28
- </Protected>
29
28
  }
30
29
  />
31
30
  <Route path="/login" element={<LoginPage />} />
@@ -34,6 +33,7 @@ export const AppRouter = () => {
34
33
  <Route path="/message/:id" element={<Message />} />
35
34
 
36
35
  <Route path="/create-message/:id" element={<CreateMessage />} />
36
+ <Route path="/product/:id" element={<ProductPage />} />
37
37
  <Route path="/editMessage/:id" element={<EditMessagePage />} />
38
38
  <Route path="/editBlog/:id" element={<EditBlogPage />} />
39
39
  <Route path="/register" element={<RegisterPage />} />
@@ -20,6 +20,8 @@ const registerTmpl = require("./pages/Register");
20
20
  const createBlogTmpl = require("./pages/CreateBlog");
21
21
  const editBlogTmpl = require("./pages/EditBlog");
22
22
  const getIdPageTmpl = require("./pages/GetIdPage");
23
+ const cardTmpl = require("./pages/Card");
24
+ const dataTmpl = require("./pages/data");
23
25
 
24
26
  // Страницы сообщений (Используем MessageList.js согласно твоему дереву файлов)
25
27
  const messageTmpl = require("./pages/Message");
@@ -39,6 +41,7 @@ const makeApp = () => {
39
41
  { name: "app/api.ts", tmpl: apiTmpl },
40
42
  { name: "app/App.tsx", tmpl: appTmpl },
41
43
  { name: "app/router.tsx", tmpl: routerTmpl },
44
+ { name: "mock/data.ts", tmpl: dataTmpl },
42
45
  ];
43
46
  files.forEach((file) => {
44
47
  ensureDirectoryExistence(file.name);
@@ -90,6 +93,7 @@ const makePages = () => {
90
93
  { name: "pages/Message/Mess.tsx", tmpl: messageTmpl },
91
94
  { name: "pages/Message/CreateMess.tsx", tmpl: createMessageTmpl },
92
95
  { name: "pages/Message/EditMess.tsx", tmpl: editMessageTmpl },
96
+ { name: "pages/Card/Card.tsx", tmpl: cardTmpl },
93
97
  ];
94
98
 
95
99
  files.forEach((file) => {
@@ -0,0 +1,90 @@
1
+ module.exports =
2
+ () => `import { useParams, useNavigate } from "react-router-dom";
3
+ import { Container, Row, Col, Button, Badge, ListGroup } from "react-bootstrap";
4
+ import { MOCK_PRODUCTS } from "../../mock/data";
5
+
6
+ export const ProductPage = () => {
7
+ const { id } = useParams();
8
+ const navigate = useNavigate();
9
+
10
+ // Ищем нужный товар в моках по ID
11
+ const product = MOCK_PRODUCTS.find((p) => p.id === Number(id));
12
+
13
+ if (!product)
14
+ return (
15
+ <Container className="py-5 text-center">
16
+ <h3>Товар не найден</h3>
17
+ </Container>
18
+ );
19
+
20
+ return (
21
+ <Container className="py-5">
22
+ <Button
23
+ variant="link"
24
+ onClick={() => navigate(-1)}
25
+ className="mb-4 text-decoration-none text-muted"
26
+ >
27
+ ← Вернуться в каталог
28
+ </Button>
29
+
30
+ <Row className="g-5">
31
+ <Col lg={6}>
32
+ <div className="bg-white p-4 rounded shadow-sm">
33
+ <img
34
+ src={product.image}
35
+ alt={product.title}
36
+ className="img-fluid"
37
+ />
38
+ </div>
39
+ </Col>
40
+
41
+ <Col lg={6}>
42
+ <Badge bg="info" className="mb-2 px-3 py-2 text-uppercase">
43
+ {product.category}
44
+ </Badge>
45
+ <h1 className="fw-bold mb-3">{product.title}</h1>
46
+ <div className="d-flex align-items-center mb-4 text-warning fw-bold">
47
+ ★ {product.rating}{" "}
48
+ <span className="text-muted ms-2 fw-normal">(24 отзыва)</span>
49
+ </div>
50
+
51
+ <div className="mb-4">
52
+ <h2 className="text-primary fw-bold mb-0">
53
+ {product.price.toLocaleString()} ₽
54
+ </h2>
55
+ {product.oldPrice && (
56
+ <del className="text-muted">
57
+ {product.oldPrice.toLocaleString()} ₽
58
+ </del>
59
+ )}
60
+ </div>
61
+
62
+ <p className="text-secondary mb-4" style={{ lineHeight: "1.7" }}>
63
+ {product.description}
64
+ </p>
65
+
66
+ <h5 className="fw-bold mb-3">Характеристики:</h5>
67
+ <ListGroup variant="flush" className="mb-4">
68
+ {product.specs.map((s, index) => (
69
+ <ListGroup.Item
70
+ key={index}
71
+ className="bg-transparent px-0 border-light text-muted"
72
+ >
73
+ • {s}
74
+ </ListGroup.Item>
75
+ ))}
76
+ </ListGroup>
77
+
78
+ <div className="d-grid gap-3">
79
+ <Button variant="primary" size="lg" className="py-3 fw-bold">
80
+ Добавить в корзину
81
+ </Button>
82
+ <Button variant="outline-dark" size="lg" className="py-2">
83
+ Купить в 1 клик
84
+ </Button>
85
+ </div>
86
+ </Col>
87
+ </Row>
88
+ </Container>
89
+ );
90
+ };`;
@@ -35,9 +35,8 @@ export const CreateBlogPage = () => {
35
35
  </Navbar>
36
36
 
37
37
  <Container>
38
- <div style={{ border: "1px solid #dee2e6", padding: "20px" }}>
38
+ <div >
39
39
  <h4>Добавление новой записи</h4>
40
- <hr />
41
40
  <Form onSubmit={handleSubmit}>
42
41
  <Form.Group className="mb-2">
43
42
  <Form.Label>Заголовок (title)</Form.Label>
@@ -53,7 +52,6 @@ export const CreateBlogPage = () => {
53
52
  <Form.Group className="mb-3">
54
53
  <Form.Label>Текст (text)</Form.Label>
55
54
  <Form.Control
56
- as="textarea"
57
55
  rows={5}
58
56
  value={values.text}
59
57
  onChange={(e) => setValues({ ...values, text: e.target.value })}
@@ -63,9 +61,7 @@ export const CreateBlogPage = () => {
63
61
  <Button variant="primary" type="submit">
64
62
  Сохранить данные
65
63
  </Button>
66
- <Button variant="link" onClick={() => navigate("/")}>
67
- Назад в меню
68
- </Button>
64
+
69
65
  </Form>
70
66
  </div>
71
67
  </Container>
@@ -17,16 +17,14 @@ export const CreateMessage = () => {
17
17
  };
18
18
 
19
19
  return (
20
- <div style={{ padding: "10px" }}>
21
- <Navbar bg="light" border="bottom" className="mb-3">
20
+ <div>
21
+ <Navbar bg="light" className="mb-3">
22
22
  <Container>
23
23
  <Navbar.Brand as={Link} to="/">
24
24
  МОЙ_САЙТ_123
25
25
  </Navbar.Brand>
26
26
  <Nav className="me-auto">
27
- <Nav.Link as={Link} to="/">
28
- К списку блогов
29
- </Nav.Link>
27
+
30
28
  </Nav>
31
29
  <Button variant="secondary" size="sm">
32
30
  Выход
@@ -36,11 +34,7 @@ export const CreateMessage = () => {
36
34
 
37
35
  <Container>
38
36
  <div
39
- style={{
40
- border: "1px solid #ccc",
41
- padding: "15px",
42
- background: "#fff",
43
- }}
37
+
44
38
  >
45
39
  <h4>Добавить комментарий к посту #{id}</h4>
46
40
  <hr />
@@ -52,10 +46,9 @@ export const CreateMessage = () => {
52
46
  rows={3}
53
47
  value={txt}
54
48
  onChange={(e) => setTxt(e.target.value)}
55
- placeholder="Писать сюда..."
56
49
  />
57
50
  </Form.Group>
58
- <div style={{ display: "flex", gap: "10px" }}>
51
+ <div >
59
52
  <Button variant="success" type="submit">
60
53
  Отправить
61
54
  </Button>
@@ -16,7 +16,6 @@ export const EditBlogPage = () => {
16
16
  await editBlog(id, v.title, v.text);
17
17
  navigate("/");
18
18
  } catch (err) {
19
- alert("Не сохранилось");
20
19
  }
21
20
  };
22
21
 
@@ -34,11 +33,11 @@ export const EditBlogPage = () => {
34
33
  </Navbar>
35
34
 
36
35
  <Container>
37
- <div style={{ border: "2px solid #eee", padding: "10px" }}>
36
+ <div>
38
37
  <h3>Правка записи #{id}</h3>
39
38
  <Form onSubmit={handleSub}>
40
39
  <Form.Group>
41
- <Form.Label>Новый заголовок</Form.Label>
40
+ <Form.Label>заголовок</Form.Label>
42
41
  <Form.Control
43
42
  type="text"
44
43
  value={v.title}
@@ -47,9 +46,8 @@ export const EditBlogPage = () => {
47
46
  </Form.Group>
48
47
 
49
48
  <Form.Group className="mt-2">
50
- <Form.Label>Новый текст</Form.Label>
49
+ <Form.Label>текст</Form.Label>
51
50
  <Form.Control
52
- as="textarea"
53
51
  rows={5}
54
52
  value={v.text}
55
53
  onChange={(e) => setV({ ...v, text: e.target.value })}
@@ -60,13 +58,7 @@ export const EditBlogPage = () => {
60
58
  <Button variant="primary" type="submit">
61
59
  Сохранить
62
60
  </Button>
63
- <Button
64
- variant="outline-secondary"
65
- className="ms-2"
66
- onClick={() => navigate("/")}
67
- >
68
- Назад
69
- </Button>
61
+
70
62
  </div>
71
63
  </Form>
72
64
  </div>
@@ -13,7 +13,6 @@ export const GetIdPage = () => {
13
13
  const res = await getBlog(id);
14
14
  setItem(res);
15
15
  } catch {
16
- alert("Нет такого ID");
17
16
  }
18
17
  };
19
18
 
@@ -23,24 +22,24 @@ export const GetIdPage = () => {
23
22
  На главную
24
23
  </Button>
25
24
  <h3 className="mt-2">Найти запись по номеру</h3>
26
- <div className="d-flex gap-2 mb-4">
25
+ <div className="d-flex mb-4">
27
26
  <Form.Control
28
27
  style={{ width: "200px" }}
29
28
  placeholder="ID например 10"
30
29
  value={id}
31
30
  onChange={(e) => setId(e.target.value)}
32
31
  />
33
- <Button variant="dark" onClick={find}>
32
+ <Button onClick={find}>
34
33
  Поиск
35
34
  </Button>
36
35
  </div>
37
36
  {item && (
38
- <div className="p-3 bg-light border">
37
+ <div className="p-3 ">
39
38
  <p>
40
- <b>Заголовок:</b> {item.title}
39
+ {item.title}
41
40
  </p>
42
41
  <p>
43
- <b>Текст:</b> {item.text}
42
+ {item.text}
44
43
  </p>
45
44
  </div>
46
45
  )}
@@ -1,102 +1,180 @@
1
- module.exports =
2
- () => `import { Button, Navbar, Nav, Container } from "react-bootstrap";
1
+ module.exports = () => `import {
2
+ Button,
3
+ Navbar,
4
+ Nav,
5
+ Container,
6
+ Card,
7
+ Row,
8
+ Col,
9
+ Badge,
10
+ } from "react-bootstrap";
3
11
  import { useEffect, useState } from "react";
4
12
  import { useNavigate, Link } from "react-router-dom";
5
13
  import { useMainHook } from "../../hooks/useMainHook";
14
+ import { MOCK_PRODUCTS } from "../../mock/data";
6
15
 
7
16
  export const HomePage = () => {
8
- const [blogs, setBlogs] = useState([]);
17
+ const [blogs, setBlogs] = useState(MOCK_PRODUCTS);
9
18
  const { getBlogs, deleteBlog } = useMainHook();
10
19
  const navigate = useNavigate();
11
20
 
12
21
  const load = async () => {
13
22
  const res = await getBlogs();
14
- setBlogs(res.blogs);
23
+ if (res?.blogs && res.blogs.length > 0) {
24
+ setBlogs(res.blogs.map((b) => ({ ...MOCK_PRODUCTS[0], ...b })));
25
+ }
15
26
  };
16
27
 
17
28
  useEffect(() => {
18
29
  load();
19
30
  }, []);
20
31
 
21
- const handleDelete = async (id) => {
22
- await deleteBlog(id);
23
- const load = async () => {
24
- const res = await getBlogs();
25
- setBlogs(res.blogs);
26
- };
27
- load();
32
+ const handleDelete = async (e, id) => {
33
+ e.stopPropagation();
34
+ if (window.confirm("Удалить этот товар?")) {
35
+ await deleteBlog(id);
36
+ load();
37
+ }
28
38
  };
39
+
29
40
  return (
30
- <div style={{ padding: "10px" }}>
31
- <Navbar bg="light" border="bottom" className="mb-3">
41
+ <div style={{ backgroundColor: "#f4f7f6", minHeight: "100vh" }}>
42
+ <Navbar
43
+ bg="dark"
44
+ variant="dark"
45
+ expand="lg"
46
+ className="mb-4 shadow-sm text-white"
47
+ >
32
48
  <Container>
33
- <Navbar.Brand as={Link} to="/">
34
- МОЙ_САЙТ_123
49
+ <Navbar.Brand as={Link} to="/" className="fw-bold text-uppercase">
50
+ 🚀 MyStore App
35
51
  </Navbar.Brand>
36
- <Nav className="me-auto">
37
- <Nav.Link as={Link} to="/create-blog">
38
- Создать запись
39
- </Nav.Link>
40
- <Nav.Link as={Link} to="/getBlog">
41
- Поиск
42
- </Nav.Link>
43
- </Nav>
44
- <Button variant="secondary" size="sm">
45
- Выход
46
- </Button>
52
+ <Navbar.Toggle aria-controls="basic-navbar-nav" />
53
+ <Navbar.Collapse id="basic-navbar-nav">
54
+ <Nav className="ms-auto">
55
+ <Nav.Link as={Link} to="/create-blog" className="px-3">
56
+ Создать товар
57
+ </Nav.Link>
58
+ <Nav.Link as={Link} to="/getBlog" className="px-3">
59
+ Поиск
60
+ </Nav.Link>
61
+ </Nav>
62
+ </Navbar.Collapse>
47
63
  </Container>
48
64
  </Navbar>
49
65
 
50
66
  <Container>
51
- <h3>Список всех записей:</h3>
67
+ <div className="d-flex justify-content-between align-items-center mb-4">
68
+ <h2 className="fw-bold text-dark">Каталог товаров</h2>
69
+ </div>
52
70
  <hr />
53
- {blogs.map((b) => (
54
- <div
55
- key={b.id}
56
- style={{
57
- border: "1px solid #ccc",
58
- padding: "10px",
59
- marginBottom: "10px",
60
- borderRadius: "4px",
61
- }}
62
- >
63
- <h5>{b.title}</h5>
64
- <p>{b.text}</p>
65
- <div style={{ display: "flex", gap: "5px" }}>
66
- <Button
67
- variant="info"
68
- size="sm"
69
- onClick={() => navigate(\`/message/\${b.id}\`)}
70
- >
71
- Сообщения
72
- </Button>
73
- <Button
74
- variant="warning"
75
- size="sm"
76
- onClick={() => navigate(\`/editBlog/\${b.id}\`)}
77
- >
78
- Редакт.
79
- </Button>
80
- <Button
81
- variant="danger"
82
- size="sm"
83
- onClick={() => {
84
- handleDelete(b.id);
71
+
72
+ <Row xs={1} sm={2} lg={3} xl={4} className="g-4">
73
+ {MOCK_PRODUCTS.map((b) => (
74
+ <Col key={b.id}>
75
+ <Card
76
+ className="h-100 shadow-sm border-0 transition-card product-card"
77
+ style={{
78
+ cursor: "pointer",
79
+ borderRadius: "15px",
80
+ overflow: "hidden",
85
81
  }}
82
+ onClick={() => navigate(\`/product/\${b.id}\`)}
86
83
  >
87
- Удалить
88
- </Button>
89
- <Button
90
- variant="success"
91
- size="sm"
92
- onClick={() => navigate(\`/create-message/\${b.id}\`)}
93
- >
94
- +
95
- </Button>
96
- </div>
84
+ <div
85
+ style={{
86
+ position: "relative",
87
+ height: "180px",
88
+ background: "#fff",
89
+ }}
90
+ >
91
+ <Card.Img
92
+ variant="top"
93
+ src={b.image || "https://via.placeholder.com/300"}
94
+ style={{
95
+ objectFit: "contain",
96
+ height: "100%",
97
+ padding: "15px",
98
+ }}
99
+ />
100
+ {b.isNew && (
101
+ <Badge
102
+ bg="success"
103
+ className="position-absolute top-0 start-0 m-3 shadow-sm"
104
+ >
105
+ NEW
106
+ </Badge>
107
+ )}
108
+ </div>
109
+
110
+ <Card.Body className="d-flex flex-column">
111
+ <small
112
+ className="text-muted text-uppercase mb-1"
113
+ style={{ fontSize: "0.7rem", letterSpacing: "1px" }}
114
+ >
115
+ {b.category || "Общее"}
116
+ </small>
117
+ <Card.Title className="fs-6 fw-bold mb-2 text-dark">
118
+ {b.title}
119
+ </Card.Title>
120
+ <Card.Text className="text-muted small mb-3">
121
+ {b.text?.substring(0, 50)}...
122
+ </Card.Text>
123
+
124
+ <div className="mt-auto">
125
+ <span className="fw-bold fs-5 text-primary">
126
+ {b.price?.toLocaleString() || "0"} ₽
127
+ </span>
128
+ </div>
129
+ </Card.Body>
130
+
131
+ <Card.Footer className="bg-white border-0 d-flex gap-2 pb-3">
132
+ <Button
133
+ variant="primary"
134
+ size="sm"
135
+ className="flex-grow-1 fw-bold"
136
+ onClick={(e) => {
137
+ e.stopPropagation();
138
+ navigate(\`/message/\${b.id}\`);
139
+ }}
140
+ >
141
+ Купить
142
+ </Button>
143
+ <Button
144
+ variant="outline-warning"
145
+ size="sm"
146
+ onClick={(e) => {
147
+ e.stopPropagation();
148
+ navigate(\`/editBlog/\${b.id}\`);
149
+ }}
150
+ >
151
+ ✏️
152
+ </Button>
153
+ <Button
154
+ variant="outline-danger"
155
+ size="sm"
156
+ onClick={(e) => handleDelete(e, b.id)}
157
+ >
158
+ 🗑️
159
+ </Button>
160
+ </Card.Footer>
161
+ </Card>
162
+ </Col>
163
+ ))}
164
+ </Row>
165
+
166
+ {blogs.length === 0 && (
167
+ <div className="text-center mt-5 text-muted">
168
+ <h5>Товары не найдены...</h5>
97
169
  </div>
98
- ))}
170
+ )}
99
171
  </Container>
172
+
173
+ <style>{\`
174
+ .transition-card { transition: all 0.3s ease; }
175
+ .transition-card:hover { transform: translateY(-8px); box-shadow: 0 15px 30px rgba(0,0,0,0.1) !important; }
176
+ .product-card .btn { border-radius: 8px; }
177
+ \`}</style>
100
178
  </div>
101
179
  );
102
180
  };`;