@quicktalog/common 1.0.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.
@@ -0,0 +1,15 @@
1
+ export declare const themes: {
2
+ key: string;
3
+ label: string;
4
+ image: string;
5
+ description: string;
6
+ type: string;
7
+ }[];
8
+ export declare const layouts: {
9
+ key: string;
10
+ label: string;
11
+ image: string;
12
+ description: string;
13
+ }[];
14
+ export declare const DARK_THEMES: string[];
15
+ export declare const DEFAULT_EMAIL = "quicktalog@outlook.com";
@@ -0,0 +1,68 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.DEFAULT_EMAIL = exports.DARK_THEMES = exports.layouts = exports.themes = void 0;
4
+ exports.themes = [
5
+ {
6
+ key: "theme-elegant",
7
+ label: "Elegant",
8
+ image: "/themes/elegant.png",
9
+ description: "A dark, refined theme with a subtle gradient background, light text, and cool blue accents. Ideal for upscale or modern venues seeking a sophisticated, minimal look. Uses serif headings and clean layouts for a premium feel.",
10
+ type: "dark",
11
+ },
12
+ {
13
+ key: "theme-luxury",
14
+ label: "Luxury",
15
+ image: "/themes/luxury.png",
16
+ description: "A light, luxurious theme with gold and cream tones, dark elegant text, and premium accents. Designed for high-end restaurants, it features classic serif headings, gold highlights, and a soft, inviting background.",
17
+ type: "light",
18
+ },
19
+ {
20
+ key: "theme-modern",
21
+ label: "Modern",
22
+ image: "/themes/modern.png",
23
+ description: "A bold, contemporary theme with deep blue backgrounds, white and pink accents, and modern sans-serif typography. Perfect for trendy or urban venues wanting a striking, energetic appearance.",
24
+ type: "dark",
25
+ },
26
+ {
27
+ key: "theme-organic",
28
+ label: "Organic",
29
+ image: "/themes/organic.png",
30
+ description: "A fresh, natural theme with light beige backgrounds, green and brown accents, and soft, rounded typography. Ideal for organic, vegan, or eco-friendly restaurants seeking a wholesome, earthy vibe.",
31
+ type: "light",
32
+ },
33
+ {
34
+ key: "theme-creative",
35
+ label: "Creative",
36
+ image: "/themes/creative.png",
37
+ description: "A vibrant, artistic theme with dark backgrounds, bright accent colors (red, yellow, blue), and playful, bold typography. Great for creative spaces, cafes, or venues wanting a fun, expressive look.",
38
+ type: "dark",
39
+ },
40
+ ];
41
+ exports.layouts = [
42
+ {
43
+ key: "variant_1",
44
+ label: "Side Image",
45
+ image: "/layouts/layout_1v_2.jpg",
46
+ description: "Grid layout: Catalogue items are displayed in a responsive grid (1 column on mobile, 2 on desktop), with images and details shown together. Best for balanced, easy-to-browse catalogues.",
47
+ },
48
+ {
49
+ key: "variant_2",
50
+ label: "Top Image",
51
+ image: "/layouts/layout_2v_2.jpg",
52
+ description: "Horizontal card layout: Catalogue items are arranged in flexible horizontal cards, wrapping as needed. Ideal for showcasing items with wide images or for a modern, card-based look.",
53
+ },
54
+ {
55
+ key: "variant_3",
56
+ label: "Text Only",
57
+ image: "/layouts/layout_3v_2.jpg",
58
+ description: "Alternative grid layout: Similar to Layout 1 but with subtle style differences, such as spacing or card appearance. Useful for catalogues needing a slightly different grid presentation. This layout does not contain image.",
59
+ },
60
+ {
61
+ key: "variant_4",
62
+ label: "Carousel",
63
+ image: "/layouts/layout_4v_2.jpg",
64
+ description: "Carousel layout: Catalogue items are displayed in a horizontal scrollable carousel, allowing users to swipe or scroll through items. Great for featured items or visually rich catalogues.",
65
+ },
66
+ ];
67
+ exports.DARK_THEMES = ["theme-elegant", "theme-modern", "theme-creative"];
68
+ exports.DEFAULT_EMAIL = "quicktalog@outlook.com";
@@ -0,0 +1,2 @@
1
+ export declare function fetchImageFromUnsplash(query: string): Promise<string>;
2
+ export declare const generateUniqueSlug: (name: string) => string;
@@ -0,0 +1,32 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.generateUniqueSlug = void 0;
4
+ exports.fetchImageFromUnsplash = fetchImageFromUnsplash;
5
+ async function fetchImageFromUnsplash(query) {
6
+ try {
7
+ const res = await fetch(`https://api.unsplash.com/search/photos?page=1&per_page=1&query=${encodeURIComponent(query)}`, {
8
+ headers: {
9
+ Authorization: `Client-ID ${process.env.UNSPLASH_API_KEY}`,
10
+ },
11
+ });
12
+ const data = await res.json();
13
+ if (data?.results?.[0]?.urls?.regular) {
14
+ return data.results[0].urls.regular;
15
+ }
16
+ }
17
+ catch (err) {
18
+ console.error(`Failed to fetch image for "${query}":`, err);
19
+ }
20
+ return "https://static1.squarespace.com/static/5898e29c725e25e7132d5a5a/58aa11bc9656ca13c4524c68/58aa11e99656ca13c45253e2/1487540713345/600x400-Image-Placeholder.jpg?format=original";
21
+ }
22
+ const generateUniqueSlug = (name) => {
23
+ const slug = name
24
+ .toLowerCase()
25
+ .trim()
26
+ .replace(/\s+/g, "-")
27
+ .replace(/-+/g, "-")
28
+ .replace(/^-|-$/g, "");
29
+ return slug;
30
+ };
31
+ exports.generateUniqueSlug = generateUniqueSlug;
32
+ // npm publish --access public
@@ -0,0 +1,3 @@
1
+ export * from "./constants";
2
+ export * from "./helpers";
3
+ export * from "./types";
package/dist/index.js ADDED
@@ -0,0 +1,19 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
+ };
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ __exportStar(require("./constants"), exports);
18
+ __exportStar(require("./helpers"), exports);
19
+ __exportStar(require("./types"), exports);
@@ -0,0 +1,156 @@
1
+ import { layouts, themes } from "./constants";
2
+ export type Status = "active" | "inactive" | "draft";
3
+ export type CookiePreferences = {
4
+ accepted: boolean;
5
+ essential: boolean;
6
+ analytics: boolean;
7
+ marketing: boolean;
8
+ timestamp: string;
9
+ version: string;
10
+ };
11
+ export type CategoryItem = {
12
+ name: string;
13
+ description: string;
14
+ price: number;
15
+ image: string;
16
+ };
17
+ export type Theme = {
18
+ key: string;
19
+ label: string;
20
+ image: string;
21
+ description: string;
22
+ };
23
+ export type Layout = Theme;
24
+ export type ThemeVariant = (typeof themes)[number]["key"];
25
+ export type LayoutVariant = (typeof layouts)[number]["key"];
26
+ export type CatalogueCategory = {
27
+ order: number;
28
+ name: string;
29
+ layout: LayoutVariant;
30
+ items: CategoryItem[];
31
+ };
32
+ export type Catalogue = {
33
+ id?: string;
34
+ name: string;
35
+ status: Status;
36
+ created_by?: string;
37
+ theme: ThemeVariant;
38
+ logo?: string;
39
+ title: string;
40
+ currency: string;
41
+ contact?: ContactInfo[];
42
+ subtitle?: string;
43
+ services: CatalogueCategory[];
44
+ partners?: Partner[];
45
+ legal?: Legal;
46
+ configuration?: Configuration;
47
+ created_at?: string;
48
+ updated_at?: string;
49
+ source?: string;
50
+ };
51
+ export type ServicesFormData = Omit<Catalogue, "id" | "created_by" | "">;
52
+ export type Service = {
53
+ name: string;
54
+ image: string;
55
+ price: number | string;
56
+ description: string;
57
+ };
58
+ export type Legal = {
59
+ name?: string;
60
+ address?: string;
61
+ terms_and_conditions?: string;
62
+ privacy_policy?: string;
63
+ };
64
+ export type Partner = {
65
+ name: string;
66
+ logo: string;
67
+ description: string;
68
+ rating: number;
69
+ url?: string;
70
+ };
71
+ export type Configuration = {
72
+ ctaNavbar?: {
73
+ enabled: boolean;
74
+ label: string;
75
+ url: string;
76
+ };
77
+ ctaFooter?: {
78
+ enabled: boolean;
79
+ label: string;
80
+ url: string;
81
+ };
82
+ newsletter?: {
83
+ enabled: boolean;
84
+ };
85
+ };
86
+ export type Analytics = {
87
+ date: string;
88
+ current_url: string;
89
+ pageview_count: number;
90
+ unique_visitors: number;
91
+ };
92
+ export type User = {
93
+ id: string;
94
+ email: string | null;
95
+ name: string | null;
96
+ created_at: string;
97
+ image: string | null;
98
+ cookie_preferences?: CookiePreferences | null;
99
+ plan_id: string | null;
100
+ customer_id: string | null;
101
+ };
102
+ export type OCRImageData = {
103
+ id: string;
104
+ file: File;
105
+ originalUrl: string;
106
+ confidence?: number;
107
+ isProcessed: boolean;
108
+ };
109
+ export type ContactInfo = {
110
+ type: string;
111
+ value: string;
112
+ };
113
+ export type Usage = {
114
+ traffic: {
115
+ pageview_count: number;
116
+ unique_visitors: number;
117
+ };
118
+ ocr: number;
119
+ prompts: number;
120
+ catalogues: number;
121
+ };
122
+ export type UserData = User & {
123
+ usage: Usage;
124
+ currentPlan: PricingPlan;
125
+ nextPlan: PricingPlan;
126
+ };
127
+ export type PricingPlan = {
128
+ id: number;
129
+ name: string;
130
+ type: string;
131
+ priceId: {
132
+ month: string;
133
+ year: string;
134
+ };
135
+ description: string;
136
+ features: {
137
+ support: string;
138
+ catalogues: number;
139
+ newsletter: boolean;
140
+ custom_features: boolean;
141
+ ocr_ai_import: number;
142
+ traffic_limit: number;
143
+ branding: boolean;
144
+ analytics: string;
145
+ ai_prompts: number;
146
+ categories_per_catalogue?: number | "unlimited";
147
+ items_per_catalogue?: number | "unlimited";
148
+ };
149
+ billing_period?: "month" | "year";
150
+ };
151
+ export type ContactData = {
152
+ message: string;
153
+ email: string;
154
+ name: string;
155
+ subject: string;
156
+ };
package/dist/types.js ADDED
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
package/package.json ADDED
@@ -0,0 +1,17 @@
1
+ {
2
+ "name": "@quicktalog/common",
3
+ "version": "1.0.0",
4
+ "main": "dist/index.js",
5
+ "types": "dist/index.d.ts",
6
+ "scripts": {
7
+ "build": "tsc"
8
+ },
9
+ "devDependencies": {
10
+ "typescript": "^5.1.6"
11
+ },
12
+ "dependencies": {
13
+ "@types/glob": "^8.0.0",
14
+ "glob": "^8.1.0",
15
+ "minimatch": "^9.0.2"
16
+ }
17
+ }
@@ -0,0 +1,76 @@
1
+ export const themes = [
2
+ {
3
+ key: "theme-elegant",
4
+ label: "Elegant",
5
+ image: "/themes/elegant.png",
6
+ description:
7
+ "A dark, refined theme with a subtle gradient background, light text, and cool blue accents. Ideal for upscale or modern venues seeking a sophisticated, minimal look. Uses serif headings and clean layouts for a premium feel.",
8
+ type: "dark",
9
+ },
10
+ {
11
+ key: "theme-luxury",
12
+ label: "Luxury",
13
+ image: "/themes/luxury.png",
14
+ description:
15
+ "A light, luxurious theme with gold and cream tones, dark elegant text, and premium accents. Designed for high-end restaurants, it features classic serif headings, gold highlights, and a soft, inviting background.",
16
+ type: "light",
17
+ },
18
+ {
19
+ key: "theme-modern",
20
+ label: "Modern",
21
+ image: "/themes/modern.png",
22
+ description:
23
+ "A bold, contemporary theme with deep blue backgrounds, white and pink accents, and modern sans-serif typography. Perfect for trendy or urban venues wanting a striking, energetic appearance.",
24
+ type: "dark",
25
+ },
26
+ {
27
+ key: "theme-organic",
28
+ label: "Organic",
29
+ image: "/themes/organic.png",
30
+ description:
31
+ "A fresh, natural theme with light beige backgrounds, green and brown accents, and soft, rounded typography. Ideal for organic, vegan, or eco-friendly restaurants seeking a wholesome, earthy vibe.",
32
+ type: "light",
33
+ },
34
+ {
35
+ key: "theme-creative",
36
+ label: "Creative",
37
+ image: "/themes/creative.png",
38
+ description:
39
+ "A vibrant, artistic theme with dark backgrounds, bright accent colors (red, yellow, blue), and playful, bold typography. Great for creative spaces, cafes, or venues wanting a fun, expressive look.",
40
+ type: "dark",
41
+ },
42
+ ];
43
+
44
+ export const layouts = [
45
+ {
46
+ key: "variant_1",
47
+ label: "Side Image",
48
+ image: "/layouts/layout_1v_2.jpg",
49
+ description:
50
+ "Grid layout: Catalogue items are displayed in a responsive grid (1 column on mobile, 2 on desktop), with images and details shown together. Best for balanced, easy-to-browse catalogues.",
51
+ },
52
+ {
53
+ key: "variant_2",
54
+ label: "Top Image",
55
+ image: "/layouts/layout_2v_2.jpg",
56
+ description:
57
+ "Horizontal card layout: Catalogue items are arranged in flexible horizontal cards, wrapping as needed. Ideal for showcasing items with wide images or for a modern, card-based look.",
58
+ },
59
+ {
60
+ key: "variant_3",
61
+ label: "Text Only",
62
+ image: "/layouts/layout_3v_2.jpg",
63
+ description:
64
+ "Alternative grid layout: Similar to Layout 1 but with subtle style differences, such as spacing or card appearance. Useful for catalogues needing a slightly different grid presentation. This layout does not contain image.",
65
+ },
66
+ {
67
+ key: "variant_4",
68
+ label: "Carousel",
69
+ image: "/layouts/layout_4v_2.jpg",
70
+ description:
71
+ "Carousel layout: Catalogue items are displayed in a horizontal scrollable carousel, allowing users to swipe or scroll through items. Great for featured items or visually rich catalogues.",
72
+ },
73
+ ];
74
+
75
+ export const DARK_THEMES = ["theme-elegant", "theme-modern", "theme-creative"];
76
+ export const DEFAULT_EMAIL = "quicktalog@outlook.com";
package/src/helpers.ts ADDED
@@ -0,0 +1,35 @@
1
+ export async function fetchImageFromUnsplash(query: string): Promise<string> {
2
+ try {
3
+ const res = await fetch(
4
+ `https://api.unsplash.com/search/photos?page=1&per_page=1&query=${encodeURIComponent(query)}`,
5
+ {
6
+ headers: {
7
+ Authorization: `Client-ID ${process.env.UNSPLASH_API_KEY}`,
8
+ },
9
+ },
10
+ );
11
+
12
+ const data = await res.json();
13
+
14
+ if (data?.results?.[0]?.urls?.regular) {
15
+ return data.results[0].urls.regular;
16
+ }
17
+ } catch (err) {
18
+ console.error(`Failed to fetch image for "${query}":`, err);
19
+ }
20
+
21
+ return "https://static1.squarespace.com/static/5898e29c725e25e7132d5a5a/58aa11bc9656ca13c4524c68/58aa11e99656ca13c45253e2/1487540713345/600x400-Image-Placeholder.jpg?format=original";
22
+ }
23
+
24
+ export const generateUniqueSlug = (name: string) => {
25
+ const slug = name
26
+ .toLowerCase()
27
+ .trim()
28
+ .replace(/\s+/g, "-")
29
+ .replace(/-+/g, "-")
30
+ .replace(/^-|-$/g, "");
31
+
32
+ return slug;
33
+ };
34
+
35
+ // npm publish --access public
package/src/index.ts ADDED
@@ -0,0 +1,3 @@
1
+ export * from "./constants";
2
+ export * from "./helpers";
3
+ export * from "./types";
package/src/types.ts ADDED
@@ -0,0 +1,173 @@
1
+ import { layouts, themes } from "./constants";
2
+
3
+ export type Status = "active" | "inactive" | "draft";
4
+
5
+ export type CookiePreferences = {
6
+ accepted: boolean;
7
+ essential: boolean;
8
+ analytics: boolean;
9
+ marketing: boolean;
10
+ timestamp: string;
11
+ version: string;
12
+ };
13
+
14
+ export type CategoryItem = {
15
+ name: string;
16
+ description: string;
17
+ price: number;
18
+ image: string;
19
+ };
20
+
21
+ export type Theme = {
22
+ key: string;
23
+ label: string;
24
+ image: string;
25
+ description: string;
26
+ };
27
+
28
+ export type Layout = Theme;
29
+
30
+ export type ThemeVariant = (typeof themes)[number]["key"];
31
+ export type LayoutVariant = (typeof layouts)[number]["key"];
32
+
33
+ export type CatalogueCategory = {
34
+ order: number;
35
+ name: string;
36
+ layout: LayoutVariant;
37
+ items: CategoryItem[];
38
+ };
39
+ export type Catalogue = {
40
+ id?: string;
41
+ name: string;
42
+ status: Status;
43
+ created_by?: string;
44
+ theme: ThemeVariant;
45
+ logo?: string;
46
+ title: string;
47
+ currency: string;
48
+ contact?: ContactInfo[];
49
+ subtitle?: string;
50
+ services: CatalogueCategory[];
51
+ partners?: Partner[];
52
+ legal?: Legal;
53
+ configuration?: Configuration;
54
+ created_at?: string;
55
+ updated_at?: string;
56
+ source?: string;
57
+ };
58
+
59
+ export type ServicesFormData = Omit<Catalogue, "id" | "created_by" | "">;
60
+
61
+ export type Service = {
62
+ name: string;
63
+ image: string;
64
+ price: number | string;
65
+ description: string;
66
+ };
67
+
68
+ export type Legal = {
69
+ name?: string;
70
+ address?: string;
71
+ terms_and_conditions?: string;
72
+ privacy_policy?: string;
73
+ };
74
+
75
+ export type Partner = {
76
+ name: string;
77
+ logo: string;
78
+ description: string;
79
+ rating: number;
80
+ url?: string;
81
+ };
82
+
83
+ export type Configuration = {
84
+ ctaNavbar?: {
85
+ enabled: boolean;
86
+ label: string;
87
+ url: string;
88
+ };
89
+ ctaFooter?: {
90
+ enabled: boolean;
91
+ label: string;
92
+ url: string;
93
+ };
94
+ newsletter?: {
95
+ enabled: boolean;
96
+ };
97
+ };
98
+
99
+ export type Analytics = {
100
+ date: string;
101
+ current_url: string;
102
+ pageview_count: number;
103
+ unique_visitors: number;
104
+ };
105
+
106
+ export type User = {
107
+ id: string;
108
+ email: string | null;
109
+ name: string | null;
110
+ created_at: string;
111
+ image: string | null;
112
+ cookie_preferences?: CookiePreferences | null;
113
+ plan_id: string | null;
114
+ customer_id: string | null;
115
+ };
116
+
117
+ export type OCRImageData = {
118
+ id: string;
119
+ file: File;
120
+ originalUrl: string;
121
+ confidence?: number;
122
+ isProcessed: boolean;
123
+ };
124
+
125
+ export type ContactInfo = {
126
+ type: string;
127
+ value: string;
128
+ };
129
+
130
+ export type Usage = {
131
+ traffic: { pageview_count: number; unique_visitors: number };
132
+ ocr: number;
133
+ prompts: number;
134
+ catalogues: number;
135
+ };
136
+
137
+ export type UserData = User & {
138
+ usage: Usage;
139
+ currentPlan: PricingPlan;
140
+ nextPlan: PricingPlan;
141
+ };
142
+
143
+ export type PricingPlan = {
144
+ id: number;
145
+ name: string;
146
+ type: string;
147
+ priceId: {
148
+ month: string;
149
+ year: string;
150
+ };
151
+ description: string;
152
+ features: {
153
+ support: string;
154
+ catalogues: number;
155
+ newsletter: boolean;
156
+ custom_features: boolean;
157
+ ocr_ai_import: number;
158
+ traffic_limit: number;
159
+ branding: boolean;
160
+ analytics: string;
161
+ ai_prompts: number;
162
+ categories_per_catalogue?: number | "unlimited";
163
+ items_per_catalogue?: number | "unlimited";
164
+ };
165
+ billing_period?: "month" | "year";
166
+ };
167
+
168
+ export type ContactData = {
169
+ message: string;
170
+ email: string;
171
+ name: string;
172
+ subject: string;
173
+ };
package/tsconfig.json ADDED
@@ -0,0 +1,13 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ES2020",
4
+ "module": "commonjs",
5
+ "declaration": true,
6
+ "outDir": "dist",
7
+ "strict": true,
8
+ "esModuleInterop": true,
9
+ "skipLibCheck": true
10
+ },
11
+ "include": ["src"],
12
+ "exclude": ["dist"]
13
+ }