@@ -75,6 +75,53 @@ function parseSuggestedPrompts(value) {
7575 }
7676}
7777
78+ function toSpriteLabel ( name ) {
79+ return name
80+ . replace ( / [ - _ ] + / g, " " )
81+ . replace ( / \b \w / g, ( letter ) => letter . toUpperCase ( ) ) ;
82+ }
83+
84+ function normalizeSpriteEntries ( entries , fallbackSrc ) {
85+ const sprites = Object . entries ( entries || { } )
86+ . map ( ( [ name , src ] ) => [ String ( name ) . trim ( ) , String ( src ) . trim ( ) ] )
87+ . filter ( ( [ name , src ] ) => name && src ) ;
88+
89+ if ( ! sprites . some ( ( [ name ] ) => name === "globby" ) && fallbackSrc ) {
90+ sprites . unshift ( [ "globby" , fallbackSrc ] ) ;
91+ }
92+
93+ return sprites ;
94+ }
95+
96+ function parseSprites ( value , fallbackSrc ) {
97+ if ( ! value ) {
98+ return normalizeSpriteEntries ( { globby : fallbackSrc } , fallbackSrc ) ;
99+ }
100+
101+ try {
102+ const parsed = JSON . parse ( value ) ;
103+ return normalizeSpriteEntries ( parsed , fallbackSrc ) ;
104+ } catch {
105+ const entries = { } ;
106+ value
107+ . split ( / [ \n , ] / )
108+ . map ( ( entry ) => entry . trim ( ) )
109+ . filter ( Boolean )
110+ . forEach ( ( entry ) => {
111+ const separatorIndex = entry . indexOf ( ":" ) ;
112+ if ( separatorIndex <= 0 ) {
113+ return ;
114+ }
115+
116+ const name = entry . slice ( 0 , separatorIndex ) . trim ( ) ;
117+ const src = entry . slice ( separatorIndex + 1 ) . trim ( ) ;
118+ entries [ name ] = src ;
119+ } ) ;
120+
121+ return normalizeSpriteEntries ( entries , fallbackSrc ) ;
122+ }
123+ }
124+
78125class TinyArcgisAssistant extends HTMLElement {
79126 #controller = null ;
80127
@@ -86,6 +133,12 @@ class TinyArcgisAssistant extends HTMLElement {
86133 const agents = Array . from ( this . children ) ;
87134 const startHidden = booleanAttribute ( this , "start-hidden" ) ;
88135 const spriteSrc = this . getAttribute ( "sprite-src" ) || "" ;
136+ const spriteEntries = parseSprites ( this . getAttribute ( "sprites" ) , spriteSrc ) ;
137+ const selectedSpriteName =
138+ this . getAttribute ( "sprite" ) || spriteEntries [ 0 ] ?. [ 0 ] || "globby" ;
139+ const selectedSprite =
140+ spriteEntries . find ( ( [ name ] ) => name === selectedSpriteName ) ||
141+ spriteEntries [ 0 ] || [ "globby" , spriteSrc ] ;
89142 const referenceElement =
90143 this . getAttribute ( "reference-element" ) || "arcgis-map" ;
91144 const heading = this . getAttribute ( "heading" ) || "ArcGIS AI Assistant" ;
@@ -103,8 +156,8 @@ class TinyArcgisAssistant extends HTMLElement {
103156
104157 const globby = createElement ( "tiny-assistant-character" , {
105158 class : "tiny-assistant-character" ,
106- title : "Globby" ,
107- "sprite-src" : spriteSrc ,
159+ title : toSpriteLabel ( selectedSprite [ 0 ] ) ,
160+ "sprite-src" : selectedSprite [ 1 ] ,
108161 hidden : startHidden ,
109162 } ) ;
110163
@@ -154,7 +207,7 @@ class TinyArcgisAssistant extends HTMLElement {
154207 [ card , toggle ] ,
155208 ) ;
156209
157- const menu = createElement ( "menu" , { class : "globby-menu" , hidden : true } , [
210+ const menuChildren = [
158211 createMenuButton (
159212 {
160213 class : "follow-cursor-toggle" ,
@@ -168,7 +221,33 @@ class TinyArcgisAssistant extends HTMLElement {
168221 { class : "hide-tiny-assistant-button" } ,
169222 "Hide Tiny Assistant" ,
170223 ) ,
171- ] ) ;
224+ ] ;
225+
226+ if ( spriteEntries . length > 1 ) {
227+ menuChildren . push (
228+ createElement ( "li" , { class : "globby-menu-section" } , [
229+ document . createTextNode ( "Style" ) ,
230+ ] ) ,
231+ ...spriteEntries . map ( ( [ name , src ] ) =>
232+ createMenuButton (
233+ {
234+ class : "style-toggle" ,
235+ role : "menuitemradio" ,
236+ "aria-checked" : String ( name === selectedSprite [ 0 ] ) ,
237+ "data-sprite-name" : name ,
238+ "data-sprite-src" : src ,
239+ } ,
240+ toSpriteLabel ( name ) ,
241+ ) ,
242+ ) ,
243+ ) ;
244+ }
245+
246+ const menu = createElement (
247+ "menu" ,
248+ { class : "globby-menu" , hidden : true } ,
249+ menuChildren ,
250+ ) ;
172251
173252 const showButton = createElement (
174253 "button" ,
0 commit comments