feat: Protocol no longer required when searching

This commit is contained in:
Alicia Sykes
2026-05-10 18:59:20 +01:00
parent 52b3e19d1c
commit bf431dcf44
6 changed files with 46 additions and 47 deletions

View File

@@ -42,3 +42,12 @@ export const determineAddressType = (address: string | undefined): AddressType =
if (isUrl(address)) return 'url';
return 'err';
};
// Strip protocol and path/query/hash so the route param stays a bare host
export const normalizeAddress = (input: string | undefined): string => {
if (!input) return '';
let s = input.trim().replace(/^https?:\/\//i, '');
const stop = s.search(/[/?#]/);
if (stop !== -1) s = s.slice(0, stop);
return s;
};

View File

@@ -11,7 +11,7 @@ import FancyBackground from 'client/components/misc/FancyBackground';
import docs from 'client/utils/docs';
import colors from 'client/styles/colors';
import { determineAddressType } from 'client/utils/address-type-checker';
import { determineAddressType, normalizeAddress } from 'client/utils/address-type-checker';
const HomeContainer = styled.section`
display: flex;
@@ -140,7 +140,7 @@ const SiteFeaturesWrapper = styled(StyledCard)`
`;
const Home = (): JSX.Element => {
const defaultPlaceholder = 'e.g. https://duck.com/';
const defaultPlaceholder = 'e.g. duck.com';
const [userInput, setUserInput] = useState('');
const [errorMsg, setErrMsg] = useState('');
const [placeholder] = useState(defaultPlaceholder);
@@ -149,18 +149,17 @@ const Home = (): JSX.Element => {
const location = useLocation();
/* Redirect strait to results, if somehow we land on /check?url=[] */
useEffect(() => {
const query = new URLSearchParams(location.search);
const urlFromQuery = query.get('url');
if (urlFromQuery) {
navigate(`/check/${encodeURIComponent(urlFromQuery)}`, { replace: true });
const target = normalizeAddress(urlFromQuery);
if (target) navigate(`/check/${target}`, { replace: true });
}
}, [navigate, location.search]);
/* Check is valid address, either show err or redirect to results page */
const submit = () => {
let address = userInput.endsWith('/') ? userInput.slice(0, -1) : userInput;
const address = normalizeAddress(userInput);
const addressType = determineAddressType(address);
if (addressType === 'empt') {
@@ -168,12 +167,8 @@ const Home = (): JSX.Element => {
} else if (addressType === 'err') {
setErrMsg('Must be a valid URL, IPv4 or IPv6 Address');
} else {
// if the addressType is 'url' and address doesn't start with 'http://' or 'https://', prepend 'https://'
if (addressType === 'url' && !/^https?:\/\//i.test(address)) {
address = 'https://' + address;
}
const resultRouteParams: NavigateOptions = { state: { address, addressType } };
navigate(`/check/${encodeURIComponent(address)}`, resultRouteParams);
navigate(`/check/${address}`, resultRouteParams);
}
};

View File

@@ -58,7 +58,8 @@ const ResultsContent = styled.section`
const makeSiteName = (address: string): string => {
try {
return new URL(address).hostname.replace('www.', '');
const withScheme = /^https?:\/\//i.test(address) ? address : `https://${address}`;
return new URL(withScheme).hostname.replace(/^www\./, '');
} catch {
return address;
}
@@ -175,7 +176,11 @@ const Results = (props: { address?: string }): JSX.Element => {
{address && (
<Heading color={colors.textColor} size="medium">
{addressType === 'url' && (
<a target="_blank" rel="noreferrer" href={address}>
<a
target="_blank"
rel="noreferrer"
href={/^https?:\/\//i.test(address) ? address : `https://${address}`}
>
<img width="32px" alt="" src={`https://icon.horse/icon/${makeSiteName(address)}`} />
</a>
)}

View File

@@ -11,7 +11,18 @@ const placeholders = [
---
<div class="input-container">
<input required id="url-input" type="url" name="url" placeholder="E.g. duck.com" />
<input
required
id="url-input"
type="text"
name="url"
inputmode="url"
autocapitalize="off"
autocomplete="off"
autocorrect="off"
spellcheck="false"
placeholder="E.g. duck.com"
/>
<div class="placeholder-container">
<span class="starter" aria-hidden="true">E.g.</span>
{

View File

@@ -28,37 +28,15 @@ import Screenshots from './Screenshots.astro';
</div>
<script>
/**
* Form management actions (validation, submission, etc.)
* We just use normal, old school JavaScript for this
*/
import { normalizeAddress } from '../../client/utils/address-type-checker';
// Select the form and input elements from the DOM
const form = document.getElementById('live-start');
const urlInput = document.getElementById('url-input') as HTMLInputElement;
// Submit Event - called when user submits form with a valid URL
// Gets and checks the URL, then redirects user to /check/:url
form?.addEventListener('submit', (event) => {
event.preventDefault();
const url = urlInput.value.trim();
if (url) {
const encodedUrl = encodeURIComponent(url);
window.location.href = `/check/${encodedUrl}`;
}
});
// User presses enter, forgets to add protocol
// Will add https:// to the URL, and retry form submit
urlInput?.addEventListener('keydown', (event) => {
if (event.key === 'Enter') {
const url = urlInput.value.trim();
const urlWithoutProtocolRegex = /^[a-zA-Z0-9]+[a-zA-Z0-9.-]*\.[a-zA-Z]{2,}$/;
if (url && !/^https?:\/\//i.test(url) && urlWithoutProtocolRegex.test(url)) {
urlInput.value = 'https://' + url;
form?.dispatchEvent(new Event('submit'));
}
}
const target = normalizeAddress(urlInput.value);
if (target) window.location.href = `/check/${target}`;
});
</script>

View File

@@ -2,6 +2,7 @@
import BaseLayout from '@layouts/Base.astro';
import Main from '../../client/main.tsx';
import '../../client/styles/index.css';
import { normalizeAddress } from '../../client/utils/address-type-checker';
export const prerender = false;
@@ -10,7 +11,8 @@ const { search } = new URL(Astro.request.url);
const searchUrl = new URLSearchParams(search).get('url');
if (searchUrl) {
Astro.redirect(`/check/${encodeURIComponent(searchUrl)}`);
const target = normalizeAddress(searchUrl);
if (target) Astro.redirect(`/check/${target}`);
}
---
@@ -27,22 +29,21 @@ if (searchUrl) {
</BaseLayout>
<script>
// Fallback, if Astro hasn't initialized the RC comp yet, then check the url
// And if form has been submitted with ?url=, redirect to the results page
import { normalizeAddress } from '../../client/utils/address-type-checker';
const searchParams = new URL(window.location.href).searchParams;
if (searchParams.has('url')) {
window.location.href = `/check/${encodeURIComponent(searchParams.get('url') || '')}`;
const target = normalizeAddress(searchParams.get('url') || '');
if (target) window.location.href = `/check/${target}`;
}
// And add a manual no-react form submit handler
const form = document.querySelector<HTMLFormElement>('form');
if (form) {
form.addEventListener('submit', function (event: Event) {
event.preventDefault();
const input = (this as HTMLFormElement).querySelector<HTMLInputElement>('input[name="url"]');
if (input && input.value) {
window.location.href = `/check/${encodeURIComponent(input.value)}`;
}
const target = normalizeAddress(input?.value);
if (target) window.location.href = `/check/${target}`;
});
}
</script>