// Product, content, and auth data for the storefront CMS. const IMG = (id, w = 800) => `https://images.unsplash.com/${id}?auto=format&fit=crop&w=${w}&q=80`; const PEXVID = (id, file) => `https://videos.pexels.com/video-files/${id}/${id}-${file}.mp4`; const PEXPOSTER = (id) => `https://images.pexels.com/videos/${id}/pexels-photo-${id}.jpeg?auto=compress&cs=tinysrgb&w=1400`; // Reliable editorial fallback (the old local file 404'd on deploy). Editable in admin. const LOCAL_EDITORIAL = IMG('photo-1469334031218-e382a71b716b', 900); const SW = { blush: { name: 'Blush', hex: '#F6D6DA' }, rose: { name: 'Rose', hex: '#B86A78' }, ivory: { name: 'Ivory', hex: '#FFF8F5' }, champagne: { name: 'Champagne', hex: '#F2E3DC' }, deep: { name: 'Cocoa', hex: '#4A2D33' }, sand: { name: 'Sand', hex: '#D8C3A8' }, sage: { name: 'Sage', hex: '#B6C2A7' }, black: { name: 'Onyx', hex: '#1A1414' }, }; const SIZES = ['XS', 'S', 'M', 'L', 'XL']; const DEFAULT_SITE_DATA = { settings: { brandName: 'House of Sheylas', brandMark: 'HOS', brandTagline: 'HOUSE OF SHEYLAS', tagline: 'Quietly elegant pieces, curated for women who dress for themselves.', supportEmail: 'care@houseofsheylas.com', pressEmail: 'press@houseofsheylas.com', phone: '+1 (438) 555-0148', instagramHandle: '@houseofsheylas', instagramUrl: 'https://www.instagram.com/', tiktokUrl: 'https://www.tiktok.com/', facebookUrl: 'https://www.facebook.com/', pinterestUrl: 'https://www.pinterest.com/', copyright: '© 2026 House of Sheylas. Curated with care in Paris.', footerLocation: 'Paris', newsletterCode: 'HOUSE10', newsletterReplyTo: 'care@houseofsheylas.com', adminUsername: 'admin', adminPassword: 'admin123', }, navigation: [ { id: 'home', label: 'Home', href: '#home', public: true }, { id: 'shop', label: 'Shop', href: '#shop', public: true }, { id: 'collections', label: 'Collections', href: '#collections', public: true }, { id: 'about', label: 'About', href: '#about', public: true }, { id: 'contact', label: 'Contact', href: '#contact', public: true }, ], pages: [ { id: 'home', title: 'Home', status: 'live', href: '#home' }, { id: 'shop', title: 'Shop', status: 'live', href: '#shop' }, { id: 'collections', title: 'Collections', status: 'live', href: '#collections' }, { id: 'about', title: 'About', status: 'live', href: '#about' }, { id: 'contact', title: 'Contact', status: 'live', href: '#contact' }, ], hero: { eyebrow: 'Summer · Édition 2026', title: 'Soft elegance', accent: 'for every woman.', description: 'A curated edit of feminine pieces — selected to make you feel confident, graceful and unforgettable.', metaLeft: 'Boutique · Paris · Est. 2025', metaRight: 'N°08 · Summer', primaryCtaLabel: 'Shop new collection', primaryCtaHref: '#shop/new', secondaryCtaLabel: 'View lookbook', secondaryCtaHref: '#collections', featuredProductId: 'na1', featuredLabel: 'Featured', }, story: { eyebrow: 'Our story', title: 'For women who love', accent: 'elegance, confidence,', end: 'and timeless femininity.', body: 'House of Sheylas is a curated boutique, bringing together feminine, elevated pieces — chosen with care for the women who wear them.', imagePrimary: IMG('photo-1496747611176-843222e1e57c', 900), imageSecondary: LOCAL_EDITORIAL, stats: [ { label: 'Launched', value: 'Paris · 2025' }, { label: 'Atelier', value: 'Small-batch pieces' }, { label: 'Where we are', value: 'Paris · Canada · Tunisia' }, ], ctaLabel: 'Discover the house', ctaHref: '#about', }, newsletter: { eyebrow: 'Become a member', title: 'Join the', accent: 'House', description: 'Get early access to new drops, private sales, and styling inspiration delivered with care to your inbox.', successTitle: 'Welcome home.', }, about: { eyebrow: 'The House', title: 'Quietly made,', accent: 'always intentional.', subtitle: 'House of Sheylas is an independent womenswear boutique — a curated edit of feminine, elevated pieces selected for women who dress for themselves.', values: [ { id: '01', title: 'Curated selection', description: 'Every piece is hand-picked. We edit so you don’t have to.', }, { id: '02', title: 'Elevated quality', description: 'Silk, linen, cashmere — fabrics that breathe, drape, and live with you.', }, { id: '03', title: 'Feminine by design', description: 'Soft silhouettes and refined details, chosen for how they make you feel.', }, { id: '04', title: 'A quiet ethos', description: 'No trends, no noise. We select for the woman, not the season.', }, ], }, locations: [ { city: 'Paris', role: 'Studio', note: 'Where it all began — 2025.', }, { city: 'Canada', role: 'Operations', note: 'Serving our North American community.', }, { city: 'Tunisia', role: 'Office', note: 'Part of our team, behind the scenes.', }, ], services: [ { id: 'shipping', title: 'Shipping & Returns', href: '#contact' }, { id: 'tracking', title: 'Order Tracking', href: '#contact' }, { id: 'size-guide', title: 'Size Guide', href: '#contact' }, { id: 'care', title: 'Garment Care', href: '#contact' }, { id: 'contact-us', title: 'Contact Us', href: '#contact' }, ], contact: { eyebrow: 'Contact', title: 'We’d love to', accent: 'hear from you.', subtitle: 'For styling questions, sizing help, press, or quiet hellos. We answer every message within two working days.', responseTime: 'We typically reply within 48h.', topics: [ { id: 'general', label: 'General enquiry' }, { id: 'styling', label: 'Styling help' }, { id: 'order', label: 'Order question' }, { id: 'press', label: 'Press' }, { id: 'wholesale', label: 'Wholesale' }, ], faqs: [ { q: 'Where do you ship?', a: 'We ship worldwide from Paris. Rates calculated at checkout.', }, { q: 'When will I be charged?', a: 'At checkout. Final taxes and duties calculated by destination.', }, { q: 'Do you do exchanges?', a: 'Yes — within 14 days. Reach out to our care team to arrange one.', }, { q: 'Sustainability?', a: 'We curate elevated pieces and favour natural fibres wherever we can. Read more on our About page.', }, ], }, collections: [ { id: 'spring-bloom', name: 'Summer Edit', season: 'SS 2026', pieces: 32, img: IMG('photo-1490481651871-ab68de25d43d', 1000), accent: '#F6D6DA', }, { id: 'soft-noir', name: 'Soft Noir', season: 'AW 2026', pieces: 18, img: IMG('photo-1539008835657-9e8e9680c956', 1000), accent: '#4A2D33', }, { id: 'champagne', name: 'Champagne Hour', season: 'Resort', pieces: 24, img: IMG('photo-1518049362265-d5b2a6b00b37', 1000), accent: '#F2E3DC', }, { id: 'atelier', name: 'Atelier Edit', season: 'Capsule', pieces: 12, img: LOCAL_EDITORIAL, accent: '#B86A78', }, ], categories: [ { id: 'dresses', name: 'Dresses', count: '48 pieces', img: IMG('photo-1539109136881-3be0616acf4b', 700), status: 'live', subcategories: [ { id: 'new', name: 'New In', href: '#shop/new' }, { id: 'bestsellers', name: 'Best Sellers', href: '#shop/bestsellers' }, ], }, { id: 'sets', name: 'Sets', count: '24 pieces', img: IMG('photo-1515886657613-9f3515b0c78f', 700), status: 'live', subcategories: [], }, { id: 'tops', name: 'Tops', count: '36 pieces', img: IMG('photo-1551803091-e20673f15770', 700), status: 'live', subcategories: [], }, { id: 'accessories', name: 'Accessories', count: '52 pieces', img: IMG('photo-1606760227091-3dd870d97f1d', 700), status: 'live', subcategories: [], }, ], products: [ { id: 'na1', name: 'Aurelie Silk Slip Dress', price: 248, category: 'dresses', img: IMG('photo-1566174053879-31528523f8ae', 700), tag: 'New', colors: [SW.blush, SW.champagne, SW.deep], description: 'Cut from feather-light silk satin, this piece drapes effortlessly with a bias-cut silhouette that moves with you.', stock: 24, status: 'live', isNew: true, sizes: SIZES, }, { id: 'na2', name: 'Mireille Pleated Skirt', price: 184, category: 'bottoms', img: IMG('photo-1581338834647-b0fb40704e21', 700), tag: 'New', colors: [SW.ivory, SW.rose, SW.sand], stock: 18, status: 'live', isNew: true, sizes: SIZES, }, { id: 'na3', name: 'Celeste Linen Co-ord', price: 295, category: 'sets', img: IMG('photo-1572804013309-59a88b7e92f1', 700), tag: 'Just in', colors: [SW.champagne, SW.sage], stock: 12, status: 'live', isNew: true, sizes: SIZES, }, { id: 'na4', name: 'Sienna Wrap Blouse', price: 148, category: 'tops', img: IMG('photo-1551163943-3f7053a3b8d8', 700), tag: 'New', colors: [SW.blush, SW.ivory, SW.rose], stock: 28, status: 'live', isNew: true, sizes: SIZES, }, { id: 'na5', name: 'Romy Cropped Cardigan', price: 168, category: 'tops', img: IMG('photo-1518049362265-d5b2a6b00b37', 700), tag: 'Limited', colors: [SW.rose, SW.champagne, SW.deep], stock: 9, status: 'live', isNew: true, sizes: SIZES, }, { id: 'na6', name: 'Eloise Mini Dress', price: 228, category: 'dresses', img: IMG('photo-1572804013427-4d7ca7268217', 700), tag: 'New', colors: [SW.ivory, SW.blush], stock: 16, status: 'live', isNew: true, sizes: SIZES, }, { id: 'na7', name: 'Lila Wide-Leg Trousers', price: 198, category: 'bottoms', img: IMG('photo-1594633312681-425c7b97ccd1', 700), tag: 'New', colors: [SW.champagne, SW.deep, SW.black], stock: 21, status: 'live', isNew: true, sizes: SIZES, }, { id: 'na8', name: 'Solene Knot Top', price: 124, category: 'tops', img: IMG('photo-1503342217505-b0a15ec3261c', 700), tag: 'Just in', colors: [SW.blush, SW.rose, SW.ivory], stock: 19, status: 'live', isNew: true, sizes: SIZES, }, { id: 'bs1', name: 'Margaux Tailored Blazer', price: 325, category: 'tops', img: IMG('photo-1591047139829-d91aecb6caea', 800), badge: 'Bestseller', reviews: 412, colors: [SW.champagne, SW.deep, SW.black], stock: 14, status: 'live', isBest: true, sizes: SIZES, }, { id: 'bs2', name: 'Adele Bias Maxi Dress', price: 368, category: 'dresses', img: IMG('photo-1539008835657-9e8e9680c956', 800), badge: 'Most loved', reviews: 587, colors: [SW.blush, SW.ivory, SW.rose], stock: 11, status: 'live', isBest: true, sizes: SIZES, }, { id: 'bs3', name: 'Camille Cashmere Knit', price: 285, category: 'tops', img: IMG('photo-1583744946564-b52ac1c389c8', 800), badge: 'Restocked', reviews: 298, colors: [SW.champagne, SW.sand, SW.rose], stock: 22, status: 'live', isBest: true, sizes: SIZES, }, { id: 'bs4', name: 'Juliette Pearl Cardigan', price: 248, category: 'tops', img: IMG('photo-1551488831-00ddcb6c6bd3', 800), badge: 'Bestseller', reviews: 341, colors: [SW.ivory, SW.blush], stock: 6, status: 'live', isBest: true, sizes: SIZES, }, { id: 'ex1', name: 'Noor Pearl Earrings', price: 88, category: 'accessories', img: IMG('photo-1535632787350-4e68ef0ac584', 700), colors: [SW.ivory, SW.champagne], stock: 31, status: 'live', sizes: ['One size'], }, { id: 'ex2', name: 'Ophelia Silk Scarf', price: 68, category: 'accessories', img: IMG('photo-1606760227091-3dd870d97f1d', 700), colors: [SW.blush, SW.rose], stock: 33, status: 'live', sizes: ['One size'], }, { id: 'ex3', name: 'Quilted Mini Bag', price: 248, category: 'accessories', img: IMG('photo-1584917865442-de89df76afd3', 700), colors: [SW.champagne, SW.deep], stock: 8, status: 'live', sizes: ['One size'], }, ], instagram: [ IMG('photo-1485968579580-b6d095142e6e', 600), IMG('photo-1483985988355-763728e1935b', 600), LOCAL_EDITORIAL, IMG('photo-1503342217505-b0a15ec3261c', 600), ], }; const SITE_DATA_KEY = 'roudaina.siteData.v1'; const ADMIN_SESSION_KEY = 'roudaina.admin.session.v1'; const deepClone = (value) => JSON.parse(JSON.stringify(value)); const slugify = (value) => String(value || '') .toLowerCase() .normalize('NFD') .replace(/[\u0300-\u036f]/g, '') .replace(/[^a-z0-9]+/g, '-') .replace(/^-+|-+$/g, ''); function normalizeSiteData(raw) { const site = deepClone(raw || DEFAULT_SITE_DATA); site.categories = (site.categories || []).map((category) => ({ ...category, status: category.status || 'live', subcategories: (category.subcategories || []).map((sub) => ({ ...sub, href: sub.href || `#shop/${sub.id}`, })), })); site.products = (site.products || []).map((product) => ({ status: 'live', stock: 0, description: 'Cut from feather-light silk satin, this piece drapes effortlessly with a bias-cut silhouette that moves with you.', sizes: SIZES, slug: product.slug || slugify(product.name || product.id), ...product, })); return site; } const defaultSiteData = normalizeSiteData(DEFAULT_SITE_DATA); function mapApiToSiteData(api) { const s = api.settings || {}; // Strip leftover placeholder branding ("Roudaina") and any production-house wording // ("couture", "maison") — House of Sheylas is a curated boutique that sells, not produces. const clean = (value, fallback) => (!value || /roudaina|couture|maison/i.test(value)) ? fallback : value; const D = defaultSiteData.settings; return { settings: { brandName: clean(s.brand_name, D.brandName), brandMark: /roudaina/i.test(s.brand_mark || '') ? D.brandMark : (s.brand_mark || D.brandMark), brandTagline: clean(s.brand_tagline, D.brandTagline), tagline: clean(s.tagline, D.tagline), supportEmail: /roudaina/i.test(s.support_email || '') ? D.supportEmail : (s.support_email || D.supportEmail), pressEmail: /roudaina/i.test(s.press_email || '') ? D.pressEmail : (s.press_email || D.pressEmail), phone: s.phone || D.phone, instagramHandle: /roudaina/i.test(s.instagram_handle || '') ? D.instagramHandle : (s.instagram_handle || D.instagramHandle), instagramUrl: /roudaina/i.test(s.instagram_url || '') ? D.instagramUrl : (s.instagram_url || D.instagramUrl), tiktokUrl: s.tiktok_url || D.tiktokUrl, facebookUrl: s.facebook_url || D.facebookUrl, pinterestUrl: s.pinterest_url || D.pinterestUrl, newsletterCode: D.newsletterCode, newsletterReplyTo: D.newsletterReplyTo, adminUsername: D.adminUsername, adminPassword: D.adminPassword, // Multi-currency (product prices are stored in baseCurrency; convert for display) baseCurrency: s.base_currency || 'CAD', currencyRates: (s.currency_rates && typeof s.currency_rates === 'object' && Object.keys(s.currency_rates).length) ? s.currency_rates : { USD: 0.73, EUR: 0.68, TND: 2.30 }, enabledCurrencies: (Array.isArray(s.enabled_currencies) && s.enabled_currencies.length) ? s.enabled_currencies : ['CAD', 'EUR', 'USD', 'TND'], }, homepage: (s.homepage_content && typeof s.homepage_content === 'object') ? s.homepage_content : {}, hero: { eyebrow: s.hero_eyebrow || defaultSiteData.hero.eyebrow, title: s.hero_title || defaultSiteData.hero.title, accent: s.hero_accent || defaultSiteData.hero.accent, description: s.hero_description || defaultSiteData.hero.description, }, story: { title: s.story_title || defaultSiteData.story.title, accent: s.story_accent || defaultSiteData.story.accent, end: s.story_end || defaultSiteData.story.end, body: s.story_body || defaultSiteData.story.body, imagePrimary: defaultSiteData.story.imagePrimary, imageSecondary: defaultSiteData.story.imageSecondary, }, categories: (api.categories || []).map(c => ({ ...c, subcategories: [] })), products: (api.products || []).map(p => ({ ...p, sizes: p.sizes || SIZES })), collections: api.collections || defaultSiteData.collections, newArrivals: api.newArrivals || [], bestSellers: api.bestSellers || [], services: api.services || defaultSiteData.services, faqs: api.faqs || defaultSiteData.faqs, locations: api.locations || defaultSiteData.locations, pages: (api.pages || []).map(p => ({ id: p.slug, title: p.title, href: `#${p.slug}`, status: p.status, })), instagram: defaultSiteData.instagram, newsletter: defaultSiteData.newsletter, about: defaultSiteData.about, contact: defaultSiteData.contact, navigation: defaultSiteData.navigation, }; } let HERO_VIDEOS = [ { id: 'walk', label: 'Walking to camera', src: PEXVID('12719017', 'uhd_1440_2560_60fps'), poster: PEXPOSTER('12719017'), }, { id: 'turn', label: 'Turning away', src: PEXVID('12719021', 'uhd_1440_2560_60fps'), poster: PEXPOSTER('12719021'), }, { id: 'garden', label: 'Garden walkway', src: PEXVID('12719019', 'uhd_1440_2560_60fps'), poster: PEXPOSTER('12719019'), }, ]; let HERO_VIDEO = HERO_VIDEOS[0].src; let HERO_VIDEO_POSTER = HERO_VIDEOS[0].poster; let HERO_MAIN = IMG('photo-1490481651871-ab68de25d43d', 1400); let HERO_ACCENT = IMG('photo-1469334031218-e382a71b716b', 900); let STORY_IMG_1 = IMG('photo-1496747611176-843222e1e57c', 900); let STORY_IMG_2 = LOCAL_EDITORIAL; let SITE_SETTINGS = defaultSiteData.settings; let PAGE_CONTENT = defaultSiteData.pages; let HERO_SECTION = defaultSiteData.hero; let BRAND_STORY_SECTION = defaultSiteData.story; let NEWSLETTER_SECTION = defaultSiteData.newsletter; let ABOUT_CONTENT = defaultSiteData.about; let CONTACT_CONTENT = defaultSiteData.contact; let LOCATIONS = defaultSiteData.locations; let SERVICES = defaultSiteData.services; let CATEGORIES = defaultSiteData.categories; let COLLECTIONS = defaultSiteData.collections; let INSTAGRAM = defaultSiteData.instagram; let ALL_PRODUCTS = defaultSiteData.products; let NEW_ARRIVALS = ALL_PRODUCTS.filter((product) => product.isNew); let BEST_SELLERS = ALL_PRODUCTS.filter((product) => product.isBest); let EXTRA = ALL_PRODUCTS.filter((product) => !product.isNew && !product.isBest); let COPY = { description: 'Cut from feather-light silk satin, this piece drapes effortlessly with a bias-cut silhouette that moves with you. Adjustable straps and a softly cowled neckline make it as elegant for evenings out as it is layered beneath knits.', fabric: '100% mulberry silk · Dry clean only', fit: "True to size · Model is 5'9\" wearing size S", shipping: 'Worldwide shipping · Calculated at checkout', }; function syncSiteGlobals(site) { SITE_SETTINGS = site.settings; PAGE_CONTENT = site.pages; HERO_SECTION = site.hero; BRAND_STORY_SECTION = site.story; NEWSLETTER_SECTION = site.newsletter; ABOUT_CONTENT = site.about; CONTACT_CONTENT = site.contact; LOCATIONS = site.locations; SERVICES = site.services; CATEGORIES = site.categories; COLLECTIONS = site.collections; INSTAGRAM = site.instagram; ALL_PRODUCTS = site.products; NEW_ARRIVALS = ALL_PRODUCTS.filter((product) => product.isNew); BEST_SELLERS = ALL_PRODUCTS.filter((product) => product.isBest); EXTRA = ALL_PRODUCTS.filter((product) => !product.isNew && !product.isBest); STORY_IMG_1 = site.story.imagePrimary || STORY_IMG_1; STORY_IMG_2 = site.story.imageSecondary || STORY_IMG_2; Object.assign(window, { IMG, SW, SIZES, HERO_MAIN, HERO_ACCENT, HERO_VIDEO, HERO_VIDEO_POSTER, HERO_VIDEOS, STORY_IMG_1, STORY_IMG_2, SITE_SETTINGS, PAGE_CONTENT, HERO_SECTION, BRAND_STORY_SECTION, NEWSLETTER_SECTION, ABOUT_CONTENT, CONTACT_CONTENT, LOCATIONS, SERVICES, CATEGORIES, COLLECTIONS, INSTAGRAM, ALL_PRODUCTS, NEW_ARRIVALS, BEST_SELLERS, EXTRA, COPY, }); } function getProduct(id) { const requested = String(id || ''); return ALL_PRODUCTS.find((product) => product.id === requested || product.slug === requested || slugify(product.name) === requested ) || ALL_PRODUCTS[0]; } function getCollection(id) { return COLLECTIONS.find((collection) => collection.id === id) || COLLECTIONS[0]; } syncSiteGlobals(defaultSiteData); const SiteDataCtx = createContext(null); function loadSiteData() { try { const raw = localStorage.getItem(SITE_DATA_KEY); return raw ? normalizeSiteData(JSON.parse(raw)) : defaultSiteData; } catch { return defaultSiteData; } } function SiteDataProvider({ children }) { const [siteData, setSiteData] = useState(loadSiteData); // Fetch live Supabase data on mount — replaces localStorage/defaults with real content useEffect(() => { fetch('/api/site-data') .then(r => r.json()) .then(api => { if (api.ok && !api.fallback) { setSiteData(normalizeSiteData(mapApiToSiteData(api))); } }) .catch(() => {}); }, []); useEffect(() => { syncSiteGlobals(siteData); try { localStorage.setItem(SITE_DATA_KEY, JSON.stringify(siteData)); } catch {} }, [siteData]); const updateSiteData = useCallback((updater) => { setSiteData((current) => normalizeSiteData(typeof updater === 'function' ? updater(current) : updater)); }, []); const resetSiteData = useCallback(() => { setSiteData(deepClone(defaultSiteData)); }, []); const value = useMemo( () => ({ siteData, updateSiteData, resetSiteData, defaultSiteData, }), [siteData, updateSiteData, resetSiteData] ); return {children}; } function useSiteData() { const value = useContext(SiteDataCtx); if (!value) throw new Error('useSiteData must be used within SiteDataProvider'); return value; } const AdminAuthCtx = createContext(null); function AdminAuthProvider({ children }) { const { siteData } = useSiteData(); const [authenticated, setAuthenticated] = useState(() => { try { return localStorage.getItem(ADMIN_SESSION_KEY) === 'true'; } catch { return false; } }); const login = useCallback( (username, password) => { const ok = username === siteData.settings.adminUsername && password === siteData.settings.adminPassword; if (ok) { setAuthenticated(true); try { localStorage.setItem(ADMIN_SESSION_KEY, 'true'); } catch {} return { ok: true }; } return { ok: false, error: 'Invalid username or password.' }; }, [siteData.settings.adminPassword, siteData.settings.adminUsername] ); const logout = useCallback(() => { setAuthenticated(false); try { localStorage.removeItem(ADMIN_SESSION_KEY); } catch {} }, []); return ( {children} ); } function useAdminAuth() { const value = useContext(AdminAuthCtx); if (!value) throw new Error('useAdminAuth must be used within AdminAuthProvider'); return value; } Object.assign(window, { IMG, SW, SIZES, COPY, SiteDataProvider, useSiteData, AdminAuthProvider, useAdminAuth, ADMIN_SESSION_KEY, SITE_SETTINGS, PAGE_CONTENT, HERO_SECTION, BRAND_STORY_SECTION, NEWSLETTER_SECTION, ABOUT_CONTENT, CONTACT_CONTENT, LOCATIONS, SERVICES, CATEGORIES, COLLECTIONS, INSTAGRAM, ALL_PRODUCTS, NEW_ARRIVALS, BEST_SELLERS, EXTRA, getProduct, getCollection, HERO_MAIN, HERO_ACCENT, HERO_VIDEOS, HERO_VIDEO, HERO_VIDEO_POSTER, STORY_IMG_1, STORY_IMG_2, });