urpanels-ui-pack 0.0.2

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.
Files changed (62) hide show
  1. package/README.md +37 -0
  2. package/dist/Button/Button.svelte +76 -0
  3. package/dist/Button/Button.svelte.d.ts +13 -0
  4. package/dist/Button/index.d.ts +1 -0
  5. package/dist/Button/index.js +1 -0
  6. package/dist/InfoCard/InfoCard.svelte +227 -0
  7. package/dist/InfoCard/InfoCard.svelte.d.ts +4 -0
  8. package/dist/InfoCard/InfoCard.types.d.ts +56 -0
  9. package/dist/InfoCard/InfoCard.types.js +1 -0
  10. package/dist/InfoCard/index.d.ts +2 -0
  11. package/dist/InfoCard/index.js +1 -0
  12. package/dist/LoadingSpinner/LoadingSpinner.svelte +3 -0
  13. package/dist/LoadingSpinner/LoadingSpinner.svelte.d.ts +26 -0
  14. package/dist/LoadingSpinner/index.d.ts +1 -0
  15. package/dist/LoadingSpinner/index.js +1 -0
  16. package/dist/Modal/Modal.svelte +122 -0
  17. package/dist/Modal/Modal.svelte.d.ts +39 -0
  18. package/dist/Modal/index.d.ts +1 -0
  19. package/dist/Modal/index.js +1 -0
  20. package/dist/PageLayout/ActionButton.svelte +26 -0
  21. package/dist/PageLayout/ActionButton.svelte.d.ts +8 -0
  22. package/dist/PageLayout/PageContent.svelte +19 -0
  23. package/dist/PageLayout/PageContent.svelte.d.ts +8 -0
  24. package/dist/PageLayout/PageHeader.svelte +29 -0
  25. package/dist/PageLayout/PageHeader.svelte.d.ts +9 -0
  26. package/dist/PageLayout/SearchBar.svelte +25 -0
  27. package/dist/PageLayout/SearchBar.svelte.d.ts +8 -0
  28. package/dist/PageLayout/ViewToggle.svelte +53 -0
  29. package/dist/PageLayout/ViewToggle.svelte.d.ts +8 -0
  30. package/dist/PageLayout/index.d.ts +5 -0
  31. package/dist/PageLayout/index.js +5 -0
  32. package/dist/Pagination/Pagination.svelte +96 -0
  33. package/dist/Pagination/Pagination.svelte.d.ts +4 -0
  34. package/dist/Pagination/Pagination.types.d.ts +11 -0
  35. package/dist/Pagination/Pagination.types.js +1 -0
  36. package/dist/Pagination/index.d.ts +2 -0
  37. package/dist/Pagination/index.js +1 -0
  38. package/dist/RichTextEditor/RichTextEditor.svelte +575 -0
  39. package/dist/RichTextEditor/RichTextEditor.svelte.d.ts +10 -0
  40. package/dist/RichTextEditor/index.d.ts +1 -0
  41. package/dist/RichTextEditor/index.js +1 -0
  42. package/dist/index.d.ts +5 -0
  43. package/dist/index.js +12 -0
  44. package/dist/sections/ArticlesGrid/ArticlesGrid.svelte +201 -0
  45. package/dist/sections/ArticlesGrid/ArticlesGrid.svelte.d.ts +31 -0
  46. package/dist/sections/ArticlesGrid/README.md +229 -0
  47. package/dist/sections/ArticlesGrid/index.d.ts +2 -0
  48. package/dist/sections/ArticlesGrid/index.js +1 -0
  49. package/dist/sections/FeaturedGalleryGrid/FeaturedGalleryGrid.svelte +118 -0
  50. package/dist/sections/FeaturedGalleryGrid/FeaturedGalleryGrid.svelte.d.ts +21 -0
  51. package/dist/sections/FeaturedGalleryGrid/README.md +270 -0
  52. package/dist/sections/FeaturedGalleryGrid/index.d.ts +2 -0
  53. package/dist/sections/FeaturedGalleryGrid/index.js +1 -0
  54. package/dist/sections/HeroCarousel/HeroCarousel.svelte +318 -0
  55. package/dist/sections/HeroCarousel/HeroCarousel.svelte.d.ts +23 -0
  56. package/dist/sections/HeroCarousel/index.d.ts +1 -0
  57. package/dist/sections/HeroCarousel/index.js +1 -0
  58. package/dist/sections/index.d.ts +5 -0
  59. package/dist/sections/index.js +3 -0
  60. package/dist/utils/translations.svelte.d.ts +37 -0
  61. package/dist/utils/translations.svelte.js +67 -0
  62. package/package.json +47 -0
@@ -0,0 +1,201 @@
1
+ <script lang="ts">
2
+ /**
3
+ * ArticlesGrid Component - Framework-agnostic article cards grid
4
+ * Extracted from av-talha-web for reusability
5
+ */
6
+
7
+ export interface Article {
8
+ slug: string;
9
+ title: string;
10
+ date?: string;
11
+ featuredImage?: string;
12
+ images?: string[];
13
+ summary?: string;
14
+ header?: string;
15
+ content?: string;
16
+ }
17
+
18
+ interface Props {
19
+ articles: Article[];
20
+ translations: {
21
+ articlesLabel: string;
22
+ title: string;
23
+ description: string;
24
+ readMore: string;
25
+ viewAll: string;
26
+ };
27
+ locale?: string;
28
+ onArticleClick?: (slug: string) => void;
29
+ onViewAllClick?: () => void;
30
+ imageResolver?: (path: string) => string;
31
+ }
32
+
33
+ let {
34
+ articles = [],
35
+ translations,
36
+ locale = 'tr',
37
+ onArticleClick,
38
+ onViewAllClick,
39
+ imageResolver = (path: string) => path
40
+ }: Props = $props();
41
+
42
+ const formatDate = (dateStr: string, locale: string): string => {
43
+ const date = new Date(dateStr);
44
+ if (locale === 'tr') {
45
+ return date.toLocaleDateString('tr-TR', {
46
+ year: 'numeric',
47
+ month: 'long',
48
+ day: 'numeric'
49
+ });
50
+ }
51
+ return date.toLocaleDateString('en-US', {
52
+ year: 'numeric',
53
+ month: 'long',
54
+ day: 'numeric'
55
+ });
56
+ };
57
+
58
+ const handleArticleClick = (e: MouseEvent, slug: string) => {
59
+ if (onArticleClick) {
60
+ e.preventDefault();
61
+ onArticleClick(slug);
62
+ }
63
+ };
64
+
65
+ const handleViewAllClick = (e: MouseEvent) => {
66
+ if (onViewAllClick) {
67
+ e.preventDefault();
68
+ onViewAllClick();
69
+ }
70
+ };
71
+
72
+ const getArticleImage = (article: Article): string | null => {
73
+ return article.featuredImage || (article.images && article.images[0]) || null;
74
+ };
75
+
76
+ const getArticleExcerpt = (article: Article): string => {
77
+ const text = article.summary || article.header || article.content || '';
78
+ return text.replace(/<[^>]*>/g, '').substring(0, 150);
79
+ };
80
+ </script>
81
+
82
+ <section class="py-20 bg-gray-50">
83
+ <div class="container mx-auto px-4">
84
+ <div class="text-center mb-16">
85
+ <span class="text-primary-600 font-semibold text-sm uppercase tracking-wider mb-2 block">
86
+ {translations.articlesLabel}
87
+ </span>
88
+ <h2 class="text-4xl md:text-5xl font-bold text-gray-900 mb-4">
89
+ {translations.title}
90
+ </h2>
91
+ <p class="text-xl text-gray-600 max-w-2xl mx-auto">
92
+ {translations.description}
93
+ </p>
94
+ </div>
95
+
96
+ <div class="grid grid-cols-1 md:grid-cols-3 gap-8 max-w-7xl mx-auto">
97
+ {#each articles as article}
98
+ <article class="group bg-white rounded-2xl shadow-lg hover:shadow-2xl transition-all duration-300 overflow-hidden transform hover:-translate-y-2">
99
+ {#if getArticleImage(article)}
100
+ <a
101
+ href="#"
102
+ onclick={(e) => handleArticleClick(e, article.slug)}
103
+ class="block relative overflow-hidden aspect-[16/10]"
104
+ >
105
+ <div class="absolute inset-0 bg-gradient-to-t from-black/50 to-transparent opacity-0 group-hover:opacity-100 transition-opacity duration-300 z-10"></div>
106
+ <img
107
+ src={imageResolver(getArticleImage(article)!)}
108
+ alt={article.title}
109
+ class="w-full h-full object-cover transform group-hover:scale-110 transition-transform duration-500"
110
+ />
111
+ </a>
112
+ {:else}
113
+ <div class="aspect-[16/10] bg-gradient-to-br from-primary-100 to-primary-50 flex items-center justify-center">
114
+ <svg class="w-16 h-16 text-primary-300" fill="none" stroke="currentColor" viewBox="0 0 24 24">
115
+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" d="M12 6.253v13m0-13C10.832 5.477 9.246 5 7.5 5S4.168 5.477 3 6.253v13C4.168 18.477 5.754 18 7.5 18s3.332.477 4.5 1.253m0-13C13.168 5.477 14.754 5 16.5 5c1.747 0 3.332.477 4.5 1.253v13C19.832 18.477 18.247 18 16.5 18c-1.746 0-3.332.477-4.5 1.253" />
116
+ </svg>
117
+ </div>
118
+ {/if}
119
+
120
+ <div class="p-8">
121
+ {#if article.date}
122
+ <div class="flex items-center text-sm text-gray-500 mb-4">
123
+ <svg class="w-4 h-4 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24">
124
+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8 7V3m8 4V3m-9 8h10M5 21h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v12a2 2 0 002 2z" />
125
+ </svg>
126
+ {formatDate(article.date, locale)}
127
+ </div>
128
+ {/if}
129
+
130
+ <h3 class="text-2xl font-bold text-gray-900 mb-4 line-clamp-2 group-hover:text-primary-600 transition-colors">
131
+ <a href="#" onclick={(e) => handleArticleClick(e, article.slug)}>
132
+ {article.title}
133
+ </a>
134
+ </h3>
135
+
136
+ {#if article.summary || article.header || article.content}
137
+ <p class="text-gray-600 mb-6 line-clamp-3 leading-relaxed">
138
+ {getArticleExcerpt(article)}...
139
+ </p>
140
+ {/if}
141
+
142
+ <a
143
+ href="#"
144
+ onclick={(e) => handleArticleClick(e, article.slug)}
145
+ class="inline-flex items-center text-primary-600 hover:text-primary-700 font-semibold group/link"
146
+ >
147
+ <span>{translations.readMore}</span>
148
+ <svg class="w-5 h-5 ml-2 transform group-hover/link:translate-x-1 transition-transform" fill="none" stroke="currentColor" viewBox="0 0 24 24">
149
+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M17 8l4 4m0 0l-4 4m4-4H3" />
150
+ </svg>
151
+ </a>
152
+ </div>
153
+ </article>
154
+ {/each}
155
+ </div>
156
+
157
+ <div class="text-center mt-16">
158
+ <a
159
+ href="#"
160
+ onclick={handleViewAllClick}
161
+ class="inline-flex items-center px-8 py-4 bg-gradient-to-r from-[#d6bb6d] via-[#c9a858] to-[#b89544] text-white font-bold text-lg rounded-xl hover:from-[#e0c97d] hover:via-[#d4b868] hover:to-[#c9a858] transform hover:scale-105 transition-all shadow-xl hover:shadow-2xl"
162
+ >
163
+ <span>{translations.viewAll}</span>
164
+ <svg class="w-6 h-6 ml-3" fill="none" stroke="currentColor" viewBox="0 0 24 24">
165
+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M17 8l4 4m0 0l-4 4m4-4H3" />
166
+ </svg>
167
+ </a>
168
+ </div>
169
+ </div>
170
+ </section>
171
+
172
+ <style>
173
+ /* Scoped Tailwind-like styles - framework agnostic */
174
+ section :global(.container) {
175
+ max-width: 1280px;
176
+ }
177
+
178
+ /* Line clamp utility classes */
179
+ :global(.line-clamp-2) {
180
+ display: -webkit-box;
181
+ -webkit-line-clamp: 2;
182
+ -webkit-box-orient: vertical;
183
+ overflow: hidden;
184
+ }
185
+
186
+ :global(.line-clamp-3) {
187
+ display: -webkit-box;
188
+ -webkit-line-clamp: 3;
189
+ -webkit-box-orient: vertical;
190
+ overflow: hidden;
191
+ }
192
+
193
+ /* Primary color fallbacks if not defined in parent */
194
+ section {
195
+ --primary-50: #fef5e7;
196
+ --primary-100: #fce8c4;
197
+ --primary-300: #f5c76e;
198
+ --primary-600: #d6bb6d;
199
+ --primary-700: #c9a858;
200
+ }
201
+ </style>
@@ -0,0 +1,31 @@
1
+ /**
2
+ * ArticlesGrid Component - Framework-agnostic article cards grid
3
+ * Extracted from av-talha-web for reusability
4
+ */
5
+ export interface Article {
6
+ slug: string;
7
+ title: string;
8
+ date?: string;
9
+ featuredImage?: string;
10
+ images?: string[];
11
+ summary?: string;
12
+ header?: string;
13
+ content?: string;
14
+ }
15
+ interface Props {
16
+ articles: Article[];
17
+ translations: {
18
+ articlesLabel: string;
19
+ title: string;
20
+ description: string;
21
+ readMore: string;
22
+ viewAll: string;
23
+ };
24
+ locale?: string;
25
+ onArticleClick?: (slug: string) => void;
26
+ onViewAllClick?: () => void;
27
+ imageResolver?: (path: string) => string;
28
+ }
29
+ declare const ArticlesGrid: import("svelte").Component<Props, {}, "">;
30
+ type ArticlesGrid = ReturnType<typeof ArticlesGrid>;
31
+ export default ArticlesGrid;
@@ -0,0 +1,229 @@
1
+ # ArticlesGrid Component
2
+
3
+ Framework-agnostic articles grid component extracted from av-talha-web project.
4
+
5
+ ## Features
6
+
7
+ - ✅ Responsive 3-column grid (mobile: 1 column)
8
+ - ✅ Article cards with image, date, title, excerpt
9
+ - ✅ Hover animations & transitions
10
+ - ✅ Framework-agnostic event handlers
11
+ - ✅ Customizable translations
12
+ - ✅ Optional image resolver
13
+ - ✅ Fallback placeholder for articles without images
14
+ - ✅ View all button with custom click handler
15
+
16
+ ## Usage
17
+
18
+ ```svelte
19
+ <script>
20
+ import { ArticlesGrid } from '@urga-panel/urPanels-ui-pack/sections';
21
+
22
+ const articles = [
23
+ {
24
+ slug: 'article-1',
25
+ title: 'Article Title',
26
+ date: '2024-01-15',
27
+ featuredImage: '/images/article1.jpg',
28
+ summary: 'Article summary text...',
29
+ },
30
+ // ... more articles
31
+ ];
32
+
33
+ const translations = {
34
+ articlesLabel: 'ARTICLES',
35
+ title: 'Latest Articles',
36
+ description: 'Read our latest legal insights and updates',
37
+ readMore: 'Read More',
38
+ viewAll: 'View All Articles'
39
+ };
40
+
41
+ function handleArticleClick(slug: string) {
42
+ // Navigate to article detail page
43
+ window.location.href = `/articles/${slug}`;
44
+ }
45
+
46
+ function handleViewAllClick() {
47
+ // Navigate to articles list page
48
+ window.location.href = '/articles';
49
+ }
50
+ </script>
51
+
52
+ <ArticlesGrid
53
+ {articles}
54
+ {translations}
55
+ locale="en"
56
+ onArticleClick={handleArticleClick}
57
+ onViewAllClick={handleViewAllClick}
58
+ />
59
+ ```
60
+
61
+ ## Props
62
+
63
+ ### `articles` (required)
64
+ Type: `Article[]`
65
+
66
+ Array of article objects:
67
+ ```typescript
68
+ interface Article {
69
+ slug: string; // Unique identifier
70
+ title: string; // Article title
71
+ date?: string; // ISO date string (e.g., '2024-01-15')
72
+ featuredImage?: string; // Primary image URL
73
+ images?: string[]; // Fallback images array
74
+ summary?: string; // Article summary/excerpt
75
+ header?: string; // Fallback excerpt source
76
+ content?: string; // Fallback excerpt source (HTML stripped)
77
+ }
78
+ ```
79
+
80
+ ### `translations` (required)
81
+ Type: `object`
82
+
83
+ Localized text content:
84
+ ```typescript
85
+ {
86
+ articlesLabel: string; // Small label above title
87
+ title: string; // Main section heading
88
+ description: string; // Subtitle/description
89
+ readMore: string; // "Read More" link text
90
+ viewAll: string; // "View All" button text
91
+ }
92
+ ```
93
+
94
+ ### `locale` (optional)
95
+ Type: `string`
96
+ Default: `'tr'`
97
+
98
+ Locale for date formatting (`'tr'` or `'en'`).
99
+
100
+ ### `onArticleClick` (optional)
101
+ Type: `(slug: string) => void`
102
+
103
+ Click handler for article cards and "Read More" links.
104
+
105
+ ### `onViewAllClick` (optional)
106
+ Type: `() => void`
107
+
108
+ Click handler for "View All Articles" button.
109
+
110
+ ### `imageResolver` (optional)
111
+ Type: `(path: string) => string`
112
+ Default: `(path) => path`
113
+
114
+ Function to resolve/transform image paths (e.g., CDN URLs).
115
+
116
+ ## Examples
117
+
118
+ ### With SvelteKit
119
+
120
+ ```svelte
121
+ <script lang="ts">
122
+ import { ArticlesGrid } from '@urga-panel/urPanels-ui-pack/sections';
123
+ import { goto } from '$app/navigation';
124
+ import { localizedPath, locale, t } from '$lib/i18n';
125
+
126
+ export let data;
127
+
128
+ const translations = {
129
+ articlesLabel: $t('nav.articles'),
130
+ title: $t('home.articles.title'),
131
+ description: $t('home.articles.description'),
132
+ readMore: $t('articles.readMore'),
133
+ viewAll: $t('home.articles.viewAll')
134
+ };
135
+
136
+ function handleArticleClick(slug: string) {
137
+ goto(localizedPath(`/articles/${slug}`, $locale));
138
+ }
139
+
140
+ function handleViewAllClick() {
141
+ goto(localizedPath('/articles', $locale));
142
+ }
143
+ </script>
144
+
145
+ <ArticlesGrid
146
+ articles={data.featuredBlogs}
147
+ {translations}
148
+ locale={$locale}
149
+ onArticleClick={handleArticleClick}
150
+ onViewAllClick={handleViewAllClick}
151
+ />
152
+ ```
153
+
154
+ ### With Custom Image Resolver
155
+
156
+ ```svelte
157
+ <script>
158
+ const imageResolver = (path) => {
159
+ // Add CDN prefix
160
+ if (path.startsWith('/')) {
161
+ return `https://cdn.example.com${path}`;
162
+ }
163
+ return path;
164
+ };
165
+ </script>
166
+
167
+ <ArticlesGrid
168
+ {articles}
169
+ {translations}
170
+ {imageResolver}
171
+ />
172
+ ```
173
+
174
+ ### Turkish Locale
175
+
176
+ ```svelte
177
+ <script>
178
+ const translationsTr = {
179
+ articlesLabel: 'MAKALELER',
180
+ title: 'Son Makaleler',
181
+ description: 'En güncel hukuki içeriklerimizi okuyun',
182
+ readMore: 'Devamını Oku',
183
+ viewAll: 'Tüm Makaleleri Görüntüle'
184
+ };
185
+ </script>
186
+
187
+ <ArticlesGrid
188
+ {articles}
189
+ translations={translationsTr}
190
+ locale="tr"
191
+ />
192
+ ```
193
+
194
+ ## Styling
195
+
196
+ Component uses Tailwind-like utility classes. Includes scoped CSS with fallback primary color variables:
197
+
198
+ ```css
199
+ --primary-50: #fef5e7;
200
+ --primary-100: #fce8c4;
201
+ --primary-300: #f5c76e;
202
+ --primary-600: #d6bb6d;
203
+ --primary-700: #c9a858;
204
+ ```
205
+
206
+ Override by defining these CSS variables in your parent component or global styles.
207
+
208
+ ## Layout
209
+
210
+ - **Grid**: 1 column (mobile), 3 columns (md+)
211
+ - **Card Aspect Ratio**: 16:10 for images
212
+ - **Max Width**: 1280px (7xl container)
213
+ - **Spacing**: py-20 section, gap-8 grid
214
+
215
+ ## Accessibility
216
+
217
+ - Semantic `<article>` elements
218
+ - Proper heading hierarchy
219
+ - Alt text on images
220
+ - SVG icons with proper viewBox
221
+ - Keyboard-friendly links
222
+
223
+ ## Browser Support
224
+
225
+ Works in all modern browsers with CSS Grid and Flexbox support.
226
+
227
+ ## Version
228
+
229
+ Component extracted from av-talha-web (January 2025).
@@ -0,0 +1,2 @@
1
+ export { default as ArticlesGrid } from './ArticlesGrid.svelte';
2
+ export type { Article } from './ArticlesGrid.svelte';
@@ -0,0 +1 @@
1
+ export { default as ArticlesGrid } from './ArticlesGrid.svelte';
@@ -0,0 +1,118 @@
1
+ <script lang="ts">
2
+ /**
3
+ * FeaturedGalleryGrid Component - Framework-agnostic gallery grid
4
+ * Extracted from turk-cin-dernek-website
5
+ * Layout: Large featured image on left, 3 smaller images stacked on right
6
+ */
7
+
8
+ export interface GalleryItem {
9
+ image: string;
10
+ alt: string;
11
+ text?: string;
12
+ href?: string;
13
+ }
14
+
15
+ interface Props {
16
+ featuredItem: GalleryItem;
17
+ smallItems: GalleryItem[];
18
+ onItemClick?: (href: string) => void;
19
+ imageResolver?: (path: string) => string;
20
+ placeholderImage?: string;
21
+ }
22
+
23
+ let {
24
+ featuredItem,
25
+ smallItems = [],
26
+ onItemClick,
27
+ imageResolver = (path: string) => path,
28
+ placeholderImage = 'https://placehold.co/800x500'
29
+ }: Props = $props();
30
+
31
+ const handleItemClick = (e: MouseEvent, href?: string) => {
32
+ if (onItemClick && href) {
33
+ e.preventDefault();
34
+ onItemClick(href);
35
+ }
36
+ };
37
+
38
+ const resolveImage = (image?: string): string => {
39
+ if (!image || !image.trim()) {
40
+ return placeholderImage;
41
+ }
42
+ return imageResolver(image);
43
+ };
44
+ </script>
45
+
46
+ <div class="container mx-auto">
47
+ <div class="mb-12 grid grid-cols-1 gap-y-4 md:grid-cols-3 md:gap-4">
48
+ <!-- Sol Büyük Resim (Featured) -->
49
+ <a
50
+ class="group relative col-span-2 block cursor-pointer overflow-hidden rounded-lg shadow-md max-h-[600px]"
51
+ href={featuredItem.href ?? '/'}
52
+ onclick={(e) => handleItemClick(e, featuredItem.href)}
53
+ >
54
+ <img
55
+ src={resolveImage(featuredItem.image)}
56
+ alt={featuredItem.alt}
57
+ class="h-auto w-full object-cover transition-transform duration-300 group-hover:scale-[1.01]"
58
+ />
59
+ <div
60
+ class="absolute inset-0 bg-gradient-to-t from-black/50 via-black/20 to-transparent"
61
+ ></div>
62
+ {#if featuredItem.text}
63
+ <div class="pointer-events-none absolute inset-x-0 bottom-0 p-4 text-white md:p-6">
64
+ <h3 class="text-lg font-semibold drop-shadow md:text-2xl">
65
+ {featuredItem.text}
66
+ </h3>
67
+ </div>
68
+ {/if}
69
+ </a>
70
+
71
+ <!-- Sağdaki 3 Küçük Resim -->
72
+ <div class="flex flex-col justify-between gap-4 max-h-[600px]">
73
+ {#each smallItems.slice(0, 3) as item}
74
+ <a
75
+ class="group relative block max-h-[200px] cursor-pointer overflow-hidden rounded-lg shadow-md"
76
+ href={item.href ?? '/'}
77
+ onclick={(e) => handleItemClick(e, item.href)}
78
+ >
79
+ <img
80
+ src={resolveImage(item.image)}
81
+ alt={item.alt}
82
+ class="h-auto w-full object-cover transition-transform duration-300 group-hover:scale-105"
83
+ />
84
+ <div
85
+ class="absolute inset-0 bg-gradient-to-t from-black/50 via-black/20 to-transparent"
86
+ ></div>
87
+ {#if item.text}
88
+ <div class="pointer-events-none absolute inset-x-0 bottom-0 p-3 text-white md:p-4">
89
+ <h4 class="text-base font-semibold drop-shadow md:text-lg">{item.text}</h4>
90
+ </div>
91
+ {/if}
92
+ </a>
93
+ {/each}
94
+ </div>
95
+ </div>
96
+ </div>
97
+
98
+ <style>
99
+ /* Container max-width */
100
+ .container {
101
+ max-width: 1280px;
102
+ }
103
+
104
+ /* Ensure proper aspect ratio and object-fit */
105
+ img {
106
+ display: block;
107
+ }
108
+
109
+ /* Drop shadow utility for text */
110
+ .drop-shadow {
111
+ filter: drop-shadow(0 2px 4px rgba(0, 0, 0, 0.5));
112
+ }
113
+
114
+ /* Pointer events none utility */
115
+ .pointer-events-none {
116
+ pointer-events: none;
117
+ }
118
+ </style>
@@ -0,0 +1,21 @@
1
+ /**
2
+ * FeaturedGalleryGrid Component - Framework-agnostic gallery grid
3
+ * Extracted from turk-cin-dernek-website
4
+ * Layout: Large featured image on left, 3 smaller images stacked on right
5
+ */
6
+ export interface GalleryItem {
7
+ image: string;
8
+ alt: string;
9
+ text?: string;
10
+ href?: string;
11
+ }
12
+ interface Props {
13
+ featuredItem: GalleryItem;
14
+ smallItems: GalleryItem[];
15
+ onItemClick?: (href: string) => void;
16
+ imageResolver?: (path: string) => string;
17
+ placeholderImage?: string;
18
+ }
19
+ declare const FeaturedGalleryGrid: import("svelte").Component<Props, {}, "">;
20
+ type FeaturedGalleryGrid = ReturnType<typeof FeaturedGalleryGrid>;
21
+ export default FeaturedGalleryGrid;