feat(domains): allow claiming username root domain
Build and publish Docker image / build-and-publish (push) Successful in 12s
Build and publish Docker image / build-and-publish (push) Successful in 12s
This commit is contained in:
1 parent
687f895345
commit
179a8c274b
1 file changed
+23
-8
@@ -682,6 +682,7 @@ export const DomainManager = ({ userId, username, servers, sendMessage, showAler
|
|||||||
const [customDomains, setCustomDomains] = useState([]);
|
const [customDomains, setCustomDomains] = useState([]);
|
||||||
const [isLoading, setIsLoading] = useState(true);
|
const [isLoading, setIsLoading] = useState(true);
|
||||||
const [newDomainName, setNewDomainName] = useState('');
|
const [newDomainName, setNewDomainName] = useState('');
|
||||||
|
const [useUsernameDomain, setUseUsernameDomain] = useState(false);
|
||||||
const [selectedServerForLink, setSelectedServerForLink] = useState('');
|
const [selectedServerForLink, setSelectedServerForLink] = useState('');
|
||||||
const [showCreateModal, setShowCreateModal] = useState(false);
|
const [showCreateModal, setShowCreateModal] = useState(false);
|
||||||
const [showLinkModal, setShowLinkModal] = useState(false);
|
const [showLinkModal, setShowLinkModal] = useState(false);
|
||||||
@@ -765,6 +766,7 @@ export const DomainManager = ({ userId, username, servers, sendMessage, showAler
|
|||||||
setSuccessMessage(data.message || 'Domain created successfully!');
|
setSuccessMessage(data.message || 'Domain created successfully!');
|
||||||
setShowCreateModal(false);
|
setShowCreateModal(false);
|
||||||
setNewDomainName('');
|
setNewDomainName('');
|
||||||
|
setUseUsernameDomain(false);
|
||||||
setActionInProgress(false);
|
setActionInProgress(false);
|
||||||
loadDomains();
|
loadDomains();
|
||||||
break;
|
break;
|
||||||
@@ -837,19 +839,19 @@ export const DomainManager = ({ userId, username, servers, sendMessage, showAler
|
|||||||
}, [loadDomains, loadCustomDomains]);
|
}, [loadDomains, loadCustomDomains]);
|
||||||
|
|
||||||
const createDomain = () => {
|
const createDomain = () => {
|
||||||
if (!newDomainName.trim()) {
|
if (!useUsernameDomain && !newDomainName.trim()) {
|
||||||
setErrorMessage('Please enter a domain name');
|
setErrorMessage('Please enter a domain name');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Validate domain name format
|
// Validate domain name format
|
||||||
const domainRegex = /^[a-zA-Z0-9]([a-zA-Z0-9-]*[a-zA-Z0-9])?$/;
|
const domainRegex = /^[a-zA-Z0-9]([a-zA-Z0-9-]*[a-zA-Z0-9])?$/;
|
||||||
if (!domainRegex.test(newDomainName)) {
|
if (!useUsernameDomain && !domainRegex.test(newDomainName)) {
|
||||||
setErrorMessage('Domain name can only contain letters, numbers, and hyphens. Cannot start or end with hyphen.');
|
setErrorMessage('Domain name can only contain letters, numbers, and hyphens. Cannot start or end with hyphen.');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (newDomainName.length > 63) {
|
if (!useUsernameDomain && newDomainName.length > 63) {
|
||||||
setErrorMessage('Domain name must be 63 characters or less');
|
setErrorMessage('Domain name must be 63 characters or less');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -860,7 +862,8 @@ export const DomainManager = ({ userId, username, servers, sendMessage, showAler
|
|||||||
|
|
||||||
sendMessage({
|
sendMessage({
|
||||||
type: 'create_domain',
|
type: 'create_domain',
|
||||||
subdomain: newDomainName.trim().toLowerCase(),
|
subdomain: useUsernameDomain ? '' : newDomainName.trim().toLowerCase(),
|
||||||
|
useUsernameDomain,
|
||||||
serverId: selectedServerForLink || null
|
serverId: selectedServerForLink || null
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
@@ -1124,9 +1127,21 @@ export const DomainManager = ({ userId, username, servers, sendMessage, showAler
|
|||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<div className="p-6 space-y-6">
|
<div className="p-6 space-y-6">
|
||||||
<SettingsPanel title="Domain Details" description={`Choose a name under u-${username}.${branding.domain}. Other names under your username are available too.`}>
|
<SettingsPanel title="Domain Details" description={`A name such as "my-site" becomes my-site.u-${username}.${branding.domain}. You can also claim u-${username}.${branding.domain} directly.`}>
|
||||||
<div className="space-y-4">
|
<div className="space-y-4">
|
||||||
<div className="relative">
|
<label className="flex items-start gap-3 rounded-xl border border-dash-border bg-black/20 p-3 text-sm">
|
||||||
|
<input
|
||||||
|
type="checkbox"
|
||||||
|
checked={useUsernameDomain}
|
||||||
|
onChange={(event) => setUseUsernameDomain(event.target.checked)}
|
||||||
|
className="mt-1 accent-primary"
|
||||||
|
/>
|
||||||
|
<span>
|
||||||
|
<span className="block font-bold" style={{ color: colors.brightWhite }}>Use my username domain directly</span>
|
||||||
|
<span className="mt-1 block text-xs opacity-70">Creates <strong>u-{username}.{branding.domain}</strong> with no name in front.</span>
|
||||||
|
</span>
|
||||||
|
</label>
|
||||||
|
{!useUsernameDomain && <div className="relative">
|
||||||
<input
|
<input
|
||||||
type="text"
|
type="text"
|
||||||
value={newDomainName}
|
value={newDomainName}
|
||||||
@@ -1138,7 +1153,7 @@ export const DomainManager = ({ userId, username, servers, sendMessage, showAler
|
|||||||
<div className="absolute right-3 top-1/2 -translate-y-1/2 text-xs font-black opacity-30 uppercase tracking-widest pointer-events-none">
|
<div className="absolute right-3 top-1/2 -translate-y-1/2 text-xs font-black opacity-30 uppercase tracking-widest pointer-events-none">
|
||||||
.u-{username}.{branding.domain}
|
.u-{username}.{branding.domain}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>}
|
||||||
</div>
|
</div>
|
||||||
</SettingsPanel>
|
</SettingsPanel>
|
||||||
|
|
||||||
@@ -1153,7 +1168,7 @@ export const DomainManager = ({ userId, username, servers, sendMessage, showAler
|
|||||||
|
|
||||||
<div className="flex gap-3">
|
<div className="flex gap-3">
|
||||||
<ActionButton onClick={() => setShowCreateModal(false)} variant="secondary" className="flex-1">Cancel</ActionButton>
|
<ActionButton onClick={() => setShowCreateModal(false)} variant="secondary" className="flex-1">Cancel</ActionButton>
|
||||||
<ActionButton onClick={createDomain} variant="primary" className="flex-1" disabled={actionInProgress || !newDomainName.trim()}>
|
<ActionButton onClick={createDomain} variant="primary" className="flex-1" disabled={actionInProgress || (!useUsernameDomain && !newDomainName.trim())}>
|
||||||
{actionInProgress ? <RefreshCw className="w-4 h-4 animate-spin" /> : 'Create Domain'}
|
{actionInProgress ? <RefreshCw className="w-4 h-4 animate-spin" /> : 'Create Domain'}
|
||||||
</ActionButton>
|
</ActionButton>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Reference in new issue
Block a user