Compare commits

...

1 Commits

Author SHA1 Message Date
3b91fad590 Implement 'internal submit button' to the 'Textbox' component. Remove separate submit to the Headcode search card.
Adjust the hover and active styles of the 'TrainService' expandable cards.
2026-05-05 15:55:51 +01:00
3 changed files with 85 additions and 16 deletions

View File

@@ -2,6 +2,8 @@
import { fade } from 'svelte/transition';
import type { HTMLInputAttributes } from 'svelte/elements';
import { IconChevronRightFilled } from '@tabler/icons-svelte';
interface Props extends HTMLInputAttributes {
value?: string;
label?: string;
@@ -9,6 +11,7 @@
type?: 'text' | 'password' | 'email' | 'number' | 'search' | 'tel' | 'url';
error?: string;
uppercase?: boolean;
onsubmit?: (val: string) => void | Promise<void>;
[key: string]: any;
}
@@ -19,10 +22,18 @@
type = 'text',
error = '',
uppercase = false,
onsubmit,
...rest
}: Props = $props();
let isFocussed = $state(false);
const handleSubmit = (e: Event) => {
e.preventDefault();
if (onsubmit && value) {
onsubmit(value);
}
}
</script>
<div class="input-wrapper" class:focussed={isFocussed} class:has-error={!!error}>
@@ -30,6 +41,7 @@
<label for="adaptive-input">{label}</label>
{/if}
<form onsubmit={handleSubmit} class="input-container">
<input
id="adaptive-input"
class:all-caps={uppercase}
@@ -41,6 +53,19 @@
{...rest}
/>
{#if onsubmit}
<button
type="submit"
class="submit-icon"
transition:fade
disabled={!value}
aria-label="Submit"
>
<IconChevronRightFilled />
</button>
{/if}
</form>
{#if error}
<span class="error-message" transition:fade>{error}</span>
{/if}
@@ -50,11 +75,22 @@
.input-wrapper {
display: flex;
flex-direction: column;
gap: 8px;
gap: 0.4rem;
width: 100%;
font-family: 'URW Gothic', sans-serif;
}
.input-container {
position: relative;
display: flex;
align-items: center;
width: 100%;
background-color: var(--color-title);
border-radius: 5000px;
transition: all 0.2s;
overflow: hidden;
}
label {
font-size: 0.9rem;
font-weight: 400;
@@ -62,19 +98,46 @@
}
input {
width: 100%;
background: transparent;
min-height: 40px;
padding: 0 16px;
background-color: var(--color-title);
border: 2px solid transparent;
border-radius: 20px;
height: 100%;
line-height: normal;
padding: 0 48px;
border: none;
color: var(--color-bg-dark);
font-size: 1.2rem;
transition: all 0.2s ease-in-out;
outline: none;
text-align: center;
box-shadow: var(--shadow-std);
}
.submit-icon {
position: absolute;
background: transparent;
right: 0;
border: none;
color: var(--color-bg-dark);
cursor: pointer;
width: 48px;
height: 48px;
display: flex;
align-items: center;
justify-content: center;
opacity: 0.75;
transition: opacity 0.2s, transform 0.2s;
}
.submit-icon:hover:not(:disabled) {
opacity: 1;
transform: translateX(2px);
}
.submit-icon:disabled {
opacity: 0.5;
cursor: not-allowed;
}
.all-caps {
text-transform: uppercase;
}

View File

@@ -93,7 +93,7 @@
};
</script>
<div class="train-service">
<div class="train-service" class:isExpanded={isExpanded}>
<button class="summary" onclick={toggleExpand} type="button" aria-expanded={isExpanded}>
{#if loadingDetails}
<div class="loading-state"><div class="loading-spinner"></div></div>
@@ -241,10 +241,18 @@
filter: brightness(1.2);
}
.train-service:active .arrow {
filter: brightness(0.2);
}
@media (hover: hover) {
.train-service:hover {
.train-service:not(.isExpanded):hover {
filter: brightness(1.2);
}
.summary:hover .arrow {
filter: brightness(0.2);
}
}
/*
@@ -299,7 +307,7 @@
padding: 0;
margin: 0 0 0 auto;
height: 25px;
transition: all 0.9s;
transition: all 0.3s;
}
.expanded {

View File

@@ -6,8 +6,7 @@
let headcode = $state('');
function handleSearch(e: SubmitEvent) {
e.preventDefault();
function handleSearch(headcode: string) {
if (!headcode.trim()) return;
const searchParams = new URLSearchParams();
@@ -18,10 +17,9 @@
</script>
<BaseCard header={'Search Train & PIS'}>
<form onsubmit={handleSearch} class="card-content">
<Textbox placeholder="Enter Headcode" bind:value={headcode} maxLength={4} />
<Button type="submit" disabled={!headcode}>Search</Button>
</form>
<div class="card-content">
<Textbox placeholder="Enter Headcode" bind:value={headcode} maxLength={4} onsubmit={handleSearch} />
</div>
</BaseCard>
<style>
@@ -29,7 +27,7 @@
text-align: center;
width: 90%;
margin: auto;
padding: 10px 0 0 0;
padding: 10px 0 0.5rem 0;
display: flex;
flex-direction: column;
gap: 0.75rem;