@veeyaainnovatives/blog-card 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.
package/README.md ADDED
@@ -0,0 +1,115 @@
1
+ # @veeyaainnovatives/blog-card
2
+
3
+ A reusable Blog card component for React applications.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ npm install @veeyaainnovatives/blog-card --save
9
+ ```
10
+
11
+ ## Peer Dependencies
12
+
13
+ This package requires the following peer dependencies:
14
+
15
+ - `react` (^16.8.0 || ^17.0.0 || ^18.0.0)
16
+ - `react-dom` (^16.8.0 || ^17.0.0 || ^18.0.0)
17
+ - `react-bootstrap` (^2.0.0)
18
+ - `react-router-dom` (^6.0.0)
19
+
20
+ ## Usage
21
+
22
+ ```jsx
23
+ import { BlogCard } from '@veeyaainnovatives/blog-card';
24
+ import { Link } from 'react-router-dom';
25
+ import placeholderImage from './path/to/placeholder.png';
26
+
27
+ const blogs = [
28
+ {
29
+ id: 1,
30
+ title: 'Blog Title',
31
+ excerpt: 'Blog excerpt...',
32
+ image: 'https://example.com/image.jpg',
33
+ slug: 'blog-slug',
34
+ category: 'Technology',
35
+ updated_at: '2024-01-01T00:00:00Z',
36
+ author: 'John Doe'
37
+ }
38
+ ];
39
+
40
+ function App() {
41
+ return (
42
+ <BlogCard
43
+ blogs={blogs}
44
+ placeholderImage={placeholderImage}
45
+ />
46
+ );
47
+ }
48
+ ```
49
+
50
+ ## Props
51
+
52
+ | Prop | Type | Default | Description |
53
+ |------|------|---------|-------------|
54
+ | `blogs` | `Array` | **Required** | Array of blog objects |
55
+ | `placeholderImage` | `string` | **Required** | Placeholder image URL for blogs without images |
56
+ | `categoryColors` | `Object` | `{}` | Custom category color mapping |
57
+ | `getTimeAgo` | `Function` | `defaultGetTimeAgo` | Custom function to format time ago |
58
+ | `getCategory` | `Function` | `defaultGetCategory` | Custom function to extract category |
59
+ | `getCategoryColor` | `Function` | `defaultGetCategoryColor` | Custom function to get category color |
60
+ | `LinkComponent` | `Component` | `Link` (react-router-dom) | Custom link component |
61
+ | `className` | `string` | `"g-4"` | Row className |
62
+ | `cardClassName` | `string` | `"blog-card-modern mb-4"` | Card wrapper className |
63
+ | `imageWrapperClassName` | `string` | `"blog-card-image-wrapper"` | Image wrapper className |
64
+ | `imageClassName` | `string` | `"blog-card-img-modern"` | Image className |
65
+ | `categoryTagClassName` | `string` | `"blog-category-tag"` | Category tag className |
66
+ | `contentClassName` | `string` | `"blog-card-content"` | Content wrapper className |
67
+ | `titleClassName` | `string` | `"blog-card-title-modern"` | Title className |
68
+ | `descClassName` | `string` | `"blog-card-desc-modern"` | Description className |
69
+ | `authorClassName` | `string` | `"blog-card-author"` | Author section className |
70
+ | `authorLeftClassName` | `string` | `"blog-author-left"` | Author left section className |
71
+ | `authorAvatarClassName` | `string` | `"blog-author-avatar"` | Author avatar className |
72
+ | `authorInfoClassName` | `string` | `"blog-author-info"` | Author info className |
73
+ | `authorNameClassName` | `string` | `"blog-author-name"` | Author name className |
74
+ | `authorTimeClassName` | `string` | `"blog-author-time"` | Author time className |
75
+ | `arrowLinkClassName` | `string` | `"blog-arrow-link"` | Arrow link className |
76
+ | `colProps` | `Object` | `{ lg: 4, md: 6 }` | Column props for react-bootstrap Col |
77
+
78
+ ## Blog Object Structure
79
+
80
+ Each blog object should have the following structure:
81
+
82
+ ```javascript
83
+ {
84
+ id: Number, // Unique identifier
85
+ title: String, // Blog title
86
+ excerpt: String, // Blog excerpt/description
87
+ image: String, // Blog image URL
88
+ slug: String, // Blog slug for routing
89
+ category: String|Object, // Blog category
90
+ updated_at: String, // ISO date string
91
+ created_at: String, // ISO date string (fallback for timeAgo)
92
+ author: String, // Author name (or writer, user.name, created_by.name)
93
+ }
94
+ ```
95
+
96
+ ## Custom Category Colors
97
+
98
+ You can provide custom category colors:
99
+
100
+ ```jsx
101
+ <BlogCard
102
+ blogs={blogs}
103
+ placeholderImage={placeholderImage}
104
+ categoryColors={{
105
+ 'Technology': '#3B82F6',
106
+ 'Design': '#8B5CF6',
107
+ 'Custom': '#FF0000'
108
+ }}
109
+ />
110
+ ```
111
+
112
+ ## License
113
+
114
+ MIT
115
+
@@ -0,0 +1,235 @@
1
+ import { createElement, useState, useEffect } from 'react';
2
+ import { Row, Col } from 'react-bootstrap';
3
+ import { Link } from 'react-router-dom';
4
+ import { jsx, jsxs } from 'react/jsx-runtime';
5
+
6
+ function _defineProperty(e, r, t) {
7
+ return (r = _toPropertyKey(r)) in e ? Object.defineProperty(e, r, {
8
+ value: t,
9
+ enumerable: true,
10
+ configurable: true,
11
+ writable: true
12
+ }) : e[r] = t, e;
13
+ }
14
+ function ownKeys(e, r) {
15
+ var t = Object.keys(e);
16
+ if (Object.getOwnPropertySymbols) {
17
+ var o = Object.getOwnPropertySymbols(e);
18
+ r && (o = o.filter(function (r) {
19
+ return Object.getOwnPropertyDescriptor(e, r).enumerable;
20
+ })), t.push.apply(t, o);
21
+ }
22
+ return t;
23
+ }
24
+ function _objectSpread2(e) {
25
+ for (var r = 1; r < arguments.length; r++) {
26
+ var t = null != arguments[r] ? arguments[r] : {};
27
+ r % 2 ? ownKeys(Object(t), true).forEach(function (r) {
28
+ _defineProperty(e, r, t[r]);
29
+ }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) {
30
+ Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r));
31
+ });
32
+ }
33
+ return e;
34
+ }
35
+ function _toPrimitive(t, r) {
36
+ if ("object" != typeof t || !t) return t;
37
+ var e = t[Symbol.toPrimitive];
38
+ if (void 0 !== e) {
39
+ var i = e.call(t, r);
40
+ if ("object" != typeof i) return i;
41
+ throw new TypeError("@@toPrimitive must return a primitive value.");
42
+ }
43
+ return ("string" === r ? String : Number)(t);
44
+ }
45
+ function _toPropertyKey(t) {
46
+ var i = _toPrimitive(t, "string");
47
+ return "symbol" == typeof i ? i : i + "";
48
+ }
49
+
50
+ const BlogImage = _ref => {
51
+ let {
52
+ image,
53
+ fallback,
54
+ className
55
+ } = _ref;
56
+ const [imgSrc, setImgSrc] = useState(image || fallback);
57
+ useEffect(() => {
58
+ // If no image provided, use fallback
59
+ if (!image || image.trim() === '') {
60
+ setImgSrc(fallback);
61
+ return;
62
+ }
63
+
64
+ // Preload image to check if it exists
65
+ const img = new Image();
66
+ img.onerror = () => {
67
+ // Image failed to load, use fallback
68
+ setImgSrc(fallback);
69
+ };
70
+ img.onload = () => {
71
+ // Image loaded successfully
72
+ setImgSrc(image);
73
+ };
74
+ img.src = image;
75
+ }, [image, fallback]);
76
+ return /*#__PURE__*/jsx("div", {
77
+ style: {
78
+ backgroundImage: "url(".concat(imgSrc, ")")
79
+ },
80
+ className: className
81
+ });
82
+ };
83
+ const BlogCard = _ref2 => {
84
+ let {
85
+ blogs,
86
+ placeholderImage,
87
+ categoryColors,
88
+ getTimeAgo,
89
+ getCategory,
90
+ getCategoryColor,
91
+ LinkComponent = Link,
92
+ className = "g-4",
93
+ cardClassName = "blog-card-modern mb-4",
94
+ imageWrapperClassName = "blog-card-image-wrapper",
95
+ imageClassName = "blog-card-img-modern",
96
+ categoryTagClassName = "blog-category-tag",
97
+ contentClassName = "blog-card-content",
98
+ titleClassName = "blog-card-title-modern",
99
+ descClassName = "blog-card-desc-modern",
100
+ authorClassName = "blog-card-author",
101
+ authorLeftClassName = "blog-author-left",
102
+ authorAvatarClassName = "blog-author-avatar",
103
+ authorInfoClassName = "blog-author-info",
104
+ authorNameClassName = "blog-author-name",
105
+ authorTimeClassName = "blog-author-time",
106
+ arrowLinkClassName = "blog-arrow-link",
107
+ colProps = {
108
+ lg: 4,
109
+ md: 6
110
+ }
111
+ } = _ref2;
112
+ // Default helper function to get time ago
113
+ const defaultGetTimeAgo = dateString => {
114
+ const date = new Date(dateString);
115
+ const now = new Date();
116
+ const diffInSeconds = Math.floor((now - date) / 1000);
117
+ if (diffInSeconds < 60) return 'Just now';
118
+ if (diffInSeconds < 3600) return "".concat(Math.floor(diffInSeconds / 60), "m ago");
119
+ if (diffInSeconds < 86400) return "".concat(Math.floor(diffInSeconds / 3600), "h ago");
120
+ if (diffInSeconds < 172800) return 'Yesterday';
121
+ if (diffInSeconds < 2592000) return "".concat(Math.floor(diffInSeconds / 86400), "d ago");
122
+ if (diffInSeconds < 31536000) return "".concat(Math.floor(diffInSeconds / 2592000), "mo ago");
123
+ return "".concat(Math.floor(diffInSeconds / 31536000), "y ago");
124
+ };
125
+
126
+ // Default helper function to get category
127
+ const defaultGetCategory = category => {
128
+ if (!category || typeof category === 'string' && category.trim() === '') return 'General';
129
+ // If category is an object with name property
130
+ if (typeof category === 'object' && category.name) {
131
+ return category.name;
132
+ }
133
+ // If category is a string
134
+ return category || 'General';
135
+ };
136
+
137
+ // Default helper function to get category color
138
+ const defaultGetCategoryColor = category => {
139
+ const defaultColors = {
140
+ 'Technology': '#3B82F6',
141
+ 'Food': '#F97316',
142
+ 'Automobile': '#EF4444',
143
+ 'Design': '#8B5CF6',
144
+ 'Architecture': '#10B981',
145
+ 'Interior': '#EC4899',
146
+ 'Construction': '#F59E0B',
147
+ 'BIM': '#06B6D4'
148
+ };
149
+
150
+ // Use custom category colors if provided, otherwise use defaults
151
+ const colors = categoryColors || defaultColors;
152
+ return colors[category] || '#6B7280';
153
+ };
154
+
155
+ // Use provided functions or defaults
156
+ const timeAgoFn = getTimeAgo || defaultGetTimeAgo;
157
+ const categoryFn = getCategory || defaultGetCategory;
158
+ const categoryColorFn = getCategoryColor || defaultGetCategoryColor;
159
+
160
+ // Safety check: ensure blogs is an array
161
+ if (!blogs || !Array.isArray(blogs)) {
162
+ return null;
163
+ }
164
+ return /*#__PURE__*/jsx(Row, {
165
+ className: className,
166
+ children: blogs.map(blogItem => {
167
+ var _blogItem$user, _blogItem$created_by;
168
+ // Use placeholder if image is missing or invalid
169
+ const blogImage = blogItem.image && blogItem.image.trim() !== '' ? blogItem.image : placeholderImage;
170
+ const category = categoryFn(blogItem.category);
171
+ const categoryColor = categoryColorFn(category);
172
+ const timeAgo = timeAgoFn(blogItem.updated_at || blogItem.created_at);
173
+ return /*#__PURE__*/createElement(Col, _objectSpread2(_objectSpread2({}, colProps), {}, {
174
+ key: blogItem.id
175
+ }), /*#__PURE__*/jsxs("div", {
176
+ className: cardClassName,
177
+ children: [/*#__PURE__*/jsx("div", {
178
+ className: imageWrapperClassName,
179
+ children: /*#__PURE__*/jsxs(LinkComponent, {
180
+ to: "/blog-view/".concat(blogItem.slug),
181
+ children: [/*#__PURE__*/jsx(BlogImage, {
182
+ image: blogImage,
183
+ fallback: placeholderImage,
184
+ className: imageClassName
185
+ }), /*#__PURE__*/jsx("div", {
186
+ className: categoryTagClassName,
187
+ style: {
188
+ backgroundColor: categoryColor
189
+ },
190
+ children: category
191
+ })]
192
+ })
193
+ }), /*#__PURE__*/jsxs("div", {
194
+ className: contentClassName,
195
+ children: [/*#__PURE__*/jsx("h2", {
196
+ className: titleClassName,
197
+ children: blogItem.title
198
+ }), /*#__PURE__*/jsx("p", {
199
+ className: descClassName,
200
+ children: blogItem.excerpt
201
+ }), /*#__PURE__*/jsxs("div", {
202
+ className: authorClassName,
203
+ children: [/*#__PURE__*/jsxs("div", {
204
+ className: authorLeftClassName,
205
+ children: [/*#__PURE__*/jsx("div", {
206
+ className: authorAvatarClassName,
207
+ children: /*#__PURE__*/jsx("i", {
208
+ className: "fa-solid fa-user"
209
+ })
210
+ }), /*#__PURE__*/jsxs("div", {
211
+ className: authorInfoClassName,
212
+ children: [/*#__PURE__*/jsx("span", {
213
+ className: authorNameClassName,
214
+ children: blogItem.author || blogItem.writer || ((_blogItem$user = blogItem.user) === null || _blogItem$user === void 0 ? void 0 : _blogItem$user.name) || ((_blogItem$created_by = blogItem.created_by) === null || _blogItem$created_by === void 0 ? void 0 : _blogItem$created_by.name) || 'Admin'
215
+ }), /*#__PURE__*/jsx("span", {
216
+ className: authorTimeClassName,
217
+ children: timeAgo
218
+ })]
219
+ })]
220
+ }), /*#__PURE__*/jsx(LinkComponent, {
221
+ to: "/blog-view/".concat(blogItem.slug),
222
+ className: arrowLinkClassName,
223
+ children: /*#__PURE__*/jsx("i", {
224
+ className: "fa-solid fa-arrow-up-right-from-square"
225
+ })
226
+ })]
227
+ })]
228
+ })]
229
+ }));
230
+ })
231
+ });
232
+ };
233
+
234
+ export { BlogCard };
235
+ //# sourceMappingURL=index.esm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.esm.js","sources":["../src/BlogCard.jsx"],"sourcesContent":["import { useState, useEffect } from 'react';\r\nimport { Col, Row } from 'react-bootstrap';\r\nimport { Link } from 'react-router-dom';\r\n\r\n// Component to handle image loading with fallback\r\nconst BlogImage = ({ image, fallback, className }) => {\r\n const [imgSrc, setImgSrc] = useState(image || fallback);\r\n\r\n useEffect(() => {\r\n // If no image provided, use fallback\r\n if (!image || image.trim() === '') {\r\n setImgSrc(fallback);\r\n return;\r\n }\r\n\r\n // Preload image to check if it exists\r\n const img = new Image();\r\n img.onerror = () => {\r\n // Image failed to load, use fallback\r\n setImgSrc(fallback);\r\n };\r\n img.onload = () => {\r\n // Image loaded successfully\r\n setImgSrc(image);\r\n };\r\n img.src = image;\r\n }, [image, fallback]);\r\n\r\n return (\r\n <div\r\n style={{ backgroundImage: `url(${imgSrc})` }}\r\n className={className}\r\n />\r\n );\r\n};\r\n\r\nconst BlogCard = ({ \r\n blogs,\r\n placeholderImage,\r\n categoryColors,\r\n getTimeAgo,\r\n getCategory,\r\n getCategoryColor,\r\n LinkComponent = Link,\r\n className = \"g-4\",\r\n cardClassName = \"blog-card-modern mb-4\",\r\n imageWrapperClassName = \"blog-card-image-wrapper\",\r\n imageClassName = \"blog-card-img-modern\",\r\n categoryTagClassName = \"blog-category-tag\",\r\n contentClassName = \"blog-card-content\",\r\n titleClassName = \"blog-card-title-modern\",\r\n descClassName = \"blog-card-desc-modern\",\r\n authorClassName = \"blog-card-author\",\r\n authorLeftClassName = \"blog-author-left\",\r\n authorAvatarClassName = \"blog-author-avatar\",\r\n authorInfoClassName = \"blog-author-info\",\r\n authorNameClassName = \"blog-author-name\",\r\n authorTimeClassName = \"blog-author-time\",\r\n arrowLinkClassName = \"blog-arrow-link\",\r\n colProps = { lg: 4, md: 6 }\r\n}) => {\r\n // Default helper function to get time ago\r\n const defaultGetTimeAgo = (dateString) => {\r\n const date = new Date(dateString);\r\n const now = new Date();\r\n const diffInSeconds = Math.floor((now - date) / 1000);\r\n\r\n if (diffInSeconds < 60) return 'Just now';\r\n if (diffInSeconds < 3600) return `${Math.floor(diffInSeconds / 60)}m ago`;\r\n if (diffInSeconds < 86400) return `${Math.floor(diffInSeconds / 3600)}h ago`;\r\n if (diffInSeconds < 172800) return 'Yesterday';\r\n if (diffInSeconds < 2592000) return `${Math.floor(diffInSeconds / 86400)}d ago`;\r\n if (diffInSeconds < 31536000) return `${Math.floor(diffInSeconds / 2592000)}mo ago`;\r\n return `${Math.floor(diffInSeconds / 31536000)}y ago`;\r\n };\r\n\r\n // Default helper function to get category\r\n const defaultGetCategory = (category) => {\r\n if (!category || (typeof category === 'string' && category.trim() === '')) return 'General';\r\n // If category is an object with name property\r\n if (typeof category === 'object' && category.name) {\r\n return category.name;\r\n }\r\n // If category is a string\r\n return category || 'General';\r\n };\r\n\r\n // Default helper function to get category color\r\n const defaultGetCategoryColor = (category) => {\r\n const defaultColors = {\r\n 'Technology': '#3B82F6',\r\n 'Food': '#F97316',\r\n 'Automobile': '#EF4444',\r\n 'Design': '#8B5CF6',\r\n 'Architecture': '#10B981',\r\n 'Interior': '#EC4899',\r\n 'Construction': '#F59E0B',\r\n 'BIM': '#06B6D4',\r\n };\r\n \r\n // Use custom category colors if provided, otherwise use defaults\r\n const colors = categoryColors || defaultColors;\r\n return colors[category] || '#6B7280';\r\n };\r\n\r\n // Use provided functions or defaults\r\n const timeAgoFn = getTimeAgo || defaultGetTimeAgo;\r\n const categoryFn = getCategory || defaultGetCategory;\r\n const categoryColorFn = getCategoryColor || defaultGetCategoryColor;\r\n\r\n // Safety check: ensure blogs is an array\r\n if (!blogs || !Array.isArray(blogs)) {\r\n return null;\r\n }\r\n\r\n return (\r\n <Row className={className}>\r\n {blogs.map((blogItem) => {\r\n // Use placeholder if image is missing or invalid\r\n const blogImage = blogItem.image && blogItem.image.trim() !== ''\r\n ? blogItem.image\r\n : placeholderImage;\r\n\r\n const category = categoryFn(blogItem.category);\r\n const categoryColor = categoryColorFn(category);\r\n const timeAgo = timeAgoFn(blogItem.updated_at || blogItem.created_at);\r\n\r\n return (\r\n <Col {...colProps} key={blogItem.id}>\r\n <div className={cardClassName}>\r\n <div className={imageWrapperClassName}>\r\n <LinkComponent to={`/blog-view/${blogItem.slug}`}>\r\n <BlogImage\r\n image={blogImage}\r\n fallback={placeholderImage}\r\n className={imageClassName}\r\n />\r\n <div \r\n className={categoryTagClassName} \r\n style={{ backgroundColor: categoryColor }}\r\n >\r\n {category}\r\n </div>\r\n </LinkComponent>\r\n </div>\r\n <div className={contentClassName}>\r\n <h2 className={titleClassName}>{blogItem.title}</h2>\r\n <p className={descClassName}>{blogItem.excerpt}</p>\r\n <div className={authorClassName}>\r\n <div className={authorLeftClassName}>\r\n <div className={authorAvatarClassName}>\r\n <i className=\"fa-solid fa-user\"></i>\r\n </div>\r\n <div className={authorInfoClassName}>\r\n <span className={authorNameClassName}>\r\n {blogItem.author || blogItem.writer || blogItem.user?.name || blogItem.created_by?.name || 'Admin'}\r\n </span>\r\n <span className={authorTimeClassName}>{timeAgo}</span>\r\n </div>\r\n </div>\r\n <LinkComponent\r\n to={`/blog-view/${blogItem.slug}`}\r\n className={arrowLinkClassName}\r\n >\r\n <i className=\"fa-solid fa-arrow-up-right-from-square\"></i>\r\n </LinkComponent>\r\n </div>\r\n </div>\r\n </div>\r\n </Col>\r\n );\r\n })}\r\n </Row>\r\n );\r\n};\r\n\r\nexport default BlogCard;\r\n\r\n"],"names":["BlogImage","_ref","image","fallback","className","imgSrc","setImgSrc","useState","useEffect","trim","img","Image","onerror","onload","src","_jsx","style","backgroundImage","concat","BlogCard","_ref2","blogs","placeholderImage","categoryColors","getTimeAgo","getCategory","getCategoryColor","LinkComponent","Link","cardClassName","imageWrapperClassName","imageClassName","categoryTagClassName","contentClassName","titleClassName","descClassName","authorClassName","authorLeftClassName","authorAvatarClassName","authorInfoClassName","authorNameClassName","authorTimeClassName","arrowLinkClassName","colProps","lg","md","defaultGetTimeAgo","dateString","date","Date","now","diffInSeconds","Math","floor","defaultGetCategory","category","name","defaultGetCategoryColor","defaultColors","colors","timeAgoFn","categoryFn","categoryColorFn","Array","isArray","Row","children","map","blogItem","_blogItem$user","_blogItem$created_by","blogImage","categoryColor","timeAgo","updated_at","created_at","_createElement","Col","_objectSpread","key","id","_jsxs","to","slug","backgroundColor","title","excerpt","author","writer","user","created_by"],"mappings":"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"}
package/dist/index.js ADDED
@@ -0,0 +1,237 @@
1
+ 'use strict';
2
+
3
+ var react = require('react');
4
+ var reactBootstrap = require('react-bootstrap');
5
+ var reactRouterDom = require('react-router-dom');
6
+ var jsxRuntime = require('react/jsx-runtime');
7
+
8
+ function _defineProperty(e, r, t) {
9
+ return (r = _toPropertyKey(r)) in e ? Object.defineProperty(e, r, {
10
+ value: t,
11
+ enumerable: true,
12
+ configurable: true,
13
+ writable: true
14
+ }) : e[r] = t, e;
15
+ }
16
+ function ownKeys(e, r) {
17
+ var t = Object.keys(e);
18
+ if (Object.getOwnPropertySymbols) {
19
+ var o = Object.getOwnPropertySymbols(e);
20
+ r && (o = o.filter(function (r) {
21
+ return Object.getOwnPropertyDescriptor(e, r).enumerable;
22
+ })), t.push.apply(t, o);
23
+ }
24
+ return t;
25
+ }
26
+ function _objectSpread2(e) {
27
+ for (var r = 1; r < arguments.length; r++) {
28
+ var t = null != arguments[r] ? arguments[r] : {};
29
+ r % 2 ? ownKeys(Object(t), true).forEach(function (r) {
30
+ _defineProperty(e, r, t[r]);
31
+ }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) {
32
+ Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r));
33
+ });
34
+ }
35
+ return e;
36
+ }
37
+ function _toPrimitive(t, r) {
38
+ if ("object" != typeof t || !t) return t;
39
+ var e = t[Symbol.toPrimitive];
40
+ if (void 0 !== e) {
41
+ var i = e.call(t, r);
42
+ if ("object" != typeof i) return i;
43
+ throw new TypeError("@@toPrimitive must return a primitive value.");
44
+ }
45
+ return ("string" === r ? String : Number)(t);
46
+ }
47
+ function _toPropertyKey(t) {
48
+ var i = _toPrimitive(t, "string");
49
+ return "symbol" == typeof i ? i : i + "";
50
+ }
51
+
52
+ const BlogImage = _ref => {
53
+ let {
54
+ image,
55
+ fallback,
56
+ className
57
+ } = _ref;
58
+ const [imgSrc, setImgSrc] = react.useState(image || fallback);
59
+ react.useEffect(() => {
60
+ // If no image provided, use fallback
61
+ if (!image || image.trim() === '') {
62
+ setImgSrc(fallback);
63
+ return;
64
+ }
65
+
66
+ // Preload image to check if it exists
67
+ const img = new Image();
68
+ img.onerror = () => {
69
+ // Image failed to load, use fallback
70
+ setImgSrc(fallback);
71
+ };
72
+ img.onload = () => {
73
+ // Image loaded successfully
74
+ setImgSrc(image);
75
+ };
76
+ img.src = image;
77
+ }, [image, fallback]);
78
+ return /*#__PURE__*/jsxRuntime.jsx("div", {
79
+ style: {
80
+ backgroundImage: "url(".concat(imgSrc, ")")
81
+ },
82
+ className: className
83
+ });
84
+ };
85
+ const BlogCard = _ref2 => {
86
+ let {
87
+ blogs,
88
+ placeholderImage,
89
+ categoryColors,
90
+ getTimeAgo,
91
+ getCategory,
92
+ getCategoryColor,
93
+ LinkComponent = reactRouterDom.Link,
94
+ className = "g-4",
95
+ cardClassName = "blog-card-modern mb-4",
96
+ imageWrapperClassName = "blog-card-image-wrapper",
97
+ imageClassName = "blog-card-img-modern",
98
+ categoryTagClassName = "blog-category-tag",
99
+ contentClassName = "blog-card-content",
100
+ titleClassName = "blog-card-title-modern",
101
+ descClassName = "blog-card-desc-modern",
102
+ authorClassName = "blog-card-author",
103
+ authorLeftClassName = "blog-author-left",
104
+ authorAvatarClassName = "blog-author-avatar",
105
+ authorInfoClassName = "blog-author-info",
106
+ authorNameClassName = "blog-author-name",
107
+ authorTimeClassName = "blog-author-time",
108
+ arrowLinkClassName = "blog-arrow-link",
109
+ colProps = {
110
+ lg: 4,
111
+ md: 6
112
+ }
113
+ } = _ref2;
114
+ // Default helper function to get time ago
115
+ const defaultGetTimeAgo = dateString => {
116
+ const date = new Date(dateString);
117
+ const now = new Date();
118
+ const diffInSeconds = Math.floor((now - date) / 1000);
119
+ if (diffInSeconds < 60) return 'Just now';
120
+ if (diffInSeconds < 3600) return "".concat(Math.floor(diffInSeconds / 60), "m ago");
121
+ if (diffInSeconds < 86400) return "".concat(Math.floor(diffInSeconds / 3600), "h ago");
122
+ if (diffInSeconds < 172800) return 'Yesterday';
123
+ if (diffInSeconds < 2592000) return "".concat(Math.floor(diffInSeconds / 86400), "d ago");
124
+ if (diffInSeconds < 31536000) return "".concat(Math.floor(diffInSeconds / 2592000), "mo ago");
125
+ return "".concat(Math.floor(diffInSeconds / 31536000), "y ago");
126
+ };
127
+
128
+ // Default helper function to get category
129
+ const defaultGetCategory = category => {
130
+ if (!category || typeof category === 'string' && category.trim() === '') return 'General';
131
+ // If category is an object with name property
132
+ if (typeof category === 'object' && category.name) {
133
+ return category.name;
134
+ }
135
+ // If category is a string
136
+ return category || 'General';
137
+ };
138
+
139
+ // Default helper function to get category color
140
+ const defaultGetCategoryColor = category => {
141
+ const defaultColors = {
142
+ 'Technology': '#3B82F6',
143
+ 'Food': '#F97316',
144
+ 'Automobile': '#EF4444',
145
+ 'Design': '#8B5CF6',
146
+ 'Architecture': '#10B981',
147
+ 'Interior': '#EC4899',
148
+ 'Construction': '#F59E0B',
149
+ 'BIM': '#06B6D4'
150
+ };
151
+
152
+ // Use custom category colors if provided, otherwise use defaults
153
+ const colors = categoryColors || defaultColors;
154
+ return colors[category] || '#6B7280';
155
+ };
156
+
157
+ // Use provided functions or defaults
158
+ const timeAgoFn = getTimeAgo || defaultGetTimeAgo;
159
+ const categoryFn = getCategory || defaultGetCategory;
160
+ const categoryColorFn = getCategoryColor || defaultGetCategoryColor;
161
+
162
+ // Safety check: ensure blogs is an array
163
+ if (!blogs || !Array.isArray(blogs)) {
164
+ return null;
165
+ }
166
+ return /*#__PURE__*/jsxRuntime.jsx(reactBootstrap.Row, {
167
+ className: className,
168
+ children: blogs.map(blogItem => {
169
+ var _blogItem$user, _blogItem$created_by;
170
+ // Use placeholder if image is missing or invalid
171
+ const blogImage = blogItem.image && blogItem.image.trim() !== '' ? blogItem.image : placeholderImage;
172
+ const category = categoryFn(blogItem.category);
173
+ const categoryColor = categoryColorFn(category);
174
+ const timeAgo = timeAgoFn(blogItem.updated_at || blogItem.created_at);
175
+ return /*#__PURE__*/react.createElement(reactBootstrap.Col, _objectSpread2(_objectSpread2({}, colProps), {}, {
176
+ key: blogItem.id
177
+ }), /*#__PURE__*/jsxRuntime.jsxs("div", {
178
+ className: cardClassName,
179
+ children: [/*#__PURE__*/jsxRuntime.jsx("div", {
180
+ className: imageWrapperClassName,
181
+ children: /*#__PURE__*/jsxRuntime.jsxs(LinkComponent, {
182
+ to: "/blog-view/".concat(blogItem.slug),
183
+ children: [/*#__PURE__*/jsxRuntime.jsx(BlogImage, {
184
+ image: blogImage,
185
+ fallback: placeholderImage,
186
+ className: imageClassName
187
+ }), /*#__PURE__*/jsxRuntime.jsx("div", {
188
+ className: categoryTagClassName,
189
+ style: {
190
+ backgroundColor: categoryColor
191
+ },
192
+ children: category
193
+ })]
194
+ })
195
+ }), /*#__PURE__*/jsxRuntime.jsxs("div", {
196
+ className: contentClassName,
197
+ children: [/*#__PURE__*/jsxRuntime.jsx("h2", {
198
+ className: titleClassName,
199
+ children: blogItem.title
200
+ }), /*#__PURE__*/jsxRuntime.jsx("p", {
201
+ className: descClassName,
202
+ children: blogItem.excerpt
203
+ }), /*#__PURE__*/jsxRuntime.jsxs("div", {
204
+ className: authorClassName,
205
+ children: [/*#__PURE__*/jsxRuntime.jsxs("div", {
206
+ className: authorLeftClassName,
207
+ children: [/*#__PURE__*/jsxRuntime.jsx("div", {
208
+ className: authorAvatarClassName,
209
+ children: /*#__PURE__*/jsxRuntime.jsx("i", {
210
+ className: "fa-solid fa-user"
211
+ })
212
+ }), /*#__PURE__*/jsxRuntime.jsxs("div", {
213
+ className: authorInfoClassName,
214
+ children: [/*#__PURE__*/jsxRuntime.jsx("span", {
215
+ className: authorNameClassName,
216
+ children: blogItem.author || blogItem.writer || ((_blogItem$user = blogItem.user) === null || _blogItem$user === void 0 ? void 0 : _blogItem$user.name) || ((_blogItem$created_by = blogItem.created_by) === null || _blogItem$created_by === void 0 ? void 0 : _blogItem$created_by.name) || 'Admin'
217
+ }), /*#__PURE__*/jsxRuntime.jsx("span", {
218
+ className: authorTimeClassName,
219
+ children: timeAgo
220
+ })]
221
+ })]
222
+ }), /*#__PURE__*/jsxRuntime.jsx(LinkComponent, {
223
+ to: "/blog-view/".concat(blogItem.slug),
224
+ className: arrowLinkClassName,
225
+ children: /*#__PURE__*/jsxRuntime.jsx("i", {
226
+ className: "fa-solid fa-arrow-up-right-from-square"
227
+ })
228
+ })]
229
+ })]
230
+ })]
231
+ }));
232
+ })
233
+ });
234
+ };
235
+
236
+ exports.BlogCard = BlogCard;
237
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sources":["../src/BlogCard.jsx"],"sourcesContent":["import { useState, useEffect } from 'react';\r\nimport { Col, Row } from 'react-bootstrap';\r\nimport { Link } from 'react-router-dom';\r\n\r\n// Component to handle image loading with fallback\r\nconst BlogImage = ({ image, fallback, className }) => {\r\n const [imgSrc, setImgSrc] = useState(image || fallback);\r\n\r\n useEffect(() => {\r\n // If no image provided, use fallback\r\n if (!image || image.trim() === '') {\r\n setImgSrc(fallback);\r\n return;\r\n }\r\n\r\n // Preload image to check if it exists\r\n const img = new Image();\r\n img.onerror = () => {\r\n // Image failed to load, use fallback\r\n setImgSrc(fallback);\r\n };\r\n img.onload = () => {\r\n // Image loaded successfully\r\n setImgSrc(image);\r\n };\r\n img.src = image;\r\n }, [image, fallback]);\r\n\r\n return (\r\n <div\r\n style={{ backgroundImage: `url(${imgSrc})` }}\r\n className={className}\r\n />\r\n );\r\n};\r\n\r\nconst BlogCard = ({ \r\n blogs,\r\n placeholderImage,\r\n categoryColors,\r\n getTimeAgo,\r\n getCategory,\r\n getCategoryColor,\r\n LinkComponent = Link,\r\n className = \"g-4\",\r\n cardClassName = \"blog-card-modern mb-4\",\r\n imageWrapperClassName = \"blog-card-image-wrapper\",\r\n imageClassName = \"blog-card-img-modern\",\r\n categoryTagClassName = \"blog-category-tag\",\r\n contentClassName = \"blog-card-content\",\r\n titleClassName = \"blog-card-title-modern\",\r\n descClassName = \"blog-card-desc-modern\",\r\n authorClassName = \"blog-card-author\",\r\n authorLeftClassName = \"blog-author-left\",\r\n authorAvatarClassName = \"blog-author-avatar\",\r\n authorInfoClassName = \"blog-author-info\",\r\n authorNameClassName = \"blog-author-name\",\r\n authorTimeClassName = \"blog-author-time\",\r\n arrowLinkClassName = \"blog-arrow-link\",\r\n colProps = { lg: 4, md: 6 }\r\n}) => {\r\n // Default helper function to get time ago\r\n const defaultGetTimeAgo = (dateString) => {\r\n const date = new Date(dateString);\r\n const now = new Date();\r\n const diffInSeconds = Math.floor((now - date) / 1000);\r\n\r\n if (diffInSeconds < 60) return 'Just now';\r\n if (diffInSeconds < 3600) return `${Math.floor(diffInSeconds / 60)}m ago`;\r\n if (diffInSeconds < 86400) return `${Math.floor(diffInSeconds / 3600)}h ago`;\r\n if (diffInSeconds < 172800) return 'Yesterday';\r\n if (diffInSeconds < 2592000) return `${Math.floor(diffInSeconds / 86400)}d ago`;\r\n if (diffInSeconds < 31536000) return `${Math.floor(diffInSeconds / 2592000)}mo ago`;\r\n return `${Math.floor(diffInSeconds / 31536000)}y ago`;\r\n };\r\n\r\n // Default helper function to get category\r\n const defaultGetCategory = (category) => {\r\n if (!category || (typeof category === 'string' && category.trim() === '')) return 'General';\r\n // If category is an object with name property\r\n if (typeof category === 'object' && category.name) {\r\n return category.name;\r\n }\r\n // If category is a string\r\n return category || 'General';\r\n };\r\n\r\n // Default helper function to get category color\r\n const defaultGetCategoryColor = (category) => {\r\n const defaultColors = {\r\n 'Technology': '#3B82F6',\r\n 'Food': '#F97316',\r\n 'Automobile': '#EF4444',\r\n 'Design': '#8B5CF6',\r\n 'Architecture': '#10B981',\r\n 'Interior': '#EC4899',\r\n 'Construction': '#F59E0B',\r\n 'BIM': '#06B6D4',\r\n };\r\n \r\n // Use custom category colors if provided, otherwise use defaults\r\n const colors = categoryColors || defaultColors;\r\n return colors[category] || '#6B7280';\r\n };\r\n\r\n // Use provided functions or defaults\r\n const timeAgoFn = getTimeAgo || defaultGetTimeAgo;\r\n const categoryFn = getCategory || defaultGetCategory;\r\n const categoryColorFn = getCategoryColor || defaultGetCategoryColor;\r\n\r\n // Safety check: ensure blogs is an array\r\n if (!blogs || !Array.isArray(blogs)) {\r\n return null;\r\n }\r\n\r\n return (\r\n <Row className={className}>\r\n {blogs.map((blogItem) => {\r\n // Use placeholder if image is missing or invalid\r\n const blogImage = blogItem.image && blogItem.image.trim() !== ''\r\n ? blogItem.image\r\n : placeholderImage;\r\n\r\n const category = categoryFn(blogItem.category);\r\n const categoryColor = categoryColorFn(category);\r\n const timeAgo = timeAgoFn(blogItem.updated_at || blogItem.created_at);\r\n\r\n return (\r\n <Col {...colProps} key={blogItem.id}>\r\n <div className={cardClassName}>\r\n <div className={imageWrapperClassName}>\r\n <LinkComponent to={`/blog-view/${blogItem.slug}`}>\r\n <BlogImage\r\n image={blogImage}\r\n fallback={placeholderImage}\r\n className={imageClassName}\r\n />\r\n <div \r\n className={categoryTagClassName} \r\n style={{ backgroundColor: categoryColor }}\r\n >\r\n {category}\r\n </div>\r\n </LinkComponent>\r\n </div>\r\n <div className={contentClassName}>\r\n <h2 className={titleClassName}>{blogItem.title}</h2>\r\n <p className={descClassName}>{blogItem.excerpt}</p>\r\n <div className={authorClassName}>\r\n <div className={authorLeftClassName}>\r\n <div className={authorAvatarClassName}>\r\n <i className=\"fa-solid fa-user\"></i>\r\n </div>\r\n <div className={authorInfoClassName}>\r\n <span className={authorNameClassName}>\r\n {blogItem.author || blogItem.writer || blogItem.user?.name || blogItem.created_by?.name || 'Admin'}\r\n </span>\r\n <span className={authorTimeClassName}>{timeAgo}</span>\r\n </div>\r\n </div>\r\n <LinkComponent\r\n to={`/blog-view/${blogItem.slug}`}\r\n className={arrowLinkClassName}\r\n >\r\n <i className=\"fa-solid fa-arrow-up-right-from-square\"></i>\r\n </LinkComponent>\r\n </div>\r\n </div>\r\n </div>\r\n </Col>\r\n );\r\n })}\r\n </Row>\r\n );\r\n};\r\n\r\nexport default BlogCard;\r\n\r\n"],"names":["BlogImage","_ref","image","fallback","className","imgSrc","setImgSrc","useState","useEffect","trim","img","Image","onerror","onload","src","_jsx","style","backgroundImage","concat","BlogCard","_ref2","blogs","placeholderImage","categoryColors","getTimeAgo","getCategory","getCategoryColor","LinkComponent","Link","cardClassName","imageWrapperClassName","imageClassName","categoryTagClassName","contentClassName","titleClassName","descClassName","authorClassName","authorLeftClassName","authorAvatarClassName","authorInfoClassName","authorNameClassName","authorTimeClassName","arrowLinkClassName","colProps","lg","md","defaultGetTimeAgo","dateString","date","Date","now","diffInSeconds","Math","floor","defaultGetCategory","category","name","defaultGetCategoryColor","defaultColors","colors","timeAgoFn","categoryFn","categoryColorFn","Array","isArray","Row","children","map","blogItem","_blogItem$user","_blogItem$created_by","blogImage","categoryColor","timeAgo","updated_at","created_at","_createElement","Col","_objectSpread","key","id","_jsxs","to","slug","backgroundColor","title","excerpt","author","writer","user","created_by"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAKA,MAAMA,SAAS,GAAGC,IAAA,IAAoC;EAAA,IAAnC;IAAEC,KAAK;IAAEC,QAAQ;AAAEC,IAAAA;AAAU,GAAC,GAAAH,IAAA;EAC/C,MAAM,CAACI,MAAM,EAAEC,SAAS,CAAC,GAAGC,cAAQ,CAACL,KAAK,IAAIC,QAAQ,CAAC;AAEvDK,EAAAA,eAAS,CAAC,MAAM;AACd;IACA,IAAI,CAACN,KAAK,IAAIA,KAAK,CAACO,IAAI,EAAE,KAAK,EAAE,EAAE;MACjCH,SAAS,CAACH,QAAQ,CAAC;AACnB,MAAA;AACF,IAAA;;AAEA;AACA,IAAA,MAAMO,GAAG,GAAG,IAAIC,KAAK,EAAE;IACvBD,GAAG,CAACE,OAAO,GAAG,MAAM;AAClB;MACAN,SAAS,CAACH,QAAQ,CAAC;IACrB,CAAC;IACDO,GAAG,CAACG,MAAM,GAAG,MAAM;AACjB;MACAP,SAAS,CAACJ,KAAK,CAAC;IAClB,CAAC;IACDQ,GAAG,CAACI,GAAG,GAAGZ,KAAK;AACjB,EAAA,CAAC,EAAE,CAACA,KAAK,EAAEC,QAAQ,CAAC,CAAC;AAErB,EAAA,oBACEY,cAAA,CAAA,KAAA,EAAA;AACEC,IAAAA,KAAK,EAAE;MAAEC,eAAe,EAAA,MAAA,CAAAC,MAAA,CAASb,MAAM,EAAA,GAAA;KAAM;AAC7CD,IAAAA,SAAS,EAAEA;AAAU,GACtB,CAAC;AAEN,CAAC;AAED,MAAMe,QAAQ,GAAGC,KAAA,IAwBX;EAAA,IAxBY;IAChBC,KAAK;IACLC,gBAAgB;IAChBC,cAAc;IACdC,UAAU;IACVC,WAAW;IACXC,gBAAgB;AAChBC,IAAAA,aAAa,GAAGC,mBAAI;AACpBxB,IAAAA,SAAS,GAAG,KAAK;AACjByB,IAAAA,aAAa,GAAG,uBAAuB;AACvCC,IAAAA,qBAAqB,GAAG,yBAAyB;AACjDC,IAAAA,cAAc,GAAG,sBAAsB;AACvCC,IAAAA,oBAAoB,GAAG,mBAAmB;AAC1CC,IAAAA,gBAAgB,GAAG,mBAAmB;AACtCC,IAAAA,cAAc,GAAG,wBAAwB;AACzCC,IAAAA,aAAa,GAAG,uBAAuB;AACvCC,IAAAA,eAAe,GAAG,kBAAkB;AACpCC,IAAAA,mBAAmB,GAAG,kBAAkB;AACxCC,IAAAA,qBAAqB,GAAG,oBAAoB;AAC5CC,IAAAA,mBAAmB,GAAG,kBAAkB;AACxCC,IAAAA,mBAAmB,GAAG,kBAAkB;AACxCC,IAAAA,mBAAmB,GAAG,kBAAkB;AACxCC,IAAAA,kBAAkB,GAAG,iBAAiB;AACtCC,IAAAA,QAAQ,GAAG;AAAEC,MAAAA,EAAE,EAAE,CAAC;AAAEC,MAAAA,EAAE,EAAE;AAAE;AAC5B,GAAC,GAAAzB,KAAA;AACC;EACA,MAAM0B,iBAAiB,GAAIC,UAAU,IAAK;AACxC,IAAA,MAAMC,IAAI,GAAG,IAAIC,IAAI,CAACF,UAAU,CAAC;AACjC,IAAA,MAAMG,GAAG,GAAG,IAAID,IAAI,EAAE;AACtB,IAAA,MAAME,aAAa,GAAGC,IAAI,CAACC,KAAK,CAAC,CAACH,GAAG,GAAGF,IAAI,IAAI,IAAI,CAAC;AAErD,IAAA,IAAIG,aAAa,GAAG,EAAE,EAAE,OAAO,UAAU;AACzC,IAAA,IAAIA,aAAa,GAAG,IAAI,EAAE,UAAAjC,MAAA,CAAUkC,IAAI,CAACC,KAAK,CAACF,aAAa,GAAG,EAAE,CAAC,EAAA,OAAA,CAAA;AAClE,IAAA,IAAIA,aAAa,GAAG,KAAK,EAAE,UAAAjC,MAAA,CAAUkC,IAAI,CAACC,KAAK,CAACF,aAAa,GAAG,IAAI,CAAC,EAAA,OAAA,CAAA;AACrE,IAAA,IAAIA,aAAa,GAAG,MAAM,EAAE,OAAO,WAAW;AAC9C,IAAA,IAAIA,aAAa,GAAG,OAAO,EAAE,UAAAjC,MAAA,CAAUkC,IAAI,CAACC,KAAK,CAACF,aAAa,GAAG,KAAK,CAAC,EAAA,OAAA,CAAA;AACxE,IAAA,IAAIA,aAAa,GAAG,QAAQ,EAAE,UAAAjC,MAAA,CAAUkC,IAAI,CAACC,KAAK,CAACF,aAAa,GAAG,OAAO,CAAC,EAAA,QAAA,CAAA;IAC3E,OAAA,EAAA,CAAAjC,MAAA,CAAUkC,IAAI,CAACC,KAAK,CAACF,aAAa,GAAG,QAAQ,CAAC,EAAA,OAAA,CAAA;EAChD,CAAC;;AAED;EACA,MAAMG,kBAAkB,GAAIC,QAAQ,IAAK;AACvC,IAAA,IAAI,CAACA,QAAQ,IAAK,OAAOA,QAAQ,KAAK,QAAQ,IAAIA,QAAQ,CAAC9C,IAAI,EAAE,KAAK,EAAG,EAAE,OAAO,SAAS;AAC3F;IACA,IAAI,OAAO8C,QAAQ,KAAK,QAAQ,IAAIA,QAAQ,CAACC,IAAI,EAAE;MACjD,OAAOD,QAAQ,CAACC,IAAI;AACtB,IAAA;AACA;IACA,OAAOD,QAAQ,IAAI,SAAS;EAC9B,CAAC;;AAED;EACA,MAAME,uBAAuB,GAAIF,QAAQ,IAAK;AAC5C,IAAA,MAAMG,aAAa,GAAG;AACpB,MAAA,YAAY,EAAE,SAAS;AACvB,MAAA,MAAM,EAAE,SAAS;AACjB,MAAA,YAAY,EAAE,SAAS;AACvB,MAAA,QAAQ,EAAE,SAAS;AACnB,MAAA,cAAc,EAAE,SAAS;AACzB,MAAA,UAAU,EAAE,SAAS;AACrB,MAAA,cAAc,EAAE,SAAS;AACzB,MAAA,KAAK,EAAE;KACR;;AAED;AACA,IAAA,MAAMC,MAAM,GAAGpC,cAAc,IAAImC,aAAa;AAC9C,IAAA,OAAOC,MAAM,CAACJ,QAAQ,CAAC,IAAI,SAAS;EACtC,CAAC;;AAED;AACA,EAAA,MAAMK,SAAS,GAAGpC,UAAU,IAAIsB,iBAAiB;AACjD,EAAA,MAAMe,UAAU,GAAGpC,WAAW,IAAI6B,kBAAkB;AACpD,EAAA,MAAMQ,eAAe,GAAGpC,gBAAgB,IAAI+B,uBAAuB;;AAEnE;EACA,IAAI,CAACpC,KAAK,IAAI,CAAC0C,KAAK,CAACC,OAAO,CAAC3C,KAAK,CAAC,EAAE;AACnC,IAAA,OAAO,IAAI;AACb,EAAA;EAEA,oBACEN,cAAA,CAACkD,kBAAG,EAAA;AAAC7D,IAAAA,SAAS,EAAEA,SAAU;AAAA8D,IAAAA,QAAA,EACvB7C,KAAK,CAAC8C,GAAG,CAAEC,QAAQ,IAAK;MAAA,IAAAC,cAAA,EAAAC,oBAAA;AACvB;MACA,MAAMC,SAAS,GAAGH,QAAQ,CAAClE,KAAK,IAAIkE,QAAQ,CAAClE,KAAK,CAACO,IAAI,EAAE,KAAK,EAAE,GAC5D2D,QAAQ,CAAClE,KAAK,GACdoB,gBAAgB;AAEpB,MAAA,MAAMiC,QAAQ,GAAGM,UAAU,CAACO,QAAQ,CAACb,QAAQ,CAAC;AAC9C,MAAA,MAAMiB,aAAa,GAAGV,eAAe,CAACP,QAAQ,CAAC;MAC/C,MAAMkB,OAAO,GAAGb,SAAS,CAACQ,QAAQ,CAACM,UAAU,IAAIN,QAAQ,CAACO,UAAU,CAAC;MAErE,oBACEC,mBAAA,CAACC,kBAAG,EAAAC,cAAA,CAAAA,cAAA,KAAKnC,QAAQ,CAAA,EAAA,EAAA,EAAA;QAAEoC,GAAG,EAAEX,QAAQ,CAACY;AAAG,OAAA,CAAA,eAClCC,eAAA,CAAA,KAAA,EAAA;AAAK7E,QAAAA,SAAS,EAAEyB,aAAc;AAAAqC,QAAAA,QAAA,gBAC5BnD,cAAA,CAAA,KAAA,EAAA;AAAKX,UAAAA,SAAS,EAAE0B,qBAAsB;UAAAoC,QAAA,eACpCe,eAAA,CAACtD,aAAa,EAAA;AAACuD,YAAAA,EAAE,gBAAAhE,MAAA,CAAgBkD,QAAQ,CAACe,IAAI,CAAG;YAAAjB,QAAA,EAAA,cAC/CnD,cAAA,CAACf,SAAS,EAAA;AACRE,cAAAA,KAAK,EAAEqE,SAAU;AACjBpE,cAAAA,QAAQ,EAAEmB,gBAAiB;AAC3BlB,cAAAA,SAAS,EAAE2B;aACZ,CAAC,eACFhB,cAAA,CAAA,KAAA,EAAA;AACEX,cAAAA,SAAS,EAAE4B,oBAAqB;AAChChB,cAAAA,KAAK,EAAE;AAAEoE,gBAAAA,eAAe,EAAEZ;eAAgB;AAAAN,cAAAA,QAAA,EAEzCX;AAAQ,aACN,CAAC;WACO;SACZ,CAAC,eACN0B,eAAA,CAAA,KAAA,EAAA;AAAK7E,UAAAA,SAAS,EAAE6B,gBAAiB;AAAAiC,UAAAA,QAAA,gBAC/BnD,cAAA,CAAA,IAAA,EAAA;AAAIX,YAAAA,SAAS,EAAE8B,cAAe;YAAAgC,QAAA,EAAEE,QAAQ,CAACiB;WAAU,CAAC,eACpDtE,cAAA,CAAA,GAAA,EAAA;AAAGX,YAAAA,SAAS,EAAE+B,aAAc;YAAA+B,QAAA,EAAEE,QAAQ,CAACkB;WAAW,CAAC,eACnDL,eAAA,CAAA,KAAA,EAAA;AAAK7E,YAAAA,SAAS,EAAEgC,eAAgB;AAAA8B,YAAAA,QAAA,gBAC9Be,eAAA,CAAA,KAAA,EAAA;AAAK7E,cAAAA,SAAS,EAAEiC,mBAAoB;AAAA6B,cAAAA,QAAA,gBAClCnD,cAAA,CAAA,KAAA,EAAA;AAAKX,gBAAAA,SAAS,EAAEkC,qBAAsB;AAAA4B,gBAAAA,QAAA,eACpCnD,cAAA,CAAA,GAAA,EAAA;AAAGX,kBAAAA,SAAS,EAAC;iBAAsB;eAChC,CAAC,eACN6E,eAAA,CAAA,KAAA,EAAA;AAAK7E,gBAAAA,SAAS,EAAEmC,mBAAoB;AAAA2B,gBAAAA,QAAA,gBAClCnD,cAAA,CAAA,MAAA,EAAA;AAAMX,kBAAAA,SAAS,EAAEoC,mBAAoB;AAAA0B,kBAAAA,QAAA,EAClCE,QAAQ,CAACmB,MAAM,IAAInB,QAAQ,CAACoB,MAAM,KAAA,CAAAnB,cAAA,GAAID,QAAQ,CAACqB,IAAI,MAAA,IAAA,IAAApB,cAAA,KAAA,MAAA,GAAA,MAAA,GAAbA,cAAA,CAAeb,IAAI,CAAA,KAAA,CAAAc,oBAAA,GAAIF,QAAQ,CAACsB,UAAU,MAAA,IAAA,IAAApB,oBAAA,KAAA,MAAA,GAAA,MAAA,GAAnBA,oBAAA,CAAqBd,IAAI,CAAA,IAAI;iBACvF,CAAC,eACPzC,cAAA,CAAA,MAAA,EAAA;AAAMX,kBAAAA,SAAS,EAAEqC,mBAAoB;AAAAyB,kBAAAA,QAAA,EAAEO;AAAO,iBAAO,CAAC;AAAA,eACnD,CAAC;AAAA,aACH,CAAC,eACN1D,cAAA,CAACY,aAAa,EAAA;AACZuD,cAAAA,EAAE,gBAAAhE,MAAA,CAAgBkD,QAAQ,CAACe,IAAI,CAAG;AAClC/E,cAAAA,SAAS,EAAEsC,kBAAmB;AAAAwB,cAAAA,QAAA,eAE9BnD,cAAA,CAAA,GAAA,EAAA;AAAGX,gBAAAA,SAAS,EAAC;eAA4C;AAAC,aAC7C,CAAC;AAAA,WACb,CAAC;AAAA,SACH,CAAC;AAAA,OACH,CACF,CAAC;IAEV,CAAC;AAAC,GACC,CAAC;AAEV;;;;"}
package/package.json ADDED
@@ -0,0 +1,56 @@
1
+ {
2
+ "name": "@veeyaainnovatives/blog-card",
3
+ "version": "1.0.0",
4
+ "description": "A reusable Blog card component for React applications",
5
+ "main": "dist/index.js",
6
+ "module": "dist/index.esm.js",
7
+ "exports": {
8
+ ".": {
9
+ "import": "./dist/index.esm.js",
10
+ "require": "./dist/index.js"
11
+ }
12
+ },
13
+ "files": [
14
+ "dist",
15
+ "README.md"
16
+ ],
17
+ "scripts": {
18
+ "build": "rollup -c",
19
+ "dev": "rollup -c -w",
20
+ "prepare": "npm run build"
21
+ },
22
+ "keywords": [
23
+ "react",
24
+ "blog",
25
+ "card",
26
+ "component",
27
+ "veeyaainnovatives"
28
+ ],
29
+ "author": "Veeyaa Innovatives",
30
+ "license": "MIT",
31
+ "peerDependencies": {
32
+ "react": "^16.8.0 || ^17.0.0 || ^18.0.0",
33
+ "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0",
34
+ "react-bootstrap": "^2.0.0",
35
+ "react-router-dom": "^6.0.0"
36
+ },
37
+ "devDependencies": {
38
+ "@babel/core": "^7.23.5",
39
+ "@babel/preset-env": "^7.23.5",
40
+ "@babel/preset-react": "^7.23.3",
41
+ "@rollup/plugin-babel": "^6.0.4",
42
+ "@rollup/plugin-commonjs": "^25.0.7",
43
+ "@rollup/plugin-node-resolve": "^15.2.3",
44
+ "rollup": "^4.6.1",
45
+ "rollup-plugin-peer-deps-external": "^2.2.4"
46
+ },
47
+ "repository": {
48
+ "type": "git",
49
+ "url": "https://github.com/npmveeyaa/blog-card.git"
50
+ },
51
+ "homepage": "https://github.com/npmveeyaa/blog-card#readme",
52
+ "bugs": {
53
+ "url": "https://github.com/npmveeyaa/blog-card/issues"
54
+ }
55
+ }
56
+