Button component improvements
buttons with a `href` now render as <a> elements, otherwise <button>
This commit is contained in:
		
							parent
							
								
									d0163ee094
								
							
						
					
					
						commit
						77665702b7
					
				
					 4 changed files with 64 additions and 72 deletions
				
			
		|  | @ -5,47 +5,47 @@ | ||||||
| 
 | 
 | ||||||
|     const dispatch = createEventDispatcher(); |     const dispatch = createEventDispatcher(); | ||||||
| 
 | 
 | ||||||
|  |     let className = ""; | ||||||
|  |     export { className as class }; | ||||||
|     export let active = false; |     export let active = false; | ||||||
|     export let filled = false; |     export let filled = false; | ||||||
|     export let disabled = false; |     export let disabled = false; | ||||||
|     export let centered = false; |     export let centered = false; | ||||||
|     export let label = undefined; |     export let label = undefined; | ||||||
|     export let sound = "default"; |     export let sound = "default"; | ||||||
|     export let href = false; |     export let href = undefined; | ||||||
|  |     export let onClick = undefined; | ||||||
| 
 | 
 | ||||||
|     let classes = []; |     let classes = []; | ||||||
| 
 | 
 | ||||||
|     function click() { |     function click() { | ||||||
|         if (disabled) return; |         if (disabled) return; | ||||||
|         if (href) { |  | ||||||
|             const link = document.createElement('a'); |  | ||||||
|             link.href = href; |  | ||||||
|             link.dispatchEvent(new MouseEvent('click', { |  | ||||||
|                 bubbles: true, |  | ||||||
|                 cancelable: true, |  | ||||||
|                 view: window, |  | ||||||
|                 ctrlKey: event.ctrlKey, |  | ||||||
|                 metaKey: event.metaKey, |  | ||||||
|                 shiftKey: event.shiftKey, |  | ||||||
|                 altKey: event.altKey, |  | ||||||
|                 button: event.button, |  | ||||||
|             })); |  | ||||||
|             return; |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         playSound(sound); |         playSound(sound); | ||||||
|         dispatch('click'); |         dispatch('click'); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     afterUpdate(() => { |     afterUpdate(() => { | ||||||
|         classes = []; |         classes = className.split(' '); | ||||||
|         if (active) classes = ["active"]; |         if (active) classes.push("active"); | ||||||
|         if (filled) classes = ["filled"]; |         if (filled) classes.push("filled"); | ||||||
|         if (disabled) classes = ["disabled"]; |         if (disabled) classes.push("disabled"); | ||||||
|         if (centered) classes.push("centered"); |         if (centered) classes.push("centered"); | ||||||
|     }); |     }); | ||||||
| </script> | </script> | ||||||
| 
 | 
 | ||||||
|  | {#if href} | ||||||
|  |     <a | ||||||
|  |             class={classes.join(' ')} | ||||||
|  |             title={label} | ||||||
|  |             aria-label={label} | ||||||
|  |             href={href} | ||||||
|  |             on:click={() => click()}> | ||||||
|  |         <span class="icon"> | ||||||
|  |             <slot name="icon" /> | ||||||
|  |         </span> | ||||||
|  |         <slot/> | ||||||
|  |     </a> | ||||||
|  | {:else} | ||||||
|     <button |     <button | ||||||
|             type="button" |             type="button" | ||||||
|             class={classes.join(' ')} |             class={classes.join(' ')} | ||||||
|  | @ -57,10 +57,10 @@ | ||||||
|             </span> |             </span> | ||||||
|             <slot/> |             <slot/> | ||||||
|     </button> |     </button> | ||||||
|  | {/if} | ||||||
| 
 | 
 | ||||||
| <style> | <style> | ||||||
|     button { |     a, button { | ||||||
|         width: 100%; |  | ||||||
|         height: fit-content; |         height: fit-content; | ||||||
|         padding: .7em .8em; |         padding: .7em .8em; | ||||||
|         display: flex; |         display: flex; | ||||||
|  | @ -71,6 +71,7 @@ | ||||||
|         font-size: 1rem; |         font-size: 1rem; | ||||||
|         font-weight: 600; |         font-weight: 600; | ||||||
|         text-align: left; |         text-align: left; | ||||||
|  |         text-decoration: none; | ||||||
| 
 | 
 | ||||||
|         border-radius: 8px; |         border-radius: 8px; | ||||||
|         border: 2px solid var(--bg-700); |         border: 2px solid var(--bg-700); | ||||||
|  | @ -84,22 +85,32 @@ | ||||||
| 
 | 
 | ||||||
|         cursor: pointer; |         cursor: pointer; | ||||||
|     } |     } | ||||||
|  |     a { | ||||||
|  |         width: calc(100% - 1.6em); | ||||||
|  |     } | ||||||
|  |     button { | ||||||
|  |         width: 100%; | ||||||
|  |     } | ||||||
| 
 | 
 | ||||||
|  |     a.centered, | ||||||
|     button.centered { |     button.centered { | ||||||
|         text-align: center; |         text-align: center; | ||||||
|         justify-content: center; |         justify-content: center; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     a:hover, | ||||||
|     button:hover { |     button:hover { | ||||||
|         border-color: color-mix(in srgb, var(--bg-700), black 10%); |         border-color: color-mix(in srgb, var(--bg-700), black 10%); | ||||||
|         background-color: color-mix(in srgb, var(--bg-700), black 10%); |         background-color: color-mix(in srgb, var(--bg-700), black 10%); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     a:active, | ||||||
|     button:active { |     button:active { | ||||||
|         border-color: color-mix(in srgb, var(--bg-700), black 20%); |         border-color: color-mix(in srgb, var(--bg-700), black 20%); | ||||||
|         background-color: color-mix(in srgb, var(--bg-700), black 20%); |         background-color: color-mix(in srgb, var(--bg-700), black 20%); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     a.active, | ||||||
|     button.active { |     button.active { | ||||||
|         background-color: var(--bg-600); |         background-color: var(--bg-600); | ||||||
|         color: var(--accent); |         color: var(--accent); | ||||||
|  | @ -107,34 +118,40 @@ | ||||||
|         text-shadow: 0px 2px 32px var(--accent); |         text-shadow: 0px 2px 32px var(--accent); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     a.active:hover, | ||||||
|     button.active:hover { |     button.active:hover { | ||||||
|         color: color-mix(in srgb, var(--accent), var(--bg-1000) 20%); |         color: color-mix(in srgb, var(--accent), var(--bg-1000) 20%); | ||||||
|         border-color: color-mix(in srgb, var(--accent), var(--bg-1000) 20%); |         border-color: color-mix(in srgb, var(--accent), var(--bg-1000) 20%); | ||||||
|         background-color: color-mix(in srgb, var(--bg-600), var(--accent) 10%); |         background-color: color-mix(in srgb, var(--bg-600), var(--accent) 10%); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     a.active:active, | ||||||
|     button.active:active { |     button.active:active { | ||||||
|         color: color-mix(in srgb, var(--accent), var(--bg-800) 10%); |         color: color-mix(in srgb, var(--accent), var(--bg-800) 10%); | ||||||
|         border-color: color-mix(in srgb, var(--accent), var(--bg-800) 10%); |         border-color: color-mix(in srgb, var(--accent), var(--bg-800) 10%); | ||||||
|         background-color: color-mix(in srgb, var(--bg-600), var(--bg-800) 10%); |         background-color: color-mix(in srgb, var(--bg-600), var(--bg-800) 10%); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     a.filled, | ||||||
|     button.filled { |     button.filled { | ||||||
|         background-color: var(--accent); |         background-color: var(--accent); | ||||||
|         color: var(--bg-800); |         color: var(--bg-800); | ||||||
|         border-color: transparent; |         border-color: transparent; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     a.filled:hover, | ||||||
|     button.filled:hover { |     button.filled:hover { | ||||||
|         color: color-mix(in srgb, var(--bg-800), white 10%); |         color: color-mix(in srgb, var(--bg-800), white 10%); | ||||||
|         background-color: color-mix(in srgb, var(--accent), white 20%); |         background-color: color-mix(in srgb, var(--accent), white 20%); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     a.filled:active, | ||||||
|     button.filled:active { |     button.filled:active { | ||||||
|         color: color-mix(in srgb, var(--bg-800), black 10%); |         color: color-mix(in srgb, var(--bg-800), black 10%); | ||||||
|         background-color: color-mix(in srgb, var(--accent), black 20%); |         background-color: color-mix(in srgb, var(--accent), black 20%); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     a.disabled, | ||||||
|     button.disabled { |     button.disabled { | ||||||
|         color: var(--text); |         color: var(--text); | ||||||
|         opacity: .5; |         opacity: .5; | ||||||
|  |  | ||||||
|  | @ -32,35 +32,6 @@ | ||||||
| 
 | 
 | ||||||
|     const dispatch = createEventDispatcher(); |     const dispatch = createEventDispatcher(); | ||||||
| 
 | 
 | ||||||
|     function handle_btn(name) { |  | ||||||
|         if (!$account) return; |  | ||||||
|         let route; |  | ||||||
|         switch (name) { |  | ||||||
|             case "timeline": |  | ||||||
|                 route = "/"; |  | ||||||
|                 getTimeline(true); |  | ||||||
|                 break; |  | ||||||
|             case "notifications": |  | ||||||
|                 route = "/notifications"; |  | ||||||
|                 notifications.set([]); |  | ||||||
|                 getNotifications(); |  | ||||||
|                 break; |  | ||||||
|             case "explore": |  | ||||||
|             case "lists": |  | ||||||
|             case "favourites": |  | ||||||
|             case "bookmarks": |  | ||||||
|             case "hashtags": |  | ||||||
|             default: |  | ||||||
|                 return; |  | ||||||
|         } |  | ||||||
|         if (!route) return; |  | ||||||
|         window.scrollTo({ |  | ||||||
|             top: 0, |  | ||||||
|             behavior: "smooth" |  | ||||||
|         }); |  | ||||||
|         goto(route); |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     function gotoProfile() { |     function gotoProfile() { | ||||||
|         if (!$account) return; |         if (!$account) return; | ||||||
|         playSound(); |         playSound(); | ||||||
|  | @ -102,7 +73,7 @@ | ||||||
|     {#if $account} |     {#if $account} | ||||||
|     <div id="nav-items"> |     <div id="nav-items"> | ||||||
|         <Button label="Timeline" |         <Button label="Timeline" | ||||||
|                 on:click={() => handle_btn("timeline")} |                 href="/")} | ||||||
|                 active={$page.url.pathname === "/"}> |                 active={$page.url.pathname === "/"}> | ||||||
|             <svelte:fragment slot="icon"> |             <svelte:fragment slot="icon"> | ||||||
|                 <TimelineIcon/> |                 <TimelineIcon/> | ||||||
|  | @ -110,7 +81,7 @@ | ||||||
|             {lang.string('navigation.timeline')} |             {lang.string('navigation.timeline')} | ||||||
|         </Button> |         </Button> | ||||||
|         <Button label="Notifications" |         <Button label="Notifications" | ||||||
|                 on:click={() => handle_btn("notifications")} |                 href="notifications"} | ||||||
|                 active={$page.url.pathname === "/notifications"}> |                 active={$page.url.pathname === "/notifications"}> | ||||||
|             <svelte:fragment slot="icon"> |             <svelte:fragment slot="icon"> | ||||||
|                 <NotificationsIcon/> |                 <NotificationsIcon/> | ||||||
|  | @ -183,7 +154,7 @@ | ||||||
|         <div id="account-button"> |         <div id="account-button"> | ||||||
|             <img src={$account.avatar_url} class="account-avatar" height="64px" alt="" aria-hidden="true" on:click={() => gotoProfile()}> |             <img src={$account.avatar_url} class="account-avatar" height="64px" alt="" aria-hidden="true" on:click={() => gotoProfile()}> | ||||||
|             <div class="account-name" aria-hidden="true"> |             <div class="account-name" aria-hidden="true"> | ||||||
|                 <a href="/{$server.host}/{$account.username}" class="nickname" title={$account.nickname}>{@html $account.rich_name}</a> |                 <a href="/{$server.host}/@{$account.username}" class="nickname" title={$account.nickname}>{@html $account.rich_name}</a> | ||||||
|                 <span class="username" title={`@${$account.username}@${$account.host}`}> |                 <span class="username" title={`@${$account.username}@${$account.host}`}> | ||||||
|                     {$account.fqn} |                     {$account.fqn} | ||||||
|                 </span> |                 </span> | ||||||
|  |  | ||||||
|  | @ -12,12 +12,12 @@ | ||||||
| </script> | </script> | ||||||
| 
 | 
 | ||||||
| <div class={"post-header-container" + (reply ? " reply" : "")}> | <div class={"post-header-container" + (reply ? " reply" : "")}> | ||||||
|     <a href="/{$server.host}/{post.account.fqn}" class="post-avatar-container" on:mouseup|stopPropagation> |     <a href="/{$server.host}/@{post.account.fqn}" class="post-avatar-container" on:mouseup|stopPropagation> | ||||||
|         <img src={post.account.avatar_url} type={post.account.avatar_type} alt="" width="48" height="48" class="post-avatar" loading="lazy" decoding="async"> |         <img src={post.account.avatar_url} type={post.account.avatar_type} alt="" width="48" height="48" class="post-avatar" loading="lazy" decoding="async"> | ||||||
|     </a> |     </a> | ||||||
|     <header class="post-header"> |     <header class="post-header"> | ||||||
|         <div class="post-user-info" on:mouseup|stopPropagation> |         <div class="post-user-info" on:mouseup|stopPropagation> | ||||||
|             <a href="/{$server.host}/{post.account.fqn}" class="name">{@html post.account.rich_name}</a> |             <a href="/{$server.host}/@{post.account.fqn}" class="name">{@html post.account.rich_name}</a> | ||||||
|             <span class="username">{post.account.mention}</span> |             <span class="username">{post.account.mention}</span> | ||||||
|         </div> |         </div> | ||||||
|         <div class="post-info" on:mouseup|stopPropagation> |         <div class="post-info" on:mouseup|stopPropagation> | ||||||
|  |  | ||||||
|  | @ -78,7 +78,7 @@ | ||||||
|         </ul> |         </ul> | ||||||
|         <div class="profile-actions"> |         <div class="profile-actions"> | ||||||
|             {#if $account && profile.fqn !== $account.fqn} |             {#if $account && profile.fqn !== $account.fqn} | ||||||
|             <Button disabled filled label="{lang.string('profile.follow')} {profile.nickname}" class="profile-btn-follow"> |             <Button filled label="{lang.string('profile.follow')} {profile.nickname}" class="profile-btn-follow"> | ||||||
|                 {lang.string('profile.follow')} |                 {lang.string('profile.follow')} | ||||||
|             </Button> |             </Button> | ||||||
|             {/if} |             {/if} | ||||||
|  | @ -186,13 +186,17 @@ | ||||||
|         gap: .5rem; |         gap: .5rem; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     .profile-btn-follow { |     .profile-actions :global(button.profile-btn-follow) { | ||||||
|         padding: 0 32px; |         padding: 0 32px; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     .profile-actions :global(button) { |     .profile-actions :global(a) { | ||||||
|         height: 42px; |  | ||||||
|         width: fit-content; |         width: fit-content; | ||||||
|  |         height: 16px; | ||||||
|  |     } | ||||||
|  |     .profile-actions :global(button) { | ||||||
|  |         width: fit-content; | ||||||
|  |         height: 42px; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     .profile-post-categories { |     .profile-post-categories { | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue