@creaditor/newsletter-starterkit
Version:
Creaditor Newsletter Editor - Starterkit for creating beautiful email newsletters
274 lines (251 loc) • 16.4 kB
JavaScript
"use strict";(("undefined"!=typeof self?self:this).webpackChunkCreaditor=("undefined"!=typeof self?self:this).webpackChunkCreaditor||[]).push([[901],{20901:(e,t,r)=>{r.r(t),r.d(t,{PexelsGallery:()=>n});var o=r(56666),a=r(8427),s=(r(70235),r(9085)),l=(r(36351),r(61828),r(59051));const i="jUU57RHRVmWvXd22MBjQkDhcf9Prkbufc6KXUChhrEIOr6IqNeNvMOUl",c="https://api.pexels.com/v1/search",h=function(e){let t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:1,r=arguments.length>2&&void 0!==arguments[2]?arguments[2]:20;return fetch(`${c}?query=${encodeURIComponent(e)}&page=${t}&per_page=${r}`,{method:"GET",headers:{Authorization:i,"Content-Type":"application/json"}})};class n extends a.oi{constructor(){super(),this.images=[],this.loading=!1,this.searchQuery="",this.page=1,this.hasMore=!0,this.perPage=20,this.multi=!0,this.selectedColor="",this.defaultSearchTerms=["nature","landscape","city","people","technology","food","architecture","travel","business","art"],this.colorOptions=[{name:"Red",value:"red",hex:"#ff0000"},{name:"Orange",value:"orange",hex:"#ff8000"},{name:"Yellow",value:"yellow",hex:"#ffff00"},{name:"Green",value:"green",hex:"#00ff00"},{name:"Blue",value:"blue",hex:"#0000ff"},{name:"Purple",value:"purple",hex:"#8000ff"},{name:"Pink",value:"pink",hex:"#ff0080"},{name:"Brown",value:"brown",hex:"#8b4513"},{name:"Black",value:"black",hex:"#000000"},{name:"White",value:"white",hex:"#ffffff"},{name:"Gray",value:"gray",hex:"#808080"},{name:"Teal",value:"teal",hex:"#008080"},{name:"Navy",value:"navy",hex:"#000080"},{name:"Maroon",value:"maroon",hex:"#800000"},{name:"Olive",value:"olive",hex:"#808000"},{name:"Lime",value:"lime",hex:"#00ff00"},{name:"Aqua",value:"aqua",hex:"#00ffff"},{name:"Silver",value:"silver",hex:"#c0c0c0"},{name:"Fuchsia",value:"fuchsia",hex:"#ff00ff"},{name:"Coral",value:"coral",hex:"#ff7f50"},{name:"Gold",value:"gold",hex:"#ffd700"},{name:"Indigo",value:"indigo",hex:"#4b0082"},{name:"Violet",value:"violet",hex:"#ee82ee"},{name:"Cyan",value:"cyan",hex:"#00ffff"},{name:"Magenta",value:"magenta",hex:"#ff00ff"}],this.cacheKey="pexels-gallery-cache",this.cacheExpiry=864e5,this.isTyping=!1,this.lastSearchQuery="",this.searchTimeout=null}connectedCallback(){super.connectedCallback(),this.loadFromCache()}getCacheData(){try{const e=localStorage.getItem(this.cacheKey);if(!e)return null;const t=JSON.parse(e),r=Date.now();return t.timestamp&&r-t.timestamp>this.cacheExpiry?(localStorage.removeItem(this.cacheKey),null):t}catch(e){return console.error("Error reading cache:",e),null}}saveToCache(){if(!this.isTyping)try{const e={images:this.images,searchQuery:this.searchQuery,selectedColor:this.selectedColor,page:this.page,hasMore:this.hasMore,timestamp:Date.now()};localStorage.setItem(this.cacheKey,JSON.stringify(e))}catch(e){console.error("Error saving to cache:",e)}}loadFromCache(){const e=this.getCacheData();e?(this.images=e.images||[],this.searchQuery=e.searchQuery||"",this.selectedColor=e.selectedColor||"",this.page=e.page||1,this.hasMore=void 0===e.hasMore||e.hasMore,console.log("Gallery state restored from cache"),this.requestUpdate(),this.updateComplete.then((()=>{this.updateSearchInput()}))):this.loadRandomImages()}updateSearchInput(){const e=this.shadowRoot?.querySelector('cdtr-input[type="search"]');e&&(e.value=this.searchQuery)}async loadRandomImages(){this.loading=!0;try{const e=this.defaultSearchTerms[Math.floor(Math.random()*this.defaultSearchTerms.length)],t=await h(e,1,this.perPage);if(t.ok){const e=await t.json();this.images=e.photos||[],this.hasMore=e.photos&&e.photos.length===this.perPage,this.searchQuery="",this.selectedColor="",this.page=1,this.saveToCache()}else console.error("Failed to load images from Pexels"),this.images=[]}catch(e){console.error("Error loading images:",e),this.images=[]}finally{this.loading=!1}}async searchImages(e){if(!e.trim())return this.loadRandomImages();this.loading=!0,this.searchQuery=e,this.page=1;try{const t=await h(e,1,this.perPage);if(t.ok){const e=await t.json();this.images=e.photos||[],this.hasMore=e.photos&&e.photos.length===this.perPage,this.saveToCache()}else console.error("Failed to search images from Pexels"),this.images=[]}catch(e){console.error("Error searching images:",e),this.images=[]}finally{this.loading=!1}}async loadMoreImages(){if(!this.loading&&this.hasMore){this.loading=!0,this.page++;try{let e;if(this.selectedColor&&"all"!==this.selectedColor){let t=this.removeColorFilters(this.searchQuery);e=t.trim()?`${t} ${this.selectedColor}`:this.selectedColor}else{e=this.removeColorFilters(this.searchQuery)||this.defaultSearchTerms[Math.floor(Math.random()*this.defaultSearchTerms.length)]}const t=await h(e,this.page,this.perPage);if(t.ok){const e=(await t.json()).photos||[];this.images=[...this.images,...e],this.hasMore=e.length===this.perPage,this.saveToCache()}}catch(e){console.error("Error loading more images:",e)}finally{this.loading=!1}}}onSearch(e){const t=e.target.value;this.isTyping=!0,t!==this.lastSearchQuery&&(this.lastSearchQuery=t,this.searchTimeout&&clearTimeout(this.searchTimeout),this.searchTimeout=setTimeout((()=>{this.isTyping=!1,this.searchWithColor(t,this.selectedColor)}),500))}onSelectImage(e){const t=`Photo by ${e.photographer} on Pexels`,r=`Photo by <a href="${e.photographer_url}" target="_blank" rel="noopener noreferrer">${e.photographer}</a> on <a href="${e.url}" target="_blank" rel="noopener noreferrer">Pexels</a>`,o={detail:{id:e.id,src:e.src.medium||e.src.large||e.src.original,name:`Pexels Image ${e.id}`,size:`${e.width}x${e.height}`,photographer:e.photographer,photographerUrl:e.photographer_url,pexelsUrl:e.url,alt:e.alt||`Photo by ${e.photographer} on Pexels`,attributionText:t,attributionHtml:r},bubbles:!1,composed:!1};this.dispatchEvent(new CustomEvent("file",o))}sendSelectedImages(){const e={detail:this.images.filter((e=>e.selected)).map((e=>{const t=`Photo by ${e.photographer} on Pexels`,r=`Photo by <a href="${e.photographer_url}" target="_blank" rel="noopener noreferrer">${e.photographer}</a> on <a href="${e.url}" target="_blank" rel="noopener noreferrer">Pexels</a>`;return{id:e.id,src:e.src.medium||e.src.large||e.src.original,name:`Pexels Image ${e.id}`,size:`${e.width}x${e.height}`,photographer:e.photographer,photographerUrl:e.photographer_url,pexelsUrl:e.url,alt:e.alt||`Photo by ${e.photographer} on Pexels`,attributionText:t,attributionHtml:r}})),bubbles:!1,composed:!1};this.dispatchEvent(new CustomEvent("file",e))}onScroll(e){const t=e.target;t.scrollTop+t.offsetHeight>=t.scrollHeight-50&&this.loadMoreImages()}clearCache(){localStorage.removeItem(this.cacheKey),console.log("Gallery cache cleared")}onColorChange(e){console.log("Color change event:",e);const t=e.target.value;console.log("Selected color:",t),this.selectedColor="all"===t?"":t;const r=this.searchQuery||"";this.searchWithColor(r,this.selectedColor)}searchWithColor(e,t){if(t&&"all"!==t){let r=this.removeColorFilters(e),o=r.trim()?`${r} ${t}`:t;this.searchImages(o)}else{let t=this.removeColorFilters(e);this.searchImages(t)}}removeColorFilters(e){if(!e)return"";const t=this.colorOptions.map((e=>e.value));return e.split(" ").filter((e=>{const r=e.toLowerCase().trim();return!t.includes(r)})).join(" ").trim()}getSelectedColorName(){if(!this.selectedColor)return"Filter by color";const e=this.colorOptions.find((e=>e.value===this.selectedColor));return e?e.name:"Filter by color"}getSelectedColorHex(){if(!this.selectedColor)return"#666";const e=this.colorOptions.find((e=>e.value===this.selectedColor));return e?e.hex:"#666"}render(){return a.dy`
<div class="gallery-container">
<cdtr-row alignItems="center">
<cdtr-input
type="search"
=${this.onSearch}
placeholder="Search images..."
class="search"
></cdtr-input>
<div class="divider-y"></div>
<!-- Color Filter Dropdown -->
<div class="color-dropdown">
<cdtr-dropdown
.value=${this.selectedColor||""}
=${this.onColorChange}
>
<paper-button slot="trigger">
<div
class="color-preview"
style="background-color: ${this.getSelectedColorHex()}"
></div>
</paper-button>
<div slot="content">
<cdtr-dropdown-item
value="all"
.selected=${!this.selectedColor}
>
<div
class="color-circle"
style="background-color: transparent; border: 2px dashed #ccc;"
></div>
<span style="margin-left: 8px; font-size: 12px;">All Colors</span>
</cdtr-dropdown-item>
${this.colorOptions.map((e=>a.dy`
<cdtr-dropdown-item
value="${e.value}"
.selected=${this.selectedColor===e.value}
>
<div
class="color-circle"
style="background-color: ${e.hex}"
></div>
<span style="margin-left: 8px; font-size: 12px;">${e.name}</span>
</cdtr-dropdown-item>
`))}
</div>
</cdtr-dropdown>
</div>
<paper-button =${this.loadRandomImages} class="icon-btn">
<cdtr-tooltip delay="500,0" arrow=${!1} content="refresh">
<cdtr-refresh-icon></cdtr-refresh-icon>
</cdtr-tooltip>
</paper-button>
</cdtr-row>
<cdtr-row mt="2" alignItems="center" justify="space-between">
<div class="pexels-header-credit">
<div class="status-indicator">
<div class="connected-dot"></div>
</div>
<div class="credit-content">
<span class="credit-text">Powered by </span>
<a
href="https://www.pexels.com"
target="_blank"
rel="noopener noreferrer"
class="pexels-header-link"
>
Pexels
</a>
</div>
</div>
</cdtr-row>
<cdtr-row mt="2" justify="space-between">
<cdtr-col sm="12">
<cdtr-row
=${this.onScroll}
class="scroll-body"
justify="space-evenly"
>
${this.loading&&0===this.images.length?a.dy`<cdtr-col sm="12">
<cdtr-row justify="center">
<cdtr-spinner></cdtr-spinner>
<lang-text text="loading"></lang-text>
</cdtr-row>
</cdtr-col>`:(0,s.r)(this.images||[],(e=>e.id),((e,t)=>a.dy`<cdtr-col class="file-col" sm="3">
<cdtr-editor-media-card
=${()=>this.onSelectImage(e)}
=${t=>{t.shiftKey&&this.multi||this.images.forEach((e=>e.selected=!1)),e.selected=!e.selected,this.images=[...this.images],this.isTyping||this.saveToCache()}}
.selected=${e.selected}
.controls=${!1}
src=${e.src.medium||e.src.large||e.src.original}
name=${`Photo by ${e.photographer}`}
subTitle=${`${e.width}x${e.height}`}
>
<div slot="footer" class="pexels-credit">
<a
href="${e.photographer_url}"
target="_blank"
rel="noopener noreferrer"
class="photographer-link"
>
${e.photographer}
</a>
<span class="credit-text"> on </span>
<a
href="${e.url}"
target="_blank"
rel="noopener noreferrer"
class="pexels-link"
>
Pexels
</a>
</div>
</cdtr-editor-media-card>
</cdtr-col>`))}
${this.loading&&this.images.length>0?a.dy`<cdtr-col sm="12">
<cdtr-row justify="center">
<cdtr-spinner></cdtr-spinner>
<lang-text text="loadingMore"></lang-text>
</cdtr-row>
</cdtr-col>`:null}
</cdtr-row>
</cdtr-col>
</cdtr-row>
<cdtr-row alignItems="center" justify="flex-start" class="footer">
<paper-button =${this.sendSelectedImages} class="add-btn">
<lang-text text="choose"></lang-text>
</paper-button>
</cdtr-row>
</div>
`}}(0,o.Z)(n,"styles",[l.$,a.iv`
:host {
--alpha: rgba(0, 123, 255, 0.1);
--primary: #007bff;
}
.color-dropdown {
display: inline-block;
}
.color-preview {
width: 20px;
height: 20px;
border-radius: 50%;
border: 2px solid white;
box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.1);
display: inline-block;
}
.color-circle {
width: 20px;
height: 20px;
border-radius: 50%;
border: 2px solid white;
box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.1);
display: inline-block;
}
.clear-color {
color: #666;
font-style: italic;
}
.pexels-credit {
position: absolute;
bottom: 5px;
left: 5px;
right: 5px;
background: rgba(0, 0, 0, 0.7);
color: white;
padding: 4px 8px;
border-radius: 4px;
font-size: 10px;
text-align: center;
opacity: 0;
transition: opacity 0.2s ease;
}
.file-col:hover .pexels-credit {
opacity: 1;
}
.photographer-link,
.pexels-link {
color: #fff;
text-decoration: none;
font-weight: 500;
}
.photographer-link:hover,
.pexels-link:hover {
text-decoration: underline;
}
.credit-text {
color: rgba(255, 255, 255, 0.8);
}
.pexels-header-credit {
display: flex;
align-items: center;
gap: 8px;
background: rgba(255, 255, 255, 0.95);
backdrop-filter: blur(10px);
border: 1px solid rgba(0, 0, 0, 0.08);
border-radius: 12px;
padding: 6px 12px;
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
transition: all 0.2s ease;
font-size: 11px;
font-weight: 500;
letter-spacing: 0.3px;
}
.pexels-header-credit:hover {
transform: translateY(-1px);
box-shadow: 0 3px 8px rgba(0, 0, 0, 0.15);
border-color: rgba(0, 0, 0, 0.12);
}
.status-indicator {
display: flex;
align-items: center;
justify-content: center;
}
.connected-dot {
width: 6px;
height: 6px;
border-radius: 50%;
background: #10b981;
box-shadow: 0 0 0 2px rgba(16, 185, 129, 0.2);
animation: pulse-green 2s infinite;
}
pulse-green {
0%,
100% {
box-shadow: 0 0 0 2px rgba(16, 185, 129, 0.2);
transform: scale(1);
}
50% {
box-shadow: 0 0 0 4px rgba(16, 185, 129, 0.1);
transform: scale(1.1);
}
}
.credit-content {
display: flex;
align-items: center;
gap: 4px;
}
.credit-text {
color: #6b7280;
font-weight: 400;
}
.pexels-header-link {
color: #3b82f6;
text-decoration: none;
font-weight: 600;
transition: color 0.2s ease;
}
.pexels-header-link:hover {
color: #2563eb;
}
`]),(0,o.Z)(n,"properties",{images:{type:Array},loading:{type:Boolean},searchQuery:{type:String},page:{type:Number},hasMore:{type:Boolean},multi:{type:Boolean},selectedColor:{type:String}}),customElements.define("cdtr-pexels-gallery",n)}}]);