@@ -2113,6 +2113,55 @@ function RemoteFunctions(config = {}) {
21132113 font-size: 9px !important;
21142114 opacity: 0.85 !important;
21152115 }
2116+
2117+ .phoenix-use-image-btn {
2118+ position: absolute !important;
2119+ top: 6px !important;
2120+ right: 6px !important;
2121+ background: rgba(0,0,0,0.55) !important;
2122+ border: none !important;
2123+ color: white !important;
2124+ border-radius: 20px !important;
2125+ height: 26px !important;
2126+ display: flex !important;
2127+ align-items: center !important;
2128+ justify-content: center !important;
2129+ cursor: pointer !important;
2130+ font-size: 12px !important;
2131+ z-index: 2 !important;
2132+ padding: 0 8px !important;
2133+ white-space: nowrap !important;
2134+ opacity: 0 !important;
2135+ transition: all 0.2s ease !important;
2136+ }
2137+
2138+ .phoenix-use-image-btn i {
2139+ margin-right: 0 !important;
2140+ transition: margin 0.2s !important;
2141+ }
2142+
2143+ .phoenix-use-image-btn span {
2144+ display: none !important;
2145+ font-size: 11px !important;
2146+ font-weight: 500 !important;
2147+ }
2148+
2149+ .phoenix-ribbon-thumb:hover .phoenix-use-image-btn {
2150+ opacity: 1 !important;
2151+ }
2152+
2153+ .phoenix-use-image-btn:hover {
2154+ background: rgba(0,0,0,0.8) !important;
2155+ padding: 0 10px !important;
2156+ }
2157+
2158+ .phoenix-use-image-btn:hover i {
2159+ margin-right: 4px !important;
2160+ }
2161+
2162+ .phoenix-use-image-btn:hover span {
2163+ display: inline !important;
2164+ }
21162165 </style>
21172166 <div class="phoenix-image-ribbon">
21182167 <div class="phoenix-ribbon-header">
@@ -2136,6 +2185,7 @@ function RemoteFunctions(config = {}) {
21362185 } ,
21372186
21382187 _fetchImages : function ( searchQuery = 'sunshine' ) {
2188+ this . _currentSearchQuery = searchQuery ;
21392189 const apiUrl = `https://images.phcode.dev/api/images/search?q=${ encodeURIComponent ( searchQuery ) } &per_page=10` ;
21402190 this . _showLoading ( ) ;
21412191
@@ -2254,14 +2304,7 @@ function RemoteFunctions(config = {}) {
22542304
22552305 const photographer = window . document . createElement ( 'span' ) ;
22562306 photographer . className = 'photographer' ;
2257-
2258- // unsplash attribution is in the format 'Photo by <name> on Unsplash'
2259- // we extract the name from there
2260- let photographerName = 'Anonymous' ; // if not present, show anonymous
2261- if ( image . attribution ) {
2262- const match = image . attribution . match ( / P h o t o b y ( .+ ) o n U n s p l a s h / ) ;
2263- if ( match ) { photographerName = match [ 1 ] ; }
2264- }
2307+ const photographerName = this . _getPhotographerName ( image ) ;
22652308 photographer . textContent = photographerName ;
22662309
22672310 const source = window . document . createElement ( 'span' ) ;
@@ -2271,8 +2314,24 @@ function RemoteFunctions(config = {}) {
22712314 attribution . appendChild ( photographer ) ;
22722315 attribution . appendChild ( source ) ;
22732316
2317+ // use image button
2318+ const useImageBtn = window . document . createElement ( 'button' ) ;
2319+ useImageBtn . className = 'phoenix-use-image-btn' ;
2320+ useImageBtn . innerHTML = '⬇<span>Use this image</span>' ;
2321+
2322+ // when use image button is clicked, we first generate the file name by which we need to save the image
2323+ // and then we add the image to project
2324+ useImageBtn . addEventListener ( 'click' , ( e ) => {
2325+ e . stopPropagation ( ) ;
2326+ e . preventDefault ( ) ;
2327+ const filename = this . _generateFilename ( image ) ;
2328+ const extnName = ".jpg" ;
2329+ this . _useImage ( image . url , filename , extnName ) ;
2330+ } ) ;
2331+
22742332 thumbDiv . appendChild ( img ) ;
22752333 thumbDiv . appendChild ( attribution ) ;
2334+ thumbDiv . appendChild ( useImageBtn ) ;
22762335 rowElement . appendChild ( thumbDiv ) ;
22772336 } ) ;
22782337 } ,
@@ -2285,6 +2344,42 @@ function RemoteFunctions(config = {}) {
22852344 rowElement . className = 'phoenix-ribbon-row phoenix-ribbon-error' ;
22862345 } ,
22872346
2347+ _getPhotographerName : function ( image ) {
2348+ // unsplash API returns attribution in format 'Photo by <name> on Unsplash'
2349+ // this function is responsible to get the name
2350+ if ( image . attribution ) {
2351+ const match = image . attribution . match ( / P h o t o b y ( .+ ) o n U n s p l a s h / ) ;
2352+ if ( match ) {
2353+ return match [ 1 ] ;
2354+ }
2355+ }
2356+ return 'Anonymous' ;
2357+ } ,
2358+
2359+ // file name with which we need to save the image
2360+ _generateFilename : function ( image ) {
2361+ const photographerName = this . _getPhotographerName ( image ) ;
2362+ const searchTerm = this . _currentSearchQuery || 'image' ;
2363+
2364+ // clean the search term and the photograper name to write in file name
2365+ const cleanSearchTerm = searchTerm . toLowerCase ( ) . replace ( / [ ^ a - z 0 - 9 ] / g, '-' ) . replace ( / - + / g, '-' ) . replace ( / ^ - | - $ / g, '' ) ;
2366+ const cleanPhotographerName = photographerName . toLowerCase ( ) . replace ( / [ ^ a - z 0 - 9 ] / g, '-' ) . replace ( / - + / g, '-' ) . replace ( / ^ - | - $ / g, '' ) ;
2367+
2368+ return `${ cleanSearchTerm } -by-${ cleanPhotographerName } ` ;
2369+ } ,
2370+
2371+ _useImage : function ( imageUrl , filename , extnName ) {
2372+ // to use the image we send the message to the editor instance
2373+ // this is handled inside liveDevProtocol.js file
2374+ window . _Brackets_MessageBroker . send ( {
2375+ livePreviewEditEnabled : true ,
2376+ useImage : true ,
2377+ imageUrl : imageUrl ,
2378+ filename : filename ,
2379+ extnName : extnName
2380+ } ) ;
2381+ } ,
2382+
22882383 create : function ( ) {
22892384 this . remove ( ) ; // remove existing ribbon if already present
22902385
0 commit comments