@@ -122,6 +122,10 @@ function pluginDetailHref(pluginId: string) {
122122 return withBase (` ${prefix }?id=${encodeURIComponent (pluginId )} ` );
123123}
124124
125+ function installHref(pluginName : string ) {
126+ return ` wox://query?q=${encodeURIComponent (` wpm install ${pluginName } ` )} ` ;
127+ }
128+
125129function platformIconPath(osKey : string ) {
126130 if (osKey === " windows" ) {
127131 return " M3 4.2 11 3v8.5H3zm9.5-1.3L21 1.6v9.1h-8.5zM3 12.9h8v8.6L3 20.3zm9.5 0H21v9.5l-8.5-1.2z" ;
@@ -134,7 +138,7 @@ function platformIconPath(osKey: string) {
134138 return " M12 2.2c2.2 0 4.1 1.5 4.6 3.6 1.6.6 2.7 2.1 2.7 3.9 0 1.2-.5 2.4-1.4 3.2v4.4c0 .5-.3 1-.8 1.2l-1.6.8-.8 2c-.2.5-.7.8-1.2.8h-3c-.5 0-1-.3-1.2-.8l-.8-2-1.6-.8c-.5-.2-.8-.7-.8-1.2V13c-.9-.8-1.4-2-1.4-3.2 0-1.8 1.1-3.3 2.7-3.9.5-2.1 2.4-3.7 4.6-3.7Zm-2.4 18.1.4 1h4l.4-1Zm-.4-9.2c-.7 0-1.2.6-1.2 1.2s.5 1.2 1.2 1.2 1.2-.5 1.2-1.2-.6-1.2-1.2-1.2Zm5.6 0c-.7 0-1.2.6-1.2 1.2s.5 1.2 1.2 1.2 1.2-.5 1.2-1.2-.5-1.2-1.2-1.2Z" ;
135139}
136140
137- function readCurrentPluginId( ) {
141+ function syncCurrentPluginIdFromUrl( replaceHistory = false ) {
138142 if (typeof window === " undefined" ) return ;
139143
140144 const queryPluginId = new URLSearchParams (window .location .search ).get (" id" ) || " " ;
@@ -151,7 +155,23 @@ function readCurrentPluginId() {
151155
152156 const currentUrl = new URL (window .location .href );
153157 currentUrl .searchParams .set (" id" , lastPluginId );
154- window .history .replaceState ({}, " " , currentUrl .toString ());
158+ if (replaceHistory ) {
159+ window .history .replaceState ({}, " " , currentUrl .toString ());
160+ }
161+ }
162+
163+ function openPluginDetail(pluginId : string ) {
164+ if (typeof window === " undefined" || ! pluginId ) return ;
165+ if (currentPluginId .value === pluginId ) return ;
166+
167+ currentPluginId .value = pluginId ;
168+ activeScreenshot .value = 0 ;
169+ window .sessionStorage .setItem (lastPluginStorageKey , pluginId );
170+
171+ const currentUrl = new URL (window .location .href );
172+ currentUrl .searchParams .set (" id" , pluginId );
173+ window .history .pushState ({}, " " , currentUrl .toString ());
174+ window .scrollTo ({ top: 0 , behavior: " smooth" });
155175}
156176
157177async function loadPlugins() {
@@ -160,7 +180,7 @@ async function loadPlugins() {
160180 try {
161181 const storePlugins = await fetchStorePlugins ();
162182 plugins .value = storePlugins .map ((item ) => localizePlugin (item , lang .value ));
163- readCurrentPluginId ( );
183+ syncCurrentPluginIdFromUrl ( true );
164184 activeScreenshot .value = 0 ;
165185 } catch (error ) {
166186 console .error (error );
@@ -181,18 +201,31 @@ function sharePlugin() {
181201 }
182202}
183203
204+ function handlePopState() {
205+ syncCurrentPluginIdFromUrl ();
206+ activeScreenshot .value = 0 ;
207+ }
208+
184209onMounted (() => {
185210 if (typeof document !== " undefined" ) {
186211 document .body .classList .add (pluginDetailBodyClass );
187212 }
188213
214+ if (typeof window !== " undefined" ) {
215+ window .addEventListener (" popstate" , handlePopState );
216+ }
217+
189218 loadPlugins ();
190219});
191220
192221onUnmounted (() => {
193222 if (typeof document !== " undefined" ) {
194223 document .body .classList .remove (pluginDetailBodyClass );
195224 }
225+
226+ if (typeof window !== " undefined" ) {
227+ window .removeEventListener (" popstate" , handlePopState );
228+ }
196229});
197230 </script >
198231
@@ -224,9 +257,17 @@ onUnmounted(() => {
224257 </div >
225258
226259 <div class =" hero-actions" >
227- <a :href =" `wox://query?q=wpm install ${ plugin.Id}` " class =" primary-action" >{{ uiText.install }}</a >
260+ <a :href =" installHref( plugin.LocalizedName) " class =" primary-action" >{{ uiText.install }}</a >
228261 <a v-if =" plugin.Website" :href =" plugin.Website" target =" _blank" rel =" noreferrer" class =" secondary-action" >{{ uiText.source }}</a >
229- <button type =" button" class =" secondary-action" @click =" sharePlugin" >{{ uiText.share }}</button >
262+ <button type =" button" class =" secondary-action share-action" @click =" sharePlugin" >
263+ <svg viewBox =" 0 0 24 24" aria-hidden =" true" class =" share-icon" >
264+ <path
265+ d =" M18.9 2H22l-6.8 7.8L23.2 22h-6.3l-4.9-7.4L5.6 22H2.5l7.3-8.3L1.8 2h6.4l4.4 6.8L18.9 2Zm-1.1 18h1.8L7.2 3.9H5.3Z"
266+ fill =" currentColor"
267+ />
268+ </svg >
269+ <span >{{ uiText.share }}</span >
270+ </button >
230271 </div >
231272 </div >
232273
@@ -315,7 +356,7 @@ onUnmounted(() => {
315356 </div >
316357
317358 <div class =" related-grid" >
318- <a v-for =" item in relatedPlugins" :key =" item.Id" :href =" pluginDetailHref(item.Id)" class =" related-card" >
359+ <a v-for =" item in relatedPlugins" :key =" item.Id" :href =" pluginDetailHref(item.Id)" class =" related-card" @click.prevent = " openPluginDetail(item.Id) " >
319360 <div class =" related-top" >
320361 <img v-if =" item.IconUrl" :src =" item.IconUrl" class =" related-icon" alt =" plugin icon" />
321362 <div v-else class =" related-icon related-placeholder" >{{ item.IconEmoji || "🧩" }}</div >
@@ -450,6 +491,7 @@ onUnmounted(() => {
450491 display : inline-flex ;
451492 align-items : center ;
452493 justify-content : center ;
494+ gap : 8px ;
453495 min-height : 42px ;
454496 padding : 0 18px ;
455497 border-radius : 999px ;
@@ -479,6 +521,20 @@ onUnmounted(() => {
479521 transform : translateY (-1px );
480522}
481523
524+ .primary-action :hover {
525+ color : white ;
526+ }
527+
528+ .secondary-action :hover {
529+ color : var (--vp-c-text-1 );
530+ }
531+
532+ .share-icon {
533+ width : 15px ;
534+ height : 15px ;
535+ flex-shrink : 0 ;
536+ }
537+
482538.hero-panel {
483539 padding : 22px ;
484540 border-radius : 24px ;
0 commit comments