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,270 @@
1
+ # FeaturedGalleryGrid Component
2
+
3
+ Framework-agnostic featured gallery grid component extracted from turk-cin-dernek-website project.
4
+
5
+ ## Features
6
+
7
+ - ✅ Asymmetric grid layout (2:1 ratio)
8
+ - ✅ Large featured image on left
9
+ - ✅ 3 smaller images stacked on right
10
+ - ✅ Responsive design (stacks on mobile)
11
+ - ✅ Hover scale animations
12
+ - ✅ Image overlays with gradient
13
+ - ✅ Text labels on images
14
+ - ✅ Framework-agnostic click handlers
15
+ - ✅ Custom image resolver support
16
+ - ✅ Placeholder fallback images
17
+
18
+ ## Layout Preview
19
+
20
+ ```
21
+ ┌─────────────────┬────────┐
22
+ │ │ IMG1 │
23
+ │ FEATURED ├────────┤
24
+ │ IMAGE │ IMG2 │
25
+ │ (Large) ├────────┤
26
+ │ │ IMG3 │
27
+ └─────────────────┴────────┘
28
+ ```
29
+
30
+ ## Usage
31
+
32
+ ```svelte
33
+ <script>
34
+ import { FeaturedGalleryGrid } from '@urga-panel/urPanels-ui-pack/sections';
35
+
36
+ const featuredItem = {
37
+ image: '/images/featured.jpg',
38
+ alt: 'Featured Event',
39
+ text: 'Ambassador Visit to China',
40
+ href: '/events/ambassador-visit'
41
+ };
42
+
43
+ const smallItems = [
44
+ {
45
+ image: '/images/event1.jpg',
46
+ alt: 'Chinese Dance',
47
+ text: 'Chinese Dance Performance',
48
+ href: '/events/dance'
49
+ },
50
+ {
51
+ image: '/images/event2.jpg',
52
+ alt: 'MADO Representative',
53
+ text: 'MADO Regional Representative',
54
+ href: '/events/mado'
55
+ },
56
+ {
57
+ image: '/images/event3.jpg',
58
+ alt: 'University Visit',
59
+ text: 'Northwest University',
60
+ href: '/events/university'
61
+ }
62
+ ];
63
+
64
+ function handleItemClick(href: string) {
65
+ window.location.href = href;
66
+ }
67
+ </script>
68
+
69
+ <FeaturedGalleryGrid
70
+ {featuredItem}
71
+ {smallItems}
72
+ onItemClick={handleItemClick}
73
+ />
74
+ ```
75
+
76
+ ## Props
77
+
78
+ ### `featuredItem` (required)
79
+ Type: `GalleryItem`
80
+
81
+ Large featured image on the left side:
82
+ ```typescript
83
+ interface GalleryItem {
84
+ image: string; // Image URL
85
+ alt: string; // Alt text for accessibility
86
+ text?: string; // Optional overlay text
87
+ href?: string; // Optional link destination
88
+ }
89
+ ```
90
+
91
+ ### `smallItems` (required)
92
+ Type: `GalleryItem[]`
93
+
94
+ Array of 3 smaller images for the right column. If more than 3 items provided, only first 3 are displayed.
95
+
96
+ ### `onItemClick` (optional)
97
+ Type: `(href: string) => void`
98
+
99
+ Click handler for all gallery items. Receives the `href` from the clicked item.
100
+
101
+ ### `imageResolver` (optional)
102
+ Type: `(path: string) => string`
103
+ Default: `(path) => path`
104
+
105
+ Function to transform/resolve image paths (e.g., add CDN prefix).
106
+
107
+ ### `placeholderImage` (optional)
108
+ Type: `string`
109
+ Default: `'https://placehold.co/800x500'`
110
+
111
+ Fallback image URL when item image is empty or invalid.
112
+
113
+ ## Examples
114
+
115
+ ### With SvelteKit Navigation
116
+
117
+ ```svelte
118
+ <script lang="ts">
119
+ import { FeaturedGalleryGrid } from '@urga-panel/urPanels-ui-pack/sections';
120
+ import { goto } from '$app/navigation';
121
+ import { localizedPath, locale } from '$lib/i18n';
122
+
123
+ export let data;
124
+
125
+ const featuredItem = {
126
+ image: data.indexData?.gallery?.left?.image ?? '',
127
+ alt: data.indexData?.gallery?.left?.alt ?? 'Featured',
128
+ text: data.indexData?.gallery?.left?.text,
129
+ href: data.indexData?.gallery?.left?.href
130
+ };
131
+
132
+ const smallItems = data.indexData?.gallery?.right ?? [];
133
+
134
+ function handleItemClick(href: string) {
135
+ if (href.startsWith('http')) {
136
+ window.location.href = href;
137
+ } else {
138
+ goto(localizedPath(href, $locale));
139
+ }
140
+ }
141
+ </script>
142
+
143
+ <FeaturedGalleryGrid
144
+ {featuredItem}
145
+ {smallItems}
146
+ onItemClick={handleItemClick}
147
+ />
148
+ ```
149
+
150
+ ### With CDN Image Resolver
151
+
152
+ ```svelte
153
+ <script>
154
+ const imageResolver = (path) => {
155
+ if (!path) return 'https://placehold.co/800x500';
156
+ if (path.startsWith('http')) return path;
157
+ return `https://cdn.example.com${path}`;
158
+ };
159
+ </script>
160
+
161
+ <FeaturedGalleryGrid
162
+ {featuredItem}
163
+ {smallItems}
164
+ {imageResolver}
165
+ />
166
+ ```
167
+
168
+ ### With Custom Placeholder
169
+
170
+ ```svelte
171
+ <FeaturedGalleryGrid
172
+ {featuredItem}
173
+ {smallItems}
174
+ placeholderImage="/default-event-image.jpg"
175
+ />
176
+ ```
177
+
178
+ ### Static Content (No Click Handlers)
179
+
180
+ ```svelte
181
+ <script>
182
+ const featuredItem = {
183
+ image: '/gallery/main.jpg',
184
+ alt: 'Main Gallery Image',
185
+ text: 'Photo Gallery 2024'
186
+ };
187
+
188
+ const smallItems = [
189
+ { image: '/gallery/1.jpg', alt: 'Gallery 1' },
190
+ { image: '/gallery/2.jpg', alt: 'Gallery 2' },
191
+ { image: '/gallery/3.jpg', alt: 'Gallery 3' }
192
+ ];
193
+ </script>
194
+
195
+ <!-- Without onItemClick, items use default href behavior -->
196
+ <FeaturedGalleryGrid {featuredItem} {smallItems} />
197
+ ```
198
+
199
+ ## Styling
200
+
201
+ Component uses Tailwind-like utility classes with scoped CSS fallbacks. Key styles:
202
+
203
+ - **Grid**: 1 column (mobile), 3 columns (md+)
204
+ - **Featured Image**: Spans 2 columns, max-height 600px
205
+ - **Small Images**: Max-height 200px each
206
+ - **Container**: Max-width 1280px
207
+ - **Spacing**: 4px gap on desktop, 16px on mobile
208
+ - **Hover Effects**:
209
+ - Featured: scale(1.01)
210
+ - Small: scale(1.05)
211
+
212
+ ## Layout Behavior
213
+
214
+ ### Desktop (md+)
215
+ ```
216
+ ┌──────────────────┬─────────┐
217
+ │ │ Item1 │
218
+ │ Featured ├─────────┤
219
+ │ (col-span-2) │ Item2 │
220
+ │ ├─────────┤
221
+ │ │ Item3 │
222
+ └──────────────────┴─────────┘
223
+ ```
224
+
225
+ ### Mobile
226
+ ```
227
+ ┌──────────────────┐
228
+ │ Featured │
229
+ ├──────────────────┤
230
+ │ Item 1 │
231
+ ├──────────────────┤
232
+ │ Item 2 │
233
+ ├──────────────────┤
234
+ │ Item 3 │
235
+ └──────────────────┘
236
+ ```
237
+
238
+ ## Image Overlay
239
+
240
+ All images have:
241
+ - Gradient overlay: `from-black/50 via-black/20 to-transparent`
242
+ - Text positioned at bottom with padding
243
+ - White text with drop-shadow for readability
244
+ - Pointer-events disabled on text to allow image clicks
245
+
246
+ ## Accessibility
247
+
248
+ - ✅ Semantic `<a>` elements with proper `href`
249
+ - ✅ Alt text on all images
250
+ - ✅ Keyboard navigation support
251
+ - ✅ Proper heading hierarchy (`<h3>` for featured, `<h4>` for small)
252
+ - ✅ Visual hover feedback
253
+
254
+ ## Browser Support
255
+
256
+ Works in all modern browsers with CSS Grid and Flexbox support.
257
+
258
+ ## Max Items
259
+
260
+ Component automatically limits `smallItems` to first 3 items using `.slice(0, 3)`.
261
+
262
+ ## Performance
263
+
264
+ - Images lazy-load by default (browser native)
265
+ - Transform animations use GPU acceleration
266
+ - Gradient overlays use CSS, not extra DOM elements
267
+
268
+ ## Version
269
+
270
+ Component extracted from turk-cin-dernek-website (January 2025).
@@ -0,0 +1,2 @@
1
+ export { default as FeaturedGalleryGrid } from './FeaturedGalleryGrid.svelte';
2
+ export type { GalleryItem } from './FeaturedGalleryGrid.svelte';
@@ -0,0 +1 @@
1
+ export { default as FeaturedGalleryGrid } from './FeaturedGalleryGrid.svelte';
@@ -0,0 +1,318 @@
1
+ <script lang="ts">
2
+ import emblaCarouselSvelte from 'embla-carousel-svelte';
3
+ import Autoplay from 'embla-carousel-autoplay';
4
+
5
+ interface HeroItem {
6
+ id?: string;
7
+ title: string;
8
+ summary?: string;
9
+ slug?: string;
10
+ featuredImage?: string;
11
+ images?: string[];
12
+ type?: string;
13
+ content?: string;
14
+ customStyles?: string; // CSS için ayrı field
15
+ }
16
+
17
+ interface Props {
18
+ heroItems?: HeroItem[];
19
+ onSlugClick?: (slug: string) => void;
20
+ imageResolver?: (url: string | undefined) => string;
21
+ locale?: string;
22
+ translations?: {
23
+ readMore: string;
24
+ };
25
+ }
26
+
27
+ let {
28
+ heroItems = [],
29
+ onSlugClick,
30
+ imageResolver = (url) => url || '',
31
+ locale = 'tr',
32
+ translations = { readMore: 'Devamını Oku' }
33
+ }: Props = $props();
34
+
35
+ let emblaApi: any = $state(null);
36
+ let currentSlide = $state(0);
37
+ let totalSlides = $derived(heroItems.length);
38
+
39
+ // Autoplay plugin options
40
+ const autoplayOptions = {
41
+ delay: 4000,
42
+ stopOnInteraction: false,
43
+ stopOnMouseEnter: true,
44
+ };
45
+
46
+ function onInit(event: CustomEvent): void {
47
+ emblaApi = event.detail;
48
+ emblaApi.on('select', () => {
49
+ currentSlide = emblaApi.selectedScrollSnap();
50
+ });
51
+ }
52
+
53
+ function goToSlide(index: number): void {
54
+ if (emblaApi) {
55
+ emblaApi.scrollTo(index);
56
+ }
57
+ }
58
+
59
+ function handleSlugClick(slug: string | undefined, e: MouseEvent): void {
60
+ if (slug && onSlugClick) {
61
+ e.preventDefault();
62
+ onSlugClick(slug);
63
+ }
64
+ }
65
+
66
+ // HTML content'ten style tag'lerini ayıklayıp temizle
67
+ function extractAndCleanHTML(htmlContent: string): { html: string; styles: string } {
68
+ if (!htmlContent) return { html: '', styles: '' };
69
+
70
+ const styleRegex = /<style[^>]*>([\s\S]*?)<\/style>/gi;
71
+ let styles = '';
72
+ let matches;
73
+
74
+ // Tüm style tag'lerini bul ve topla
75
+ while ((matches = styleRegex.exec(htmlContent)) !== null) {
76
+ styles += matches[1] + '\n';
77
+ }
78
+
79
+ // HTML'den style tag'lerini kaldır
80
+ const cleanHTML = htmlContent.replace(styleRegex, '');
81
+
82
+ return { html: cleanHTML, styles };
83
+ }
84
+
85
+ // Style'ları slide-specific yap (scope'la)
86
+ function scopeStyles(styles: string, slideIndex: number): string {
87
+ if (!styles) return '';
88
+
89
+ const scopeClass = `.hero-slide-${slideIndex}`;
90
+ let result = '';
91
+
92
+ // Media query pattern'i
93
+ const mediaQueryRegex = /@media[^{]+\{([\s\S]+?)\}\s*\}/g;
94
+ let lastIndex = 0;
95
+ let match;
96
+
97
+ // Media query'leri bul ve işle
98
+ while ((match = mediaQueryRegex.exec(styles)) !== null) {
99
+ // Media query'den önceki normal kuralları ekle
100
+ const beforeMedia = styles.substring(lastIndex, match.index);
101
+ if (beforeMedia.trim()) {
102
+ result += scopeNormalCSS(beforeMedia, scopeClass);
103
+ }
104
+
105
+ // Media query'yi işle
106
+ const mediaRule = match[0];
107
+ const mediaCondition = mediaRule.substring(0, mediaRule.indexOf('{') + 1);
108
+ const mediaContent = match[1];
109
+
110
+ // Media query içindeki kuralları scope'la
111
+ const scopedMediaContent = scopeNormalCSS(mediaContent, scopeClass);
112
+ result += `${mediaCondition}\n${scopedMediaContent}\n}\n`;
113
+
114
+ lastIndex = mediaQueryRegex.lastIndex;
115
+ }
116
+
117
+ // Kalan normal kuralları ekle
118
+ const afterMedia = styles.substring(lastIndex);
119
+ if (afterMedia.trim()) {
120
+ result += scopeNormalCSS(afterMedia, scopeClass);
121
+ }
122
+
123
+ return result;
124
+ }
125
+
126
+ // Normal CSS kurallarını scope'la
127
+ function scopeNormalCSS(css: string, scopeClass: string): string {
128
+ if (!css.trim()) return '';
129
+
130
+ // Satır satır işle
131
+ const lines = css.split('\n');
132
+ let result = '';
133
+ let inRule = false;
134
+ let currentSelector = '';
135
+ let currentRules = '';
136
+
137
+ for (let line of lines) {
138
+ const trimmed = line.trim();
139
+
140
+ // Boş satırları atla
141
+ if (!trimmed) continue;
142
+
143
+ // Selector başlangıcı
144
+ if (trimmed.includes('{')) {
145
+ const parts = trimmed.split('{');
146
+ currentSelector = parts[0].trim();
147
+ currentRules = parts[1] || '';
148
+ inRule = true;
149
+
150
+ // @ ile başlamıyorsa scope'la
151
+ if (!currentSelector.startsWith('@')) {
152
+ const scopedSelector = `${scopeClass} ${currentSelector}`;
153
+ result += `${scopedSelector} { ${currentRules}\n`;
154
+ } else {
155
+ result += `${currentSelector} { ${currentRules}\n`;
156
+ }
157
+ }
158
+ // Kural devam ediyor
159
+ else if (inRule && !trimmed.includes('}')) {
160
+ result += `${trimmed}\n`;
161
+ }
162
+ // Kural bitiyor
163
+ else if (trimmed.includes('}')) {
164
+ const beforeClose = trimmed.split('}')[0];
165
+ if (beforeClose.trim()) {
166
+ result += `${beforeClose}\n`;
167
+ }
168
+ result += '}\n';
169
+ inRule = false;
170
+ currentSelector = '';
171
+ currentRules = '';
172
+ }
173
+ }
174
+
175
+ return result;
176
+ }
177
+
178
+ // Her item için style ve HTML'i hazırla
179
+ let processedItems = $derived(
180
+ heroItems.map((item, index) => {
181
+ if (item.type === 'html' && item.content) {
182
+ const { html, styles } = extractAndCleanHTML(item.content);
183
+ return {
184
+ ...item,
185
+ cleanContent: html,
186
+ extractedStyles: scopeStyles(item.customStyles || styles, index)
187
+ };
188
+ }
189
+ return {
190
+ ...item,
191
+ cleanContent: item.content,
192
+ extractedStyles: item.customStyles ? scopeStyles(item.customStyles, index) : ''
193
+ };
194
+ })
195
+ );
196
+
197
+ // Tüm slide'ların style'larını birleştir
198
+ let allStyles = $derived(
199
+ processedItems
200
+ .map(item => item.extractedStyles)
201
+ .filter(Boolean)
202
+ .join('\n')
203
+ );
204
+ </script>
205
+
206
+ <!-- Style'ları head'e ekle -->
207
+ <svelte:head>
208
+ {#if allStyles}
209
+ {@html `<style>${allStyles}</style>`}
210
+ {/if}
211
+ </svelte:head>
212
+
213
+ <section class="relative text-white overflow-hidden">
214
+ <div
215
+ class="embla"
216
+ use:emblaCarouselSvelte={{
217
+ options: { loop: true },
218
+ plugins: [Autoplay(autoplayOptions)]
219
+ }}
220
+ onemblaInit={onInit}
221
+ >
222
+ <div class="embla__container">
223
+ <!-- Dynamic Slides from heroItems -->
224
+ {#each processedItems as item, index}
225
+ <div class="embla__slide hero-slide-{index} relative min-h-[600px] flex items-center">
226
+ <div class="absolute inset-0 overflow-hidden">
227
+ {#if item.featuredImage || (item.images && item.images[0])}
228
+ <img
229
+ src={imageResolver(item.featuredImage || item.images?.[0])}
230
+ alt={item.title}
231
+ class="w-full h-full object-cover"
232
+ />
233
+ {:else}
234
+ <div class="w-full h-full bg-gradient-to-br from-gray-800 to-gray-900"></div>
235
+ {/if}
236
+ <div class="absolute inset-0 bg-gradient-to-b from-gray-900/60 via-gray-900/50 to-gray-900/60"></div>
237
+ </div>
238
+
239
+ {#if item.type === 'html'}
240
+ <!-- HTML Content (full width) -->
241
+ <div class="hero-html-content">
242
+ {@html item.cleanContent}
243
+ </div>
244
+ {:else}
245
+ <!-- Standard Content -->
246
+ <div class="container mx-auto px-4 relative z-10">
247
+ <div class="max-w-4xl mx-auto text-center">
248
+ <h2 class="text-4xl md:text-6xl font-bold mb-6">
249
+ {item.title}
250
+ </h2>
251
+ {#if item.summary}
252
+ <p class="text-xl md:text-2xl text-gray-200 mb-8">
253
+ {item.summary}
254
+ </p>
255
+ {/if}
256
+ {#if item.slug}
257
+ <a
258
+ href={onSlugClick ? '#' : `/makaleler/${item.slug}`}
259
+ onclick={(e) => handleSlugClick(item.slug, e)}
260
+ class="inline-flex items-center bg-white text-primary-900 px-8 py-4 rounded-lg hover:bg-primary-50 transition-colors font-semibold text-lg"
261
+ >
262
+ {translations.readMore}
263
+ <svg class="w-5 h-5 ml-2" fill="none" stroke="currentColor" viewBox="0 0 24 24">
264
+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 5l7 7-7 7" />
265
+ </svg>
266
+ </a>
267
+ {/if}
268
+ </div>
269
+ </div>
270
+ {/if}
271
+ </div>
272
+ {/each}
273
+ </div>
274
+ </div>
275
+
276
+ <!-- Navigation Dots -->
277
+ {#if totalSlides > 1}
278
+ <div class="absolute bottom-8 left-1/2 -translate-x-1/2 z-20 flex gap-3">
279
+ {#each Array(totalSlides) as _, index}
280
+ <button
281
+ type="button"
282
+ onclick={() => goToSlide(index)}
283
+ class="w-3 h-3 rounded-full transition-all duration-300 {currentSlide === index
284
+ ? 'bg-white scale-125'
285
+ : 'bg-white/50 hover:bg-white/75'}"
286
+ aria-label="Slide {index + 1}'e git"
287
+ ></button>
288
+ {/each}
289
+ </div>
290
+ {/if}
291
+ </section>
292
+
293
+ <style>
294
+ .embla {
295
+ overflow: hidden;
296
+ }
297
+
298
+ .embla__container {
299
+ display: flex;
300
+ }
301
+
302
+ .embla__slide {
303
+ flex: 0 0 100%;
304
+ min-width: 0;
305
+ }
306
+
307
+ .hero-html-content :global(*) {
308
+ /* HTML içeriği için global stiller zaten inline gelecek */
309
+ }
310
+
311
+ .hero-html-content {
312
+ width: 100%;
313
+ }
314
+
315
+ .hero-html-content :global(> *) {
316
+ width: 100%;
317
+ }
318
+ </style>
@@ -0,0 +1,23 @@
1
+ interface HeroItem {
2
+ id?: string;
3
+ title: string;
4
+ summary?: string;
5
+ slug?: string;
6
+ featuredImage?: string;
7
+ images?: string[];
8
+ type?: string;
9
+ content?: string;
10
+ customStyles?: string;
11
+ }
12
+ interface Props {
13
+ heroItems?: HeroItem[];
14
+ onSlugClick?: (slug: string) => void;
15
+ imageResolver?: (url: string | undefined) => string;
16
+ locale?: string;
17
+ translations?: {
18
+ readMore: string;
19
+ };
20
+ }
21
+ declare const HeroCarousel: import("svelte").Component<Props, {}, "">;
22
+ type HeroCarousel = ReturnType<typeof HeroCarousel>;
23
+ export default HeroCarousel;
@@ -0,0 +1 @@
1
+ export { default as HeroCarousel } from './HeroCarousel.svelte';
@@ -0,0 +1 @@
1
+ export { default as HeroCarousel } from './HeroCarousel.svelte';
@@ -0,0 +1,5 @@
1
+ export { HeroCarousel } from './HeroCarousel';
2
+ export { ArticlesGrid } from './ArticlesGrid';
3
+ export type { Article } from './ArticlesGrid';
4
+ export { FeaturedGalleryGrid } from './FeaturedGalleryGrid';
5
+ export type { GalleryItem } from './FeaturedGalleryGrid';
@@ -0,0 +1,3 @@
1
+ export { HeroCarousel } from './HeroCarousel';
2
+ export { ArticlesGrid } from './ArticlesGrid';
3
+ export { FeaturedGalleryGrid } from './FeaturedGalleryGrid';
@@ -0,0 +1,37 @@
1
+ /**
2
+ * Translations Helper for urpanels-template-kurs
3
+ *
4
+ * Usage:
5
+ * 1. Import in view: import { t } from '../../utils/translations.svelte';
6
+ * 2. Use t('students.title') to get translations
7
+ *
8
+ * Note: Translations are loaded by layout and stored in window.__urpanels_translations
9
+ * This module reads from window for cross-module compatibility
10
+ */
11
+ declare global {
12
+ interface Window {
13
+ __urpanels_translations: Record<string, any>;
14
+ __urpanels_language: string;
15
+ __urpanels_translations_loaded: boolean;
16
+ }
17
+ }
18
+ /**
19
+ * Get translation by key
20
+ * Supports nested keys with dot notation (e.g., 'students.title')
21
+ *
22
+ * @param key - Translation key (dot notation for nested)
23
+ * @param fallback - Fallback value if key not found (defaults to key itself)
24
+ * @param params - Optional parameters for interpolation (e.g., { count: 5 })
25
+ * @returns Translated string or fallback
26
+ *
27
+ * @example
28
+ * t('common.save') // Returns "Kaydet" or "Save"
29
+ * t('students.title') // Returns "Öğrenciler" or "Students"
30
+ * t('validation.minLength', undefined, { min: 3 }) // Returns "En az 3 karakter olmalıdır"
31
+ */
32
+ export declare function t(key: string, fallback?: string, params?: Record<string, any>): string;
33
+ export declare function getCurrentLanguage(): string;
34
+ export declare function isTranslationsLoaded(): boolean;
35
+ export declare function getAllTranslations(): Record<string, any>;
36
+ export declare function initTranslations(_apiFront?: any, _settings?: any): Promise<void>;
37
+ export declare function changeLanguage(_apiFront?: any, _language?: string): Promise<void>;