create-landing-app 0.2.7 → 0.3.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/dist/prompts.js +7 -3
- package/dist/scaffold.js +5 -2
- package/package.json +1 -1
- package/templates/nextjs/base/.dockerignore +6 -0
- package/templates/nextjs/base/.editorconfig +15 -0
- package/templates/nextjs/base/.env.example +9 -2
- package/templates/nextjs/base/.husky/pre-push +8 -10
- package/templates/nextjs/base/CLAUDE.md +169 -0
- package/templates/nextjs/base/Dockerfile +3 -9
- package/templates/nextjs/base/Makefile +25 -0
- package/templates/nextjs/base/app/layout.tsx +6 -9
- package/templates/nextjs/base/app/sitemap.ts +15 -0
- package/templates/nextjs/base/commitlint.config.mjs +6 -22
- package/templates/nextjs/base/components/navs/navbar-mobile.tsx +60 -27
- package/templates/nextjs/base/components/navs/navbar.tsx +9 -2
- package/templates/nextjs/base/components/ui/checkbox.tsx +26 -0
- package/templates/nextjs/base/components/ui/input.tsx +21 -0
- package/templates/nextjs/base/components/ui/radio-group.tsx +36 -0
- package/templates/nextjs/base/components/ui/select.tsx +139 -0
- package/templates/nextjs/base/components/ui/sheet.tsx +139 -0
- package/templates/nextjs/base/components/ui/tabs.tsx +53 -0
- package/templates/nextjs/base/components/ui/textarea.tsx +20 -0
- package/templates/nextjs/base/docker-compose.yml +9 -0
- package/templates/nextjs/base/eslint.config.mjs +5 -9
- package/templates/nextjs/base/next.config.ts +4 -0
- package/templates/nextjs/base/package.json +7 -4
- package/templates/nextjs/base/styles/theme.css +2 -0
- package/templates/nextjs/base/tsconfig.json +2 -2
- package/templates/nextjs/optional/analytics/files/components/analytics.tsx +16 -0
- package/templates/nextjs/optional/analytics/files/components/web-vitals.tsx +16 -0
- package/templates/nextjs/optional/analytics/inject/app__layout.tsx +7 -0
- package/templates/nextjs/optional/analytics/pkg.json +5 -0
- package/templates/nextjs/optional/dark-mode/files/components/theme-toggle.tsx +21 -0
- package/templates/nextjs/optional/dark-mode/inject/app__layout.tsx +8 -0
- package/templates/nextjs/optional/dark-mode/pkg.json +5 -0
- package/templates/nextjs/optional/i18n-dict/files/components/navs/navbar-mobile.tsx +60 -26
- package/templates/nextjs/optional/i18n-dict/files/components/navs/navbar.tsx +8 -2
- package/templates/nextjs/optional/i18n-dict/files/{middleware.ts → proxy.ts} +8 -2
- package/templates/nextjs/optional/i18n-dict/inject/app__layout.tsx +34 -0
- package/templates/nextjs/optional/sections/blog/files/app/[lang]/blogs/(list)/[category]/main-page.tsx +15 -0
- package/templates/nextjs/optional/sections/blog/files/app/[lang]/blogs/(list)/[category]/page.tsx +38 -0
- package/templates/nextjs/optional/sections/blog/files/app/[lang]/blogs/(list)/layout.tsx +28 -0
- package/templates/nextjs/optional/sections/blog/files/app/[lang]/blogs/detail/[slugNews]/blog-detail-view.tsx +122 -0
- package/templates/nextjs/optional/sections/blog/files/app/[lang]/blogs/detail/[slugNews]/page.tsx +73 -0
- package/templates/nextjs/optional/sections/blog/files/app/api/blogs/route.ts +14 -0
- package/templates/nextjs/optional/sections/blog/files/components/blogs/blog-component.tsx +58 -0
- package/templates/nextjs/optional/sections/blog/files/components/blogs/blog-view-desktop.tsx +121 -0
- package/templates/nextjs/optional/sections/blog/files/components/blogs/blog-view-mobile.tsx +90 -0
- package/templates/nextjs/optional/sections/blog/files/components/navs/layout-blogs.tsx +51 -0
- package/templates/nextjs/optional/sections/blog/files/components/sections/blog-section-view.tsx +171 -0
- package/templates/nextjs/optional/sections/blog/files/components/sections/blog-section.tsx +13 -174
- package/templates/nextjs/optional/sections/blog/files/hooks/use-mobile.ts +19 -0
- package/templates/nextjs/optional/sections/blog/files/lib/blog-api.ts +336 -0
- package/templates/nextjs/optional/sections/blog/files/lib/sanitize.ts +25 -0
- package/templates/nextjs/optional/sections/blog/files/styles/prose.css +40 -0
- package/templates/nextjs/optional/sections/blog/inject/constants__common.ts +1 -1
- package/templates/nextjs/optional/sections/blog/pkg.json +10 -0
- package/templates/nextjs/optional/sections/contact/files/components/sections/contact-section.tsx +1 -0
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import DOMPurify from "isomorphic-dompurify";
|
|
2
|
+
|
|
3
|
+
// Allowed HTML tags for blog content
|
|
4
|
+
const ALLOWED_TAGS = [
|
|
5
|
+
"p", "br", "strong", "em", "u", "a",
|
|
6
|
+
"h1", "h2", "h3", "h4", "h5", "h6",
|
|
7
|
+
"ul", "ol", "li", "blockquote",
|
|
8
|
+
"img", "pre", "code",
|
|
9
|
+
"table", "thead", "tbody", "tr", "th", "td",
|
|
10
|
+
];
|
|
11
|
+
|
|
12
|
+
// Allowlist of permitted HTML attributes
|
|
13
|
+
const ALLOWED_ATTR = ["href", "title", "target", "rel", "src", "alt", "width", "height", "loading"];
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Sanitize raw HTML from the API before rendering with dangerouslySetInnerHTML.
|
|
17
|
+
* Strips all tags/attributes not on the allowlist.
|
|
18
|
+
*/
|
|
19
|
+
export function sanitizeBlogContent(html: string): string {
|
|
20
|
+
return DOMPurify.sanitize(html, {
|
|
21
|
+
ALLOWED_TAGS,
|
|
22
|
+
ALLOWED_ATTR,
|
|
23
|
+
FORCE_BODY: true,
|
|
24
|
+
});
|
|
25
|
+
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/* Prose styles for rendered blog HTML content */
|
|
2
|
+
|
|
3
|
+
.prose { color: #374151; line-height: 1.75; }
|
|
4
|
+
|
|
5
|
+
.prose h1,
|
|
6
|
+
.prose h2,
|
|
7
|
+
.prose h3,
|
|
8
|
+
.prose h4,
|
|
9
|
+
.prose h5,
|
|
10
|
+
.prose h6 { font-weight: 700; color: #111827; margin-top: 1.5rem; margin-bottom: 1rem; }
|
|
11
|
+
|
|
12
|
+
.prose h1 { font-size: 1.875rem; }
|
|
13
|
+
.prose h2 { font-size: 1.5rem; }
|
|
14
|
+
.prose h3 { font-size: 1.25rem; }
|
|
15
|
+
|
|
16
|
+
.prose p { margin-bottom: 1rem; }
|
|
17
|
+
.prose a { color: #2563eb; text-decoration: underline; }
|
|
18
|
+
.prose img { max-width: 100%; height: auto; border-radius: 0.5rem; margin: 1rem 0; }
|
|
19
|
+
|
|
20
|
+
.prose ul,
|
|
21
|
+
.prose ol { margin: 1rem 0; padding-left: 1.5rem; }
|
|
22
|
+
.prose ul > li { list-style-type: disc; margin-bottom: 0.5rem; }
|
|
23
|
+
.prose ol > li { list-style-type: decimal; margin-bottom: 0.5rem; }
|
|
24
|
+
|
|
25
|
+
.prose blockquote {
|
|
26
|
+
border-left: 4px solid #d1d5db;
|
|
27
|
+
padding: 0.5rem 1rem;
|
|
28
|
+
margin: 1rem 0;
|
|
29
|
+
font-style: italic;
|
|
30
|
+
color: #4b5563;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
.prose code { background: #f3f4f6; padding: 0.125rem 0.375rem; border-radius: 0.25rem; font-size: 0.875rem; font-family: monospace; }
|
|
34
|
+
.prose pre { background: #111827; color: #f9fafb; padding: 1rem; border-radius: 0.5rem; overflow-x: auto; margin-bottom: 1rem; }
|
|
35
|
+
.prose pre code { background: none; padding: 0; }
|
|
36
|
+
|
|
37
|
+
.prose table { width: 100%; border-collapse: collapse; margin: 1rem 0; }
|
|
38
|
+
.prose th,
|
|
39
|
+
.prose td { border: 1px solid #d1d5db; padding: 0.5rem 1rem; }
|
|
40
|
+
.prose th { background: #f3f4f6; font-weight: 700; }
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
MARKER:__NAV_LINK_BLOG__
|
|
2
|
-
{ label: "Blog", href: "
|
|
2
|
+
{ label: "Blog", href: "/blogs/all" },
|