💄 Restyled web pages
This commit is contained in:
@ -6,53 +6,44 @@
|
||||
|
||||
@if (Model.Account != null)
|
||||
{
|
||||
<div class="h-full bg-gray-100 dark:bg-gray-900 py-8 px-4">
|
||||
<div class="p-4 sm:p-8 bg-base-200">
|
||||
<div class="max-w-6xl mx-auto">
|
||||
<!-- Header -->
|
||||
<div class="mb-8">
|
||||
<h1 class="text-3xl font-bold text-gray-900 dark:text-white">Profile Settings</h1>
|
||||
<p class="text-gray-600 dark:text-gray-400 mt-2">Manage your account information and preferences</p>
|
||||
<h1 class="text-3xl font-bold">Profile Settings</h1>
|
||||
<p class="text-base-content/70 mt-2">Manage your account information and preferences</p>
|
||||
</div>
|
||||
|
||||
<!-- Two Column Layout -->
|
||||
<div class="flex flex-col md:flex-row gap-8">
|
||||
<!-- Left Pane - Profile Card -->
|
||||
<div class="w-full md:w-1/3 lg:w-1/4">
|
||||
<div class="bg-white dark:bg-gray-800 rounded-lg shadow-md p-6 sticky top-8">
|
||||
<div class="flex flex-col items-center text-center">
|
||||
<div class="card bg-base-100 shadow-xl sticky top-8">
|
||||
<div class="card-body items-center text-center">
|
||||
<!-- Avatar -->
|
||||
<div
|
||||
class="w-32 h-32 rounded-full bg-gray-200 dark:bg-gray-700 flex items-center justify-center mb-4 overflow-hidden">
|
||||
<span class="text-4xl text-gray-500 dark:text-gray-400">
|
||||
@Model.Account.Name?.Substring(0, 1).ToUpper()
|
||||
</span>
|
||||
<div class="avatar avatar-placeholder mb-4">
|
||||
<div class="bg-neutral text-neutral-content rounded-full w-32">
|
||||
<span class="text-4xl">@Model.Account.Name?[..1].ToUpper()</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Basic Info -->
|
||||
<h2 class="text-xl font-semibold text-gray-900 dark:text-white">
|
||||
@Model.Account.Nick
|
||||
</h2>
|
||||
<p class="text-gray-600 dark:text-gray-400">@Model.Account.Name</p>
|
||||
<h2 class="card-title">@Model.Account.Nick</h2>
|
||||
<p class="font-mono text-sm">@@@Model.Account.Name</p>
|
||||
|
||||
<!-- Stats -->
|
||||
<div
|
||||
class="mt-4 flex justify-around w-full border-t border-gray-200 dark:border-gray-700 pt-4">
|
||||
<div class="text-center">
|
||||
<div
|
||||
class="text-lg font-semibold text-gray-900 dark:text-white">@Model.Account.Profile.Level</div>
|
||||
<div class="text-sm text-gray-500 dark:text-gray-400">Level</div>
|
||||
<div class="stats stats-vertical shadow mt-4">
|
||||
<div class="stat">
|
||||
<div class="stat-title">Level</div>
|
||||
<div class="stat-value">@Model.Account.Profile.Level</div>
|
||||
</div>
|
||||
<div class="text-center">
|
||||
<div
|
||||
class="text-lg font-semibold text-gray-900 dark:text-white">@Model.Account.Profile.Experience</div>
|
||||
<div class="text-sm text-gray-500 dark:text-gray-400">XP</div>
|
||||
<div class="stat">
|
||||
<div class="stat-title">XP</div>
|
||||
<div class="stat-value">@Model.Account.Profile.Experience</div>
|
||||
</div>
|
||||
<div class="text-center">
|
||||
<div
|
||||
class="text-lg font-semibold text-gray-900 dark:text-white">
|
||||
@Model.Account.CreatedAt.ToDateTimeUtc().ToString("yyyy/MM/dd")
|
||||
</div>
|
||||
<div class="text-sm text-gray-500 dark:text-gray-400">Member since</div>
|
||||
<div class="stat">
|
||||
<div class="stat-title">Member since</div>
|
||||
<div class="stat-value">@Model.Account.CreatedAt.ToDateTimeUtc().ToString("yyyy/MM")</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -61,181 +52,107 @@
|
||||
|
||||
<!-- Right Pane - Tabbed Content -->
|
||||
<div class="flex-1">
|
||||
<div class="bg-white dark:bg-gray-800 rounded-lg shadow-md overflow-hidden">
|
||||
<!-- Tabs -->
|
||||
<div class="border-b border-gray-200 dark:border-gray-700">
|
||||
<nav class="flex -mb-px">
|
||||
<button type="button"
|
||||
class="tab-button active py-4 px-6 text-sm font-medium border-b-2 border-transparent text-gray-500 hover:text-gray-700 hover:border-gray-300 dark:text-gray-400 dark:hover:text-gray-200"
|
||||
data-tab="profile">
|
||||
Profile
|
||||
</button>
|
||||
<button type="button"
|
||||
class="tab-button py-4 px-6 text-sm font-medium border-b-2 border-transparent text-gray-500 hover:text-gray-700 hover:border-gray-300 dark:text-gray-400 dark:hover:text-gray-200"
|
||||
data-tab="security">
|
||||
Security
|
||||
</button>
|
||||
<button type="button"
|
||||
class="tab-button py-4 px-6 text-sm font-medium border-b-2 border-transparent text-gray-500 hover:text-gray-700 hover:border-gray-300 dark:text-gray-400 dark:hover:text-gray-200"
|
||||
data-tab="sessions">
|
||||
Sessions
|
||||
</button>
|
||||
</nav>
|
||||
<div role="tablist" class="tabs tabs-lift w-full">
|
||||
<input type="radio" name="profile-tabs" role="tab" class="tab" aria-label="Profile" checked />
|
||||
<div role="tabpanel" class="tab-content bg-base-100 border-base-300 p-6">
|
||||
<h2 class="text-xl font-semibold mb-6">Profile Information</h2>
|
||||
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-6">
|
||||
<div>
|
||||
<h3 class="text-lg font-medium mb-4">Basic Information</h3>
|
||||
<dl class="space-y-4">
|
||||
<div>
|
||||
<dt class="text-sm font-medium text-base-content/70">Full Name</dt>
|
||||
<dd class="mt-1 text-sm">@($"{Model.Account.Profile.FirstName} {Model.Account.Profile.MiddleName} {Model.Account.Profile.LastName}".Trim())</dd>
|
||||
</div>
|
||||
<div>
|
||||
<dt class="text-sm font-medium text-base-content/70">Username</dt>
|
||||
<dd class="mt-1 text-sm">@Model.Account.Name</dd>
|
||||
</div>
|
||||
<div>
|
||||
<dt class="text-sm font-medium text-base-content/70">Nickname</dt>
|
||||
<dd class="mt-1 text-sm">@Model.Account.Nick</dd>
|
||||
</div>
|
||||
<div>
|
||||
<dt class="text-sm font-medium text-base-content/70">Gender</dt>
|
||||
<dd class="mt-1 text-sm">@Model.Account.Profile.Gender</dd>
|
||||
</div>
|
||||
</dl>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<h3 class="text-lg font-medium mb-4">Additional Details</h3>
|
||||
<dl class="space-y-4">
|
||||
<div>
|
||||
<dt class="text-sm font-medium text-base-content/70">Location</dt>
|
||||
<dd class="mt-1 text-sm">@Model.Account.Profile.Location</dd>
|
||||
</div>
|
||||
<div>
|
||||
<dt class="text-sm font-medium text-base-content/70">Birthday</dt>
|
||||
<dd class="mt-1 text-sm">@Model.Account.Profile.Birthday?.ToString("MMMM d, yyyy", System.Globalization.CultureInfo.InvariantCulture)</dd>
|
||||
</div>
|
||||
<div>
|
||||
<dt class="text-sm font-medium text-base-content/70">Bio</dt>
|
||||
<dd class="mt-1 text-sm">@(string.IsNullOrEmpty(Model.Account.Profile.Bio) ? "No bio provided" : Model.Account.Profile.Bio)</dd>
|
||||
</div>
|
||||
</dl>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Tab Content -->
|
||||
<div class="p-6">
|
||||
<!-- Profile Tab -->
|
||||
<div id="profile-tab" class="tab-content">
|
||||
<h2 class="text-xl font-semibold text-gray-900 dark:text-white mb-6">Profile
|
||||
Information</h2>
|
||||
<input type="radio" name="profile-tabs" role="tab" class="tab" aria-label="Security" />
|
||||
<div role="tabpanel" class="tab-content bg-base-100 border-base-300 p-6">
|
||||
<h2 class="text-xl font-semibold mb-2">Security Settings</h2>
|
||||
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-6">
|
||||
<div>
|
||||
<h3 class="text-lg font-medium text-gray-900 dark:text-white mb-4">Basic
|
||||
Information</h3>
|
||||
<dl class="space-y-4">
|
||||
<div>
|
||||
<dt class="text-sm font-medium text-gray-500 dark:text-gray-400">Full
|
||||
Name
|
||||
</dt>
|
||||
<dd class="mt-1 text-sm text-gray-900 dark:text-white">
|
||||
@($"{Model.Account.Profile.FirstName} {Model.Account.Profile.MiddleName} {Model.Account.Profile.LastName}".Trim())
|
||||
</dd>
|
||||
<div class="space-y-6">
|
||||
<div class="card bg-base-300 shadow-xl">
|
||||
<div class="card-body">
|
||||
<h3 class="card-title">Access Token</h3>
|
||||
<p>Use this token to authenticate with the API</p>
|
||||
<div class="form-control">
|
||||
<div class="join">
|
||||
<input type="password" id="accessToken" value="@Model.AccessToken" readonly class="input input-bordered join-item flex-grow" />
|
||||
<button onclick="copyAccessToken()" class="btn join-item">Copy</button>
|
||||
</div>
|
||||
<div>
|
||||
<dt class="text-sm font-medium text-gray-500 dark:text-gray-400">
|
||||
Username
|
||||
</dt>
|
||||
<dd class="mt-1 text-sm text-gray-900 dark:text-white">@Model.Account.Name</dd>
|
||||
</div>
|
||||
<div>
|
||||
<dt class="text-sm font-medium text-gray-500 dark:text-gray-400">
|
||||
Nickname
|
||||
</dt>
|
||||
<dd class="mt-1 text-sm text-gray-900 dark:text-white">@Model.Account.Nick</dd>
|
||||
</div>
|
||||
<div>
|
||||
<dt class="text-sm font-medium text-gray-500 dark:text-gray-400">
|
||||
Gender
|
||||
</dt>
|
||||
<dd class="mt-1 text-sm text-gray-900 dark:text-white">@Model.Account.Profile.Gender</dd>
|
||||
</div>
|
||||
</dl>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<h3 class="text-lg font-medium text-gray-900 dark:text-white mb-4">Additional
|
||||
Details</h3>
|
||||
<dl class="space-y-4">
|
||||
<div>
|
||||
<dt class="text-sm font-medium text-gray-500 dark:text-gray-400">
|
||||
Location
|
||||
</dt>
|
||||
<dd class="mt-1 text-sm text-gray-900 dark:text-white">@Model.Account.Profile.Location</dd>
|
||||
</div>
|
||||
<div>
|
||||
<dt class="text-sm font-medium text-gray-500 dark:text-gray-400">
|
||||
Birthday
|
||||
</dt>
|
||||
<dd class="mt-1 text-sm text-gray-900 dark:text-white">
|
||||
@Model.Account.Profile.Birthday?.ToString("MMMM d, yyyy", System.Globalization.CultureInfo.InvariantCulture)
|
||||
</dd>
|
||||
</div>
|
||||
<div>
|
||||
<dt class="text-sm font-medium text-gray-500 dark:text-gray-400">Bio
|
||||
</dt>
|
||||
<dd class="mt-1 text-sm text-gray-900 dark:text-white">
|
||||
@(string.IsNullOrEmpty(Model.Account.Profile.Bio) ? "No bio provided" : Model.Account.Profile.Bio)
|
||||
</dd>
|
||||
</div>
|
||||
</dl>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mt-8 pt-6 border-t border-gray-200 dark:border-gray-700">
|
||||
<button type="button"
|
||||
class="inline-flex items-center px-4 py-2 border border-transparent text-sm font-medium rounded-md shadow-sm text-white bg-blue-600 hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500">
|
||||
Edit Profile
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Security Tab -->
|
||||
<div id="security-tab" class="tab-content hidden">
|
||||
<h2 class="text-xl font-semibold text-gray-900 dark:text-white mb-6">Security
|
||||
Settings</h2>
|
||||
|
||||
<div class="space-y-6">
|
||||
<div class="bg-white dark:bg-gray-800 shadow overflow-hidden sm:rounded-lg">
|
||||
<div class="px-4 py-5 sm:px-6">
|
||||
<h3 class="text-lg leading-6 font-medium text-gray-900 dark:text-white">
|
||||
Access Token</h3>
|
||||
<p class="mt-1 max-w-2xl text-sm text-gray-500 dark:text-gray-400">Use this
|
||||
token to authenticate with the API</p>
|
||||
</div>
|
||||
<div class="border-t border-gray-200 dark:border-gray-700 px-4 py-5 sm:px-6">
|
||||
<div class="flex items-center">
|
||||
<input type="password" id="accessToken" value="@Model.AccessToken"
|
||||
readonly
|
||||
class="form-input flex-grow rounded-md border-gray-300 shadow-sm focus:border-blue-500 focus:ring focus:ring-blue-500 focus:ring-opacity-50 dark:bg-gray-700 dark:border-gray-600 dark:text-white py-2 px-4"/>
|
||||
<button onclick="copyAccessToken()"
|
||||
class="ml-4 bg-blue-600 text-white py-2 px-4 rounded-md hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-opacity-50">
|
||||
Copy
|
||||
</button>
|
||||
</div>
|
||||
<p class="mt-2 text-sm text-gray-500 dark:text-gray-400">
|
||||
Keep this token secure and do not share it with anyone.
|
||||
</p>
|
||||
</div>
|
||||
<p class="text-sm text-base-content/70 mt-2">Keep this token secure and do not share it with anyone.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Sessions Tab -->
|
||||
<div id="sessions-tab" class="tab-content hidden">
|
||||
<h2 class="text-xl font-semibold text-gray-900 dark:text-white mb-6">Active
|
||||
Sessions</h2>
|
||||
<p class="text-gray-600 dark:text-gray-400 mb-6">This is a list of devices that have
|
||||
logged into your account. Revoke any sessions that you do not recognize.</p>
|
||||
<input type="radio" name="profile-tabs" role="tab" class="tab" aria-label="Sessions" />
|
||||
<div role="tabpanel" class="tab-content bg-base-100 border-base-300 p-6">
|
||||
<h2 class="text-xl font-semibold">Active Sessions</h2>
|
||||
<p class="text-base-content/70 mb-3">This is a list of devices that have logged into your account. Revoke any sessions that you do not recognize.</p>
|
||||
|
||||
<div class="bg-white dark:bg-gray-800 shadow overflow-hidden sm:rounded-lg">
|
||||
<ul class="divide-y divide-gray-200 dark:divide-gray-700">
|
||||
<li class="px-4 py-4 sm:px-6">
|
||||
<div class="flex items-center justify-between">
|
||||
<div class="flex items-center">
|
||||
<div
|
||||
class="flex-shrink-0 h-10 w-10 rounded-full bg-blue-100 dark:bg-blue-900 flex items-center justify-center">
|
||||
<svg class="h-6 w-6 text-blue-600 dark:text-blue-400"
|
||||
fill="currentColor" viewBox="0 0 20 20">
|
||||
<path fill-rule="evenodd"
|
||||
d="M4 4a2 2 0 012-2h8a2 2 0 012 2v12a2 2 0 01-2 2H6a2 2 0 01-2-2V4zm2 0v12h8V4H6z"
|
||||
clip-rule="evenodd"/>
|
||||
</svg>
|
||||
</div>
|
||||
<div class="ml-4">
|
||||
<div class="text-sm font-medium text-gray-900 dark:text-white">
|
||||
Current Session
|
||||
<div class="card bg-base-300 shadow-xl">
|
||||
<div class="card-body">
|
||||
<div class="overflow-x-auto">
|
||||
<table class="table">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>
|
||||
<div class="flex items-center gap-3">
|
||||
<div class="avatar">
|
||||
<div class="mask mask-squircle w-12 h-12">
|
||||
<svg class="h-full w-full text-blue-600 dark:text-blue-400" fill="currentColor" viewBox="0 0 20 20">
|
||||
<path fill-rule="evenodd" d="M4 4a2 2 0 012-2h8a2 2 0 012 2v12a2 2 0 01-2 2H6a2 2 0 01-2-2V4zm2 0v12h8V4H6z" clip-rule="evenodd" />
|
||||
</svg>
|
||||
</div>
|
||||
</div>
|
||||
<div class="text-sm text-gray-500 dark:text-gray-400">
|
||||
@($"{Request.Headers["User-Agent"]} • {DateTime.Now:MMMM d, yyyy 'at' h:mm tt}")
|
||||
<div>
|
||||
<div class="font-bold">Current Session</div>
|
||||
<div class="text-sm opacity-50">@($"{Request.Headers["User-Agent"]} • {DateTime.Now:MMMM d, yyyy 'at' h:mm tt}")</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="ml-4 flex-shrink-0">
|
||||
<span
|
||||
class="inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium bg-green-100 text-green-800 dark:bg-green-900 dark:text-green-200">
|
||||
Active now
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
<div class="bg-gray-50 dark:bg-gray-800 px-4 py-4 sm:px-6 text-right">
|
||||
<button type="button"
|
||||
class="inline-flex items-center px-4 py-2 border border-transparent text-sm font-medium rounded-md shadow-sm text-white bg-red-600 hover:bg-red-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-red-500">
|
||||
Sign out all other sessions
|
||||
</button>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div class="card-actions justify-end mt-4">
|
||||
<button type="button" class="btn btn-error">Sign out all other sessions</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -245,10 +162,7 @@
|
||||
<!-- Logout Button -->
|
||||
<div class="mt-6 flex justify-end">
|
||||
<form method="post" asp-page-handler="Logout">
|
||||
<button type="submit"
|
||||
class="inline-flex items-center px-4 py-2 border border-transparent text-sm font-medium rounded-md shadow-sm text-white bg-red-600 hover:bg-red-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-red-500">
|
||||
Sign out
|
||||
</button>
|
||||
<button type="submit" class="btn btn-error">Sign out</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
@ -258,54 +172,22 @@
|
||||
}
|
||||
else
|
||||
{
|
||||
<div class="min-h-screen flex items-center justify-center bg-gray-100 dark:bg-gray-900">
|
||||
<div class="max-w-md w-full p-8 bg-white dark:bg-gray-800 rounded-lg shadow-md text-center">
|
||||
<div class="text-red-500 text-5xl mb-4">
|
||||
<i class="fas fa-exclamation-circle"></i>
|
||||
<div class="hero min-h-screen bg-base-200">
|
||||
<div class="hero-content text-center">
|
||||
<div class="max-w-md">
|
||||
<div class="text-error text-5xl mb-4">
|
||||
<i class="fas fa-exclamation-circle"></i>
|
||||
</div>
|
||||
<h1 class="text-5xl font-bold">Profile Not Found</h1>
|
||||
<p class="py-6">User profile not found. Please log in to continue.</p>
|
||||
<a href="/auth/login" class="btn btn-primary">Go to Login</a>
|
||||
</div>
|
||||
<h2 class="text-2xl font-bold text-gray-900 dark:text-white mb-2">Profile Not Found</h2>
|
||||
<p class="text-gray-600 dark:text-gray-400 mb-6">User profile not found. Please log in to continue.</p>
|
||||
<a href="/auth/login"
|
||||
class="inline-flex items-center px-4 py-2 border border-transparent text-sm font-medium rounded-md shadow-sm text-white bg-blue-600 hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500">
|
||||
Go to Login
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
|
||||
@section Scripts {
|
||||
<script>
|
||||
// Tab functionality
|
||||
document.addEventListener('DOMContentLoaded', function () {
|
||||
// Get all tab buttons and content
|
||||
const tabButtons = document.querySelectorAll('.tab-button');
|
||||
const tabContents = document.querySelectorAll('.tab-content');
|
||||
|
||||
// Add click event listeners to tab buttons
|
||||
tabButtons.forEach(button => {
|
||||
button.addEventListener('click', function () {
|
||||
const tabId = this.getAttribute('data-tab');
|
||||
|
||||
// Update active tab button
|
||||
tabButtons.forEach(btn => btn.classList.remove('border-blue-500', 'text-blue-600', 'dark:text-blue-400'));
|
||||
this.classList.add('border-blue-500', 'text-blue-600', 'dark:text-blue-400');
|
||||
|
||||
// Show corresponding tab content
|
||||
tabContents.forEach(content => {
|
||||
content.classList.add('hidden');
|
||||
if (content.id === `${tabId}-tab`) {
|
||||
content.classList.remove('hidden');
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
// Show first tab by default
|
||||
if (tabButtons.length > 0) {
|
||||
tabButtons[0].click();
|
||||
}
|
||||
});
|
||||
|
||||
// Copy access token to clipboard
|
||||
function copyAccessToken() {
|
||||
const copyText = document.getElementById("accessToken");
|
||||
|
@ -4,10 +4,10 @@
|
||||
ViewData["Title"] = "Authorize Application";
|
||||
}
|
||||
|
||||
<div class="min-h-screen flex items-center justify-center bg-gray-50 dark:bg-gray-900 transition-colors duration-200 py-12 px-4 sm:px-6 lg:px-8">
|
||||
<div class="max-w-md w-full space-y-8 bg-white dark:bg-gray-800 p-8 rounded-lg shadow-lg border border-gray-200 dark:border-gray-700 transition-colors duration-200">
|
||||
<div class="text-center">
|
||||
<h2 class="mt-6 text-3xl font-extrabold text-gray-900 dark:text-white">
|
||||
<div class="min-h-screen flex items-center justify-center bg-base-200 py-12 px-4 sm:px-6 lg:px-8">
|
||||
<div class="card w-full max-w-md bg-base-100 shadow-xl">
|
||||
<div class="card-body">
|
||||
<h2 class="card-title justify-center text-2xl font-bold">
|
||||
Authorize Application
|
||||
</h2>
|
||||
@if (!string.IsNullOrEmpty(Model.AppName))
|
||||
@ -16,21 +16,17 @@
|
||||
<div class="flex items-center justify-center">
|
||||
@if (!string.IsNullOrEmpty(Model.AppLogo))
|
||||
{
|
||||
<div class="relative h-16 w-16 flex-shrink-0">
|
||||
<img class="h-16 w-16 rounded-lg object-cover border border-gray-200 dark:border-gray-700"
|
||||
src="@Model.AppLogo"
|
||||
alt="@Model.AppName logo"
|
||||
onerror="this.onerror=null; this.src='data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyNCAyNCIgZmlsbD0iY3VycmVudENvbG9yIiBjbGFzczz0idy02IGgtNiB0ZXh0LWdyYXktNDAwIj48cGF0aCBmaWxsLXJ1bGU9ImV2ZW5vZGQiIGQ9Ik0xOS42MDMgMy4wMDRjMS4xNTMgMCAyLjI2LjE4IDMuMzI5LjUxM2EuNzUuNzUgMCAwMS0uMzI4IDEuNDQ1IDE2LjkzIDE2LjkzIDAgMDAtNi4wMS0xuMTAzLjc1Ljc1IDAgMDEtLjY2OC0uNzQ4VjMuNzVBLjc1Ljc1IDAgMDExNi41IDNoMy4xMDN6TTMxLjUgMjEuMDA4Yy0uU0UuNzUgNzUuNzUgMCAwMTEuOTQ4LjA1MWMuMDgxLjkxOC4wNTIgMS44MzgtLjA4NiAyLjczNGEuNzUuNzUgMCAwMS0xLjQ5LS4xNTkgMjEuMzg2IDIxLjM4NiAwIDAwLjA2LTIuNTc1Ljc1Ljc1IDAgMDExLjU3OC0uMDQzem0tMy4wMi0xOC4wMmMuMDYgMS4wOTIuMDQgMi4xODctLjA1NiAzLjI3MmEuNzUuNzUgMCAwMS0xLjQ5Mi0uMTY0Yy4wOTItLjg3NC4xMDctMS43NTYuMDUxLTIuNjA3YS43NS43NSAwIDAxMS40OTctLjEwMXpNNS42MzcgNS42MzJjLS4zMzQuMS0uNjc2LjE4NS0xLjAyNi4yNTdhLjc1Ljc1IDAgMDEuMTQ5LTEuNDljLjQyNS0uMDg1Ljg1Mi0uMTg5IDEuMjY4LS4zMDRhLjc1Ljc1IDAgMDEuMzYgMS40Mzd6TTMuMzMgMTkuNjUzYy0uMTY1LS4zNS0uMzA4LS43MDctNDIuNjUzLjc1Ljc1IDAgMS4zODgtLjU0MiAxLjQ5LTEuMjg1LjA0Ni0uMzI2LjEwNi0uNjUyLjE4LS45NzZhLjc1Ljc1IDAgMTExLjQ2LS41M2MuMTA2LjQzNy4xODkuODgxLjI0NSAxLjM0OGEuNzUuNzUgMCAwMS0xLjQ5LjIzM3pNTEuMzUzIDIuNzY3YS43NS43NSAwIDAxLjc1LS4wMTdsLjAwMS4wMDFoLjAwMWwuMDAyLjAwMWwuMDA3LjAwM2wuMDI0LjAxM2MuMDIuMDEuMDQ1LjAyNS4wNzkuMDQ2LjA2Ny4wNDIuMTYxLjEwMi4yNzUuMTc4LjIzMi4xNTEuNTUuMzgzLjg1Ni42NjdsLjAyNy4wMjRjLjYxNi41NTggMS4yMTIgMS4xNzYgMS43MzMgMS44NDNhLjc1Ljc1IDAgMDEtMS4yNC44N2MtLjQ3LS42NzEtMS4wMzEtMS4yOTItMS42LFsxLjYxNi0xLjYxNmEzLjc1IDMuNzUgMCAwMC01LjMwNS01LjMwNGwtMS4wNi0xuMDZBNy4yNDMgNy4yNDMgMCAwMTUxLjM1MyAyLjc2N3pNNDQuMzc5IDkuNjRsLTEuNTYgMS41NmE2Ljk5IDYuOTkgMCAwMTIuMjMgNC4zMzcgNi45OSA2Ljk5IDAgMDEtMi4yMyA1LjE3NmwtMS41Ni0xLjU2QTguNDkgOC40OSAwIDAwNDUuNSAxNS41YzAtMi4yOTYtLjg3NC00LjQzLTIuMTIxLTYuMDF6bS0zLjUzLTMuNTNsLTEuMDYxLTEuMDZhNy4yNDMgNy4yNDMgMCAwMTkuMTkyIDkuE2x0LTEuMDYgMS4wNjFhNS43NDkgNS43NDkgMCAwMC04LjEzLTguMTN6TTM0LjUgMTUuNWE4Ljk5IDguOTkgMCAwMC0yLjYzMSA2LjM2OS43NS43NSAwIDExLTEuNDk0LS43MzlDNzIuMzkgMjAuMDYgMzMuNSAxNy41NzUgMzMuNSAxNS41YzAtMi4zNzYgMS4wOTktNC40MzggMi44MTEtNS44MTJsLS4zOTYtLjM5NmEuNzUuNzUgMCAwMTEuMDYtMS4wNkwzNy41IDkuNDRWMmgtL4wMDJhLjc1Ljc1IDAgMDEtLjc0OC0uNzVWMS41YS43NS43NSAwIDAxLjc1LS43NWg2YS43NS43NSAwIDAxLjc1Ljc1di4yNWEwIC43NS0uNzUuNzVoLS4wMDF2Ny40NGwzLjUzNy0zLjUzN2EuNzUuNzUgMCAwMTEuMDYgMS4wNmwtLjM5Ni4zOTZDMzUuNDAxIDExLjA2MiAzNC41IDEzLjEyNCAzNC41IDE1LjV6TTM5IDIuMjV2Ni4wMy0uMDAyYTEuNSAxLjUgMCAwMS0uNDQ0IDEuMDZsLTEuMDYxIDEuMDZBOC40OSA4LjQ5IDAgMDAzOSAxNS41YzAgMi4yOTYtLjg3NCA0LjQzLTIuMTIxIDYuMDFsMS41NiAxLjU2QTYuOTkgNi45OSAwIDAwNDIgMTUuNWE2Ljk5IDYuOTkgMCAwMC0yLjIzLTUuMTc2bC0xLjU2LTEuNTZhMS41IDEuNSAwIDAxLS40NC0xLjA2VjIuMjVoLTF6TTI0IDkuNzVhLjc1Ljc1IDAgMDEtLjc1Ljc1di0uNWMwLS40MTQuMzM2LS43NS43NS0uNzVoLjVjLjQxNCAwIC43NS4zMzYuNzUuNzV2LjVhLjc1Ljc1IDAgMDEtLjc1Ljc1aC0uNXpNMTkuNSAxM2EuNzUuNzUgMCAwMS0uNzUtLjc1di0uNWMwLS40MTQuMzM2LS43NS43NS0uNzVoLjVjLjQxNCAwIC43NS4zMzYuNzUuNzV2LjVhLjc1Ljc1IDAgMDEtLjc1Ljc1aC0uNXpNMTUgMTYuMjVhLjc1Ljc1IDAgMDEuNzUtLjc1aC41Yy40MTQgMCAuNzUuMzM2Ljc1Ljc1di41YS43NS43NSAwIDAxLS43NS43NWgtLjVhLjc1Ljc1IDAgMDEtLjc1LS43NXYtLjV6IiBjbGlwLXJ1bGU9ImV2ZW5vZGQiLz48L3N2Zz4=';">
|
||||
<div class="absolute inset-0 flex items-center justify-center bg-gray-100 dark:bg-gray-700 rounded-lg border border-gray-200 dark:border-gray-600">
|
||||
<span class="text-xs font-medium text-gray-500 dark:text-gray-300">@Model.AppName?[0]</span>
|
||||
<div class="avatar">
|
||||
<div class="w-16 rounded">
|
||||
<img src="@Model.AppLogo" alt="@Model.AppName logo" />
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
<div class="ml-4 text-left">
|
||||
<h3 class="text-lg font-medium text-gray-900 dark:text-white">@Model.AppName</h3>
|
||||
<h3 class="text-lg font-medium">@Model.AppName</h3>
|
||||
@if (!string.IsNullOrEmpty(Model.AppUri))
|
||||
{
|
||||
<a href="@Model.AppUri" class="text-sm text-blue-600 dark:text-blue-400 hover:text-blue-500 dark:hover:text-blue-300 transition-colors duration-200" target="_blank" rel="noopener noreferrer">
|
||||
<a href="@Model.AppUri" class="text-sm link link-primary" target="_blank" rel="noopener noreferrer">
|
||||
@Model.AppUri
|
||||
</a>
|
||||
}
|
||||
@ -38,77 +34,69 @@
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
<p class="mt-6 text-sm text-gray-600 dark:text-gray-300">
|
||||
<p class="mt-6 text-sm text-center">
|
||||
wants to access your account with the following permissions:
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="mt-6">
|
||||
<ul class="border border-gray-200 dark:border-gray-700 rounded-lg divide-y divide-gray-200 dark:divide-gray-700 overflow-hidden">
|
||||
@if (Model.Scope != null)
|
||||
{
|
||||
var scopeDescriptions = new Dictionary<string, (string Name, string Description)>
|
||||
<div class="mt-6">
|
||||
<ul class="menu bg-base-200 rounded-box">
|
||||
@if (Model.Scope != null)
|
||||
{
|
||||
["openid"] = ("OpenID", "Read your basic profile information"),
|
||||
["profile"] = ("Profile", "View your basic profile information"),
|
||||
["email"] = ("Email", "View your email address"),
|
||||
["offline_access"] = ("Offline Access", "Access your data while you're not using the application")
|
||||
};
|
||||
var scopeDescriptions = new Dictionary<string, (string Name, string Description)>
|
||||
{
|
||||
["openid"] = ("OpenID", "Read your basic profile information"),
|
||||
["profile"] = ("Profile", "View your basic profile information"),
|
||||
["email"] = ("Email", "View your email address"),
|
||||
["offline_access"] = ("Offline Access", "Access your data while you're not using the application")
|
||||
};
|
||||
|
||||
foreach (var scope in Model.Scope.Split(' ').Where(s => !string.IsNullOrWhiteSpace(s)))
|
||||
{
|
||||
var scopeInfo = scopeDescriptions.GetValueOrDefault(scope, (scope, scope.Replace('_', ' ')));
|
||||
<li class="px-4 py-3 hover:bg-gray-50 dark:hover:bg-gray-700 transition-colors duration-150">
|
||||
<div class="flex items-start">
|
||||
<div class="flex-shrink-0 pt-0.5">
|
||||
<svg class="h-5 w-5 text-green-500" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor" aria-hidden="true">
|
||||
foreach (var scope in Model.Scope.Split(' ').Where(s => !string.IsNullOrWhiteSpace(s)))
|
||||
{
|
||||
var scopeInfo = scopeDescriptions.GetValueOrDefault(scope, (scope, scope.Replace('_', ' ')));
|
||||
<li>
|
||||
<a>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5 text-success" viewBox="0 0 20 20" fill="currentColor">
|
||||
<path fill-rule="evenodd" d="M10 18a8 8 0 100-16 8 8 0 000 16zm3.707-9.293a1 1 0 00-1.414-1.414L9 10.586 7.707 9.293a1 1 0 00-1.414 1.414l2 2a1 1 0 001.414 0l4-4z" clip-rule="evenodd" />
|
||||
</svg>
|
||||
</div>
|
||||
<div class="ml-3">
|
||||
<p class="text-sm font-medium text-gray-900 dark:text-white">@scopeInfo.Item1</p>
|
||||
<p class="text-xs text-gray-500 dark:text-gray-400">@scopeInfo.Item2</p>
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
<div>
|
||||
<p class="font-medium">@scopeInfo.Item1</p>
|
||||
<p class="text-xs text-base-content/70">@scopeInfo.Item2</p>
|
||||
</div>
|
||||
</a>
|
||||
</li>
|
||||
}
|
||||
}
|
||||
}
|
||||
</ul>
|
||||
</ul>
|
||||
|
||||
<div class="mt-4 text-xs text-gray-500 dark:text-gray-400">
|
||||
<p>By authorizing, you allow this application to access your information on your behalf.</p>
|
||||
<div class="mt-4 text-xs text-base-content/70">
|
||||
<p>By authorizing, you allow this application to access your information on your behalf.</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<form method="post" class="mt-8 space-y-4">
|
||||
<input type="hidden" asp-for="ClientIdString" />
|
||||
<input type="hidden" asp-for="ResponseType" name="response_type" />
|
||||
<input type="hidden" asp-for="RedirectUri" name="redirect_uri" />
|
||||
<input type="hidden" asp-for="Scope" name="scope" />
|
||||
<input type="hidden" asp-for="State" name="state" />
|
||||
<input type="hidden" asp-for="Nonce" name="nonce" />
|
||||
<input type="hidden" asp-for="ReturnUrl" name="returnUrl" />
|
||||
<input type="hidden" name="code_challenge" value="@HttpContext.Request.Query["code_challenge"]" />
|
||||
<input type="hidden" name="code_challenge_method" value="@HttpContext.Request.Query["code_challenge_method"]" />
|
||||
<input type="hidden" name="response_mode" value="@HttpContext.Request.Query["response_mode"]" />
|
||||
|
||||
<div class="card-actions justify-center">
|
||||
<button type="submit" name="allow" value="true" class="btn btn-primary">Allow</button>
|
||||
<button type="submit" name="allow" value="false" class="btn btn-ghost">Deny</button>
|
||||
</div>
|
||||
|
||||
<div class="mt-4 pt-4 border-t border-base-300">
|
||||
<p class="text-xs text-center text-base-content/70">
|
||||
You can change these permissions later in your account settings.
|
||||
</p>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<form method="post" class="mt-8 space-y-4">
|
||||
<input type="hidden" asp-for="ClientIdString" />
|
||||
<input type="hidden" asp-for="ResponseType" name="response_type" />
|
||||
<input type="hidden" asp-for="RedirectUri" name="redirect_uri" />
|
||||
<input type="hidden" asp-for="Scope" name="scope" />
|
||||
<input type="hidden" asp-for="State" name="state" />
|
||||
<input type="hidden" asp-for="Nonce" name="nonce" />
|
||||
<input type="hidden" asp-for="ReturnUrl" name="returnUrl" />
|
||||
<input type="hidden" name="code_challenge" value="@HttpContext.Request.Query["code_challenge"]" />
|
||||
<input type="hidden" name="code_challenge_method" value="@HttpContext.Request.Query["code_challenge_method"]" />
|
||||
<input type="hidden" name="response_mode" value="@HttpContext.Request.Query["response_mode"]" />
|
||||
|
||||
<div class="flex flex-col space-y-3">
|
||||
<button type="submit" name="allow" value="true"
|
||||
class="w-full flex justify-center py-2.5 px-4 border border-transparent rounded-md shadow-sm text-sm font-medium text-white bg-blue-600 hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500 dark:focus:ring-offset-gray-800 transition-colors duration-200">
|
||||
Allow
|
||||
</button>
|
||||
<button type="submit" name="allow" value="false"
|
||||
class="w-full flex justify-center py-2.5 px-4 border border-gray-300 dark:border-gray-600 rounded-md shadow-sm text-sm font-medium text-gray-700 dark:text-gray-200 bg-white dark:bg-gray-700 hover:bg-gray-50 dark:hover:bg-gray-600 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500 dark:focus:ring-offset-gray-800 transition-colors duration-200">
|
||||
Deny
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="mt-4 pt-4 border-t border-gray-200 dark:border-gray-700">
|
||||
<p class="text-xs text-center text-gray-500 dark:text-gray-400">
|
||||
You can change these permissions later in your account settings.
|
||||
</p>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
@ -5,10 +5,12 @@
|
||||
Layout = "_Layout";
|
||||
}
|
||||
|
||||
<div class="h-full flex items-center justify-center">
|
||||
<div class="max-w-lg w-full mx-auto p-6 text-center">
|
||||
<h1 class="text-2xl font-bold text-gray-900 dark:text-white">Authentication Successful</h1>
|
||||
<p class="mb-6 text-gray-900 dark:text-white">You can now close this window and return to the application.</p>
|
||||
<div class="hero min-h-full bg-base-200">
|
||||
<div class="hero-content text-center">
|
||||
<div class="max-w-md">
|
||||
<h1 class="text-5xl font-bold">Authentication Successful</h1>
|
||||
<p class="py-6">You can now close this window and return to the application.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
@ -6,8 +6,11 @@
|
||||
Response.Redirect($"/web/auth/challenge/{Model.Id}/select-factor");
|
||||
}
|
||||
|
||||
<div class="h-full flex items-center justify-center bg-gray-100 dark:bg-gray-900">
|
||||
<div class="bg-white dark:bg-gray-800 p-8 rounded-lg shadow-md w-full max-w-md text-center">
|
||||
<p>Redirecting to authentication page...</p>
|
||||
<div class="hero min-h-full bg-base-200">
|
||||
<div class="hero-content text-center">
|
||||
<div class="max-w-md">
|
||||
<span class="loading loading-spinner loading-lg"></span>
|
||||
<p class="py-6">Redirecting to authentication page...</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
@ -5,32 +5,32 @@
|
||||
var returnUrl = Model.ReturnUrl ?? "";
|
||||
}
|
||||
|
||||
<div class="h-full flex items-center justify-center bg-gray-100 dark:bg-gray-900">
|
||||
<div class="bg-white dark:bg-gray-800 p-8 rounded-lg shadow-md w-full max-w-md">
|
||||
<h1 class="text-2xl font-bold text-center text-gray-900 dark:text-white mb-6">Login</h1>
|
||||
|
||||
<form method="post">
|
||||
<input type="hidden" asp-for="ReturnUrl" value="@returnUrl" />
|
||||
<div class="mb-4">
|
||||
<label asp-for="Username"
|
||||
class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1"></label>
|
||||
<input asp-for="Username"
|
||||
class="form-input mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-blue-500 focus:ring focus:ring-blue-500 focus:ring-opacity-50 dark:bg-gray-700 dark:border-gray-600 dark:text-white px-4 py-2"/>
|
||||
<span asp-validation-for="Username" class="text-red-500 text-sm mt-1"></span>
|
||||
<div class="hero min-h-full bg-base-200">
|
||||
<div class="hero-content w-full max-w-md">
|
||||
<div class="card w-full bg-base-100 shadow-xl">
|
||||
<div class="card-body px-8 py-7">
|
||||
<h1 class="card-title justify-center text-2xl font-bold">Welcome back!</h1>
|
||||
<p class="text-center">Login to your Solar Network account to continue.</p>
|
||||
<form method="post" class="mt-4">
|
||||
<input type="hidden" asp-for="ReturnUrl" value="@returnUrl"/>
|
||||
<div class="form-control">
|
||||
<label class="label" asp-for="Username">
|
||||
<span class="label-text">Username</span>
|
||||
</label>
|
||||
<input asp-for="Username" class="input input-bordered w-full"/>
|
||||
<span asp-validation-for="Username" class="text-error text-sm mt-1"></span>
|
||||
</div>
|
||||
<div class="form-control mt-6">
|
||||
<button type="submit" class="btn btn-primary w-full">Next</button>
|
||||
</div>
|
||||
<div class="text-sm text-center mt-4">
|
||||
<span class="text-base-content/70">Have no account?</span> <br/>
|
||||
<a href="https://solian.app/#/auth/create-account" class="link link-primary">
|
||||
Create a new account →
|
||||
</a>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<button type="submit"
|
||||
class="w-full bg-blue-600 text-white py-2 px-4 rounded-md hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-opacity-50">
|
||||
Next
|
||||
</button>
|
||||
</form>
|
||||
|
||||
<div class="mt-8 flex flex-col text-sm text-center">
|
||||
<span class="text-gray-900 dark:text-white opacity-80">Have no account?</span>
|
||||
|
||||
<a href="https://solian.app/#/auth/create-account"
|
||||
class="text-blue-600 hover:text-blue-500 dark:text-blue-400 dark:hover:text-blue-300">
|
||||
Create a new account →
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -5,54 +5,92 @@
|
||||
ViewData["Title"] = "Select Authentication Method";
|
||||
}
|
||||
|
||||
<div class="h-full flex items-center justify-center bg-gray-100 dark:bg-gray-900">
|
||||
<div class="bg-white dark:bg-gray-800 p-8 rounded-lg shadow-md w-full max-w-md">
|
||||
<h1 class="text-2xl font-bold text-center text-gray-900 dark:text-white mb-6">Select Authentication Method</h1>
|
||||
<div class="hero min-h-full bg-base-200">
|
||||
<div class="hero-content w-full max-w-md">
|
||||
<div class="card w-full bg-base-100 shadow-xl">
|
||||
<div class="card-body">
|
||||
<h1 class="card-title justify-center text-2xl font-bold">Select Authentication Method</h1>
|
||||
|
||||
@if (Model.AuthChallenge == null)
|
||||
{
|
||||
<p class="text-red-500 text-center">Challenge not found or expired.</p>
|
||||
}
|
||||
else if (Model.AuthChallenge.StepRemain == 0)
|
||||
{
|
||||
<p class="text-green-600 dark:text-green-400 text-center">Challenge completed. Redirecting...</p>
|
||||
}
|
||||
else
|
||||
{
|
||||
<p class="text-gray-700 dark:text-gray-300 mb-4">Please select an authentication method:</p>
|
||||
|
||||
<div class="space-y-4">
|
||||
@foreach (var factor in Model.AuthFactors)
|
||||
@if (Model.AuthChallenge == null)
|
||||
{
|
||||
<div class="mb-4">
|
||||
<form method="post" asp-page-handler="SelectFactor" class="w-full" id="factor-@factor.Id">
|
||||
<input type="hidden" name="SelectedFactorId" value="@factor.Id"/>
|
||||
<div class="alert alert-error">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="stroke-current shrink-0 h-6 w-6" fill="none"
|
||||
viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
|
||||
d="M10 14l2-2m0 0l2-2m-2 2l-2-2m2 2l2 2m7-2a9 9 0 11-18 0 9 9 0 0118 0z"/>
|
||||
</svg>
|
||||
<span>Challenge not found or expired.</span>
|
||||
</div>
|
||||
}
|
||||
else if (Model.AuthChallenge.StepRemain == 0)
|
||||
{
|
||||
<div class="alert alert-success">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="stroke-current shrink-0 h-6 w-6" fill="none"
|
||||
viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
|
||||
d="M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z"/>
|
||||
</svg>
|
||||
<span>Challenge completed. Redirecting...</span>
|
||||
</div>
|
||||
}
|
||||
else
|
||||
{
|
||||
<p class="text-center">Please select an authentication method:</p>
|
||||
|
||||
@if (factor.Type == AccountAuthFactorType.EmailCode)
|
||||
{
|
||||
<div class="mb-3">
|
||||
<label for="hint-@factor.Id" class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1">
|
||||
Email to send code to
|
||||
</label>
|
||||
<input type="email"
|
||||
id="hint-@factor.Id"
|
||||
name="hint"
|
||||
class="w-full px-3 py-2 border border-gray-300 dark:border-gray-600 rounded-md shadow-sm focus:outline-none focus:ring-blue-500 focus:border-blue-500 dark:bg-gray-700 dark:text-white"
|
||||
placeholder="Enter your email"
|
||||
required>
|
||||
</div>
|
||||
}
|
||||
<div class="space-y-4">
|
||||
@foreach (var factor in Model.AuthFactors)
|
||||
{
|
||||
<form method="post" asp-page-handler="SelectFactor" class="w-full" id="factor-@factor.Id">
|
||||
<input type="hidden" name="SelectedFactorId" value="@factor.Id"/>
|
||||
|
||||
<button type="submit"
|
||||
class="w-full text-left p-4 bg-gray-50 dark:bg-gray-700 hover:bg-gray-100 dark:hover:bg-gray-600 rounded-lg transition-colors">
|
||||
<div class="font-medium text-gray-900 dark:text-white">@GetFactorDisplayName(factor.Type)</div>
|
||||
<div class="text-sm text-gray-500 dark:text-gray-400">@GetFactorDescription(factor.Type)</div>
|
||||
</button>
|
||||
</form>
|
||||
@if (factor.Type == AccountAuthFactorType.EmailCode)
|
||||
{
|
||||
<div class="card w-full bg-base-200 card-sm shadow-sm rounded-md">
|
||||
<div class="py-4 px-5 align-items-center">
|
||||
<div>
|
||||
<h2 class="card-title">@GetFactorDisplayName(factor.Type)</h2>
|
||||
<p>@GetFactorDescription(factor.Type)</p>
|
||||
</div>
|
||||
<div class="join w-full mt-2">
|
||||
<div class="flex-1">
|
||||
<label class="input join-item input-sm">
|
||||
<input id="hint-@factor.Id" type="email"
|
||||
placeholder="mail@site.com" required/>
|
||||
</label>
|
||||
</div>
|
||||
<button class="btn btn-primary join-item btn-sm">
|
||||
<span class="material-symbols-outlined">
|
||||
arrow_right_alt
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
else
|
||||
{
|
||||
<div class="card w-full bg-base-200 card-sm shadow-sm rounded-md">
|
||||
<div class="flex py-4 px-5 align-items-center">
|
||||
<div class="flex-1">
|
||||
<h2 class="card-title">@GetFactorDisplayName(factor.Type)</h2>
|
||||
<p>@GetFactorDescription(factor.Type)</p>
|
||||
</div>
|
||||
<div class="justify-end card-actions">
|
||||
<button type="submit" class="btn btn-primary btn-sm">
|
||||
<span class="material-symbols-outlined">
|
||||
arrow_right_alt
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
</form>
|
||||
}
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
@ -5,70 +5,79 @@
|
||||
ViewData["Title"] = "Verify Your Identity";
|
||||
}
|
||||
|
||||
<div class="h-full flex items-center justify-center bg-gray-100 dark:bg-gray-900">
|
||||
<div class="bg-white dark:bg-gray-800 px-8 pt-8 pb-4 rounded-lg shadow-md w-full max-w-md">
|
||||
<h1 class="text-2xl font-bold text-center text-gray-900 dark:text-white mb-2">Verify Your Identity</h1>
|
||||
<p class="text-center text-gray-600 dark:text-gray-300 mb-6">
|
||||
@switch (Model.FactorType)
|
||||
{
|
||||
case AccountAuthFactorType.EmailCode:
|
||||
<span>We've sent a verification code to your email.</span>
|
||||
break;
|
||||
case AccountAuthFactorType.InAppCode:
|
||||
<span>Enter the code from your authenticator app.</span>
|
||||
break;
|
||||
case AccountAuthFactorType.TimedCode:
|
||||
<span>Enter your time-based verification code.</span>
|
||||
break;
|
||||
case AccountAuthFactorType.PinCode:
|
||||
<span>Enter your PIN code.</span>
|
||||
break;
|
||||
case AccountAuthFactorType.Password:
|
||||
<span>Enter your password.</span>
|
||||
break;
|
||||
default:
|
||||
<span>Please verify your identity.</span>
|
||||
break;
|
||||
}
|
||||
</p>
|
||||
<div class="hero min-h-full bg-base-200">
|
||||
<div class="hero-content w-full max-w-md">
|
||||
<div class="card w-full bg-base-100 shadow-xl">
|
||||
<div class="card-body px-8 py-7">
|
||||
<h1 class="card-title justify-center text-2xl font-bold">Verify Your Identity</h1>
|
||||
<p class="text-center">
|
||||
@switch (Model.FactorType)
|
||||
{
|
||||
case AccountAuthFactorType.EmailCode:
|
||||
<span>We've sent a verification code to your email.</span>
|
||||
break;
|
||||
case AccountAuthFactorType.InAppCode:
|
||||
<span>Enter the code from your authenticator app.</span>
|
||||
break;
|
||||
case AccountAuthFactorType.TimedCode:
|
||||
<span>Enter your time-based verification code.</span>
|
||||
break;
|
||||
case AccountAuthFactorType.PinCode:
|
||||
<span>Enter your PIN code.</span>
|
||||
break;
|
||||
case AccountAuthFactorType.Password:
|
||||
<span>Enter your password.</span>
|
||||
break;
|
||||
default:
|
||||
<span>Please verify your identity.</span>
|
||||
break;
|
||||
}
|
||||
</p>
|
||||
|
||||
@if (Model.AuthChallenge == null)
|
||||
{
|
||||
<p class="text-red-500 text-center">Challenge not found or expired.</p>
|
||||
}
|
||||
else if (Model.AuthChallenge.StepRemain == 0)
|
||||
{
|
||||
<p class="text-green-600 dark:text-green-400 text-center">Verification successful. Redirecting...</p>
|
||||
}
|
||||
else
|
||||
{
|
||||
<form method="post" class="space-y-4">
|
||||
<div asp-validation-summary="ModelOnly" class="text-red-500 text-sm"></div>
|
||||
@if (Model.AuthChallenge == null)
|
||||
{
|
||||
<div class="alert alert-error">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="stroke-current shrink-0 h-6 w-6" fill="none" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M10 14l2-2m0 0l2-2m-2 2l-2-2m2 2l2 2m7-2a9 9 0 11-18 0 9 9 0 0118 0z" /></svg>
|
||||
<span>Challenge not found or expired.</span>
|
||||
</div>
|
||||
}
|
||||
else if (Model.AuthChallenge.StepRemain == 0)
|
||||
{
|
||||
<div class="alert alert-success">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="stroke-current shrink-0 h-6 w-6" fill="none" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z" /></svg>
|
||||
<span>Verification successful. Redirecting...</span>
|
||||
</div>
|
||||
}
|
||||
else
|
||||
{
|
||||
<form method="post" class="space-y-4">
|
||||
<div asp-validation-summary="ModelOnly" class="text-error text-sm"></div>
|
||||
|
||||
<div class="mb-4">
|
||||
<label asp-for="Code" class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1">
|
||||
@(Model.FactorType == AccountAuthFactorType.Password ? "Use your password" : "Verification Code")
|
||||
</label>
|
||||
<input asp-for="Code"
|
||||
class="form-input mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-blue-500 focus:ring focus:ring-blue-500 focus:ring-opacity-50 dark:bg-gray-700 dark:border-gray-600 dark:text-white px-4 py-2"
|
||||
autocomplete="one-time-code"
|
||||
type="password"
|
||||
autofocus />
|
||||
<span asp-validation-for="Code" class="text-red-500 text-sm mt-1"></span>
|
||||
</div>
|
||||
<div class="form-control">
|
||||
<label asp-for="Code" class="label">
|
||||
<span class="label-text">@(Model.FactorType == AccountAuthFactorType.Password ? "Use your password" : "Verification Code")</span>
|
||||
</label>
|
||||
<input asp-for="Code"
|
||||
class="input input-bordered w-full"
|
||||
autocomplete="one-time-code"
|
||||
type="password"
|
||||
autofocus />
|
||||
<span asp-validation-for="Code" class="text-error text-sm mt-1"></span>
|
||||
</div>
|
||||
|
||||
<button type="submit"
|
||||
class="w-full bg-blue-600 text-white py-2 px-4 rounded-md hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-opacity-50">
|
||||
Verify
|
||||
</button>
|
||||
<div class="form-control mt-6">
|
||||
<button type="submit" class="btn btn-primary w-full">Verify</button>
|
||||
</div>
|
||||
|
||||
<div class="text-center mt-4">
|
||||
<a asp-page="SelectFactor" asp-route-id="@Model.Id" class="text-sm text-blue-600 hover:text-blue-500 dark:text-blue-400 dark:hover:text-blue-300">
|
||||
← Back to authentication methods
|
||||
</a>
|
||||
</div>
|
||||
</form>
|
||||
}
|
||||
<div class="text-center mt-4">
|
||||
<a asp-page="SelectFactor" asp-route-id="@Model.Id" class="link link-primary text-sm">
|
||||
← Back to authentication methods
|
||||
</a>
|
||||
</div>
|
||||
</form>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
@ -38,72 +38,72 @@
|
||||
</script>
|
||||
}
|
||||
|
||||
<div class="h-full flex items-center justify-center">
|
||||
<div class="max-w-lg w-full mx-auto p-6">
|
||||
<div class="text-center">
|
||||
<h1 class="text-2xl font-bold text-gray-900 dark:text-white">Security Check</h1>
|
||||
<p class="mb-6 text-gray-900 dark:text-white">Please complete the contest below to confirm you're not a robot</p>
|
||||
<div class="hero min-h-full bg-base-200">
|
||||
<div class="hero-content text-center">
|
||||
<div class="max-w-md">
|
||||
<div class="card bg-base-100 shadow-xl">
|
||||
<div class="card-body">
|
||||
<h1 class="card-title">Security Check</h1>
|
||||
<p>Please complete the contest below to confirm you're not a robot</p>
|
||||
|
||||
<div class="flex justify-center mb-8">
|
||||
@switch (provider)
|
||||
{
|
||||
case "cloudflare":
|
||||
<div class="cf-turnstile"
|
||||
data-sitekey="@apiKey"
|
||||
data-callback="onSuccess">
|
||||
</div>
|
||||
break;
|
||||
case "recaptcha":
|
||||
<div class="g-recaptcha"
|
||||
data-sitekey="@apiKey"
|
||||
data-callback="onSuccess">
|
||||
</div>
|
||||
break;
|
||||
case "hcaptcha":
|
||||
<div class="h-captcha"
|
||||
data-sitekey="@apiKey"
|
||||
data-callback="onSuccess">
|
||||
</div>
|
||||
break;
|
||||
default:
|
||||
<div class="p-4 bg-yellow-100 dark:bg-yellow-900 rounded-lg">
|
||||
<p class="text-yellow-800 dark:text-yellow-200">
|
||||
Captcha provider not configured correctly.
|
||||
</p>
|
||||
</div>
|
||||
break;
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex justify-center my-8">
|
||||
@switch (provider)
|
||||
{
|
||||
case "cloudflare":
|
||||
<div class="cf-turnstile"
|
||||
data-sitekey="@apiKey"
|
||||
data-callback="onSuccess">
|
||||
</div>
|
||||
break;
|
||||
case "recaptcha":
|
||||
<div class="g-recaptcha"
|
||||
data-sitekey="@apiKey"
|
||||
data-callback="onSuccess">
|
||||
</div>
|
||||
break;
|
||||
case "hcaptcha":
|
||||
<div class="h-captcha"
|
||||
data-sitekey="@apiKey"
|
||||
data-callback="onSuccess">
|
||||
</div>
|
||||
break;
|
||||
default:
|
||||
<div class="alert alert-warning">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="stroke-current shrink-0 h-6 w-6" fill="none" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z" /></svg>
|
||||
<span>Captcha provider not configured correctly.</span>
|
||||
</div>
|
||||
break;
|
||||
}
|
||||
</div>
|
||||
|
||||
<div class="mt-8 text-center text-sm">
|
||||
<div class="font-semibold text-gray-700 dark:text-gray-300 mb-1">Solar Network Anti-Robot</div>
|
||||
<div class="text-gray-600 dark:text-gray-400">
|
||||
Powered by
|
||||
@switch (provider)
|
||||
{
|
||||
case "cloudflare":
|
||||
<a href="https://www.cloudflare.com/turnstile/"
|
||||
class="hover:text-blue-600 dark:hover:text-blue-400 transition-colors">
|
||||
Cloudflare Turnstile
|
||||
</a>
|
||||
break;
|
||||
case "recaptcha":
|
||||
<a href="https://www.google.com/recaptcha/"
|
||||
class="hover:text-blue-600 dark:hover:text-blue-400 transition-colors">
|
||||
Google reCaptcha
|
||||
</a>
|
||||
break;
|
||||
default:
|
||||
<span>Nothing</span>
|
||||
break;
|
||||
}
|
||||
<br/>
|
||||
Hosted by
|
||||
<a href="https://github.com/Solsynth/DysonNetwork"
|
||||
class="hover:text-blue-600 dark:hover:text-blue-400 transition-colors">
|
||||
DysonNetwork.Sphere
|
||||
</a>
|
||||
<div class="text-center text-sm">
|
||||
<div class="font-semibold mb-1">Solar Network Anti-Robot</div>
|
||||
<div class="text-base-content/70">
|
||||
Powered by
|
||||
@switch (provider)
|
||||
{
|
||||
case "cloudflare":
|
||||
<a href="https://www.cloudflare.com/turnstile/" class="link link-hover">
|
||||
Cloudflare Turnstile
|
||||
</a>
|
||||
break;
|
||||
case "recaptcha":
|
||||
<a href="https://www.google.com/recaptcha/" class="link link-hover">
|
||||
Google reCaptcha
|
||||
</a>
|
||||
break;
|
||||
default:
|
||||
<span>Nothing</span>
|
||||
break;
|
||||
}
|
||||
<br/>
|
||||
Hosted by
|
||||
<a href="https://github.com/Solsynth/DysonNetwork" class="link link-hover">
|
||||
DysonNetwork.Sphere
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -4,26 +4,20 @@
|
||||
ViewData["Title"] = "The Solar Network";
|
||||
}
|
||||
|
||||
<div class="container-default h-full text-center flex flex-col justify-center items-center">
|
||||
<div class="mx-auto max-w-2xl">
|
||||
<h1 class="text-4xl font-bold tracking-tight text-gray-900 dark:text-white sm:text-6xl">
|
||||
Solar Network
|
||||
</h1>
|
||||
<p class="mt-6 text-lg leading-8 text-gray-600 dark:text-gray-300">
|
||||
This Solar Network instance is up and running.
|
||||
</p>
|
||||
<div class="mt-10 flex items-center justify-center gap-x-6">
|
||||
<a href="https://sn.solsynth.dev" target="_blank" class="btn-primary">
|
||||
Get started
|
||||
</a>
|
||||
</div>
|
||||
<div class="flex items-center justify-center gap-x-6 mt-6">
|
||||
<a href="/swagger" target="_blank" class="btn-text">
|
||||
<span aria-hidden="true">λ </span> API Docs
|
||||
</a>
|
||||
<a href="https://kb.solsynth.dev" target="_blank" class="btn-text">
|
||||
Learn more <span aria-hidden="true">→</span>
|
||||
</a>
|
||||
</div>
|
||||
<div class="hero min-h-full bg-base-200">
|
||||
<div class="hero-content text-center">
|
||||
<div class="max-w-md">
|
||||
<h1 class="text-5xl font-bold">Solar Network</h1>
|
||||
<p class="py-6">This Solar Network instance is up and running.</p>
|
||||
<a href="https://sn.solsynth.dev" target="_blank" class="btn btn-primary">Get started</a>
|
||||
<div class="flex items-center justify-center gap-x-6 mt-6">
|
||||
<a href="/swagger" target="_blank" class="btn btn-ghost">
|
||||
<span aria-hidden="true">λ </span> API Docs
|
||||
</a>
|
||||
<a href="https://kb.solsynth.dev" target="_blank" class="btn btn-ghost">
|
||||
Learn more <span aria-hidden="true">→</span>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -6,6 +6,5 @@ public class IndexModel : PageModel
|
||||
{
|
||||
public void OnGet()
|
||||
{
|
||||
// Add any page initialization logic here
|
||||
}
|
||||
}
|
@ -5,34 +5,44 @@
|
||||
<meta charset="utf-8"/>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
|
||||
<title>@ViewData["Title"]</title>
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||
<link
|
||||
href="https://fonts.googleapis.com/css2?family=Noto+Sans+Mono:wght@100..900&family=Nunito:ital,wght@0,200..1000;1,200..1000&display=swap"
|
||||
rel="stylesheet">
|
||||
<link rel="stylesheet" href="~/css/styles.css" asp-append-version="true"/>
|
||||
<link
|
||||
href="https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined:opsz,wght,FILL,GRAD@20..48,100..700,0..1,-50..200"
|
||||
rel="stylesheet"
|
||||
/>
|
||||
</head>
|
||||
<body class="h-[calc(100dvh-118px)] mt-[64px] bg-white dark:bg-gray-900">
|
||||
<header class="bg-white dark:bg-gray-800 shadow-sm fixed left-0 right-0 top-0 z-50">
|
||||
<nav class="container-default">
|
||||
<div class="flex justify-between h-16 items-center">
|
||||
<div class="flex">
|
||||
<a href="/" class="text-xl font-bold text-gray-900 dark:text-white">Solar Network</a>
|
||||
</div>
|
||||
<div class="flex items-center ml-auto">
|
||||
@if (Context.Request.Cookies.TryGetValue(AuthConstants.CookieTokenName, out _))
|
||||
{
|
||||
<a href="/web/account/profile" class="text-gray-900 dark:text-white hover:text-gray-700 dark:hover:text-gray-300 px-3 py-2 rounded-md text-sm font-medium">Profile</a>
|
||||
<form method="post" asp-page="/Account/Profile" asp-page-handler="Logout" class="inline">
|
||||
<button type="submit" class="text-gray-900 dark:text-white hover:text-gray-700 dark:hover:text-gray-300 px-3 py-2 rounded-md text-sm font-medium">Logout</button>
|
||||
<body class="h-full bg-base-200">
|
||||
<header class="navbar bg-base-100/35 backdrop-blur-md shadow-xl fixed left-0 right-0 top-0 z-50 px-5">
|
||||
<div class="flex-1">
|
||||
<a class="btn btn-ghost text-xl">Solar Network</a>
|
||||
</div>
|
||||
<div class="flex-none">
|
||||
<ul class="menu menu-horizontal px-1">
|
||||
@if (Context.Request.Cookies.TryGetValue(AuthConstants.CookieTokenName, out _))
|
||||
{
|
||||
<li><a href="/web/account/profile">Profile</a></li>
|
||||
<li>
|
||||
<form method="post" asp-page="/Account/Profile" asp-page-handler="Logout">
|
||||
<button type="submit">Logout</button>
|
||||
</form>
|
||||
}
|
||||
else
|
||||
{
|
||||
<a href="/web/auth/login" class="text-gray-900 dark:text-white hover:text-gray-700 dark:hover:text-gray-300 px-3 py-2 rounded-md text-sm font-medium">Login</a>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
</li>
|
||||
}
|
||||
else
|
||||
{
|
||||
<li>
|
||||
<a href="/web/auth/login"><span class="material-symbols-outlined">login</span></a>
|
||||
</li>
|
||||
}
|
||||
</ul>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
@* The header 64px *@
|
||||
<main class="h-full">
|
||||
<main class="h-full pt-16">
|
||||
@RenderBody()
|
||||
</main>
|
||||
|
||||
|
@ -6,95 +6,85 @@
|
||||
ViewData["Title"] = "Magic Spell";
|
||||
}
|
||||
|
||||
<div class="h-full flex items-center justify-center">
|
||||
<div class="max-w-lg w-full mx-auto p-6">
|
||||
<div class="text-center">
|
||||
<h1 class="text-3xl font-bold text-gray-900 dark:text-white mb-4">Magic Spell</h1>
|
||||
<div class="hero min-h-full bg-base-200">
|
||||
<div class="hero-content text-center">
|
||||
<div class="max-w-md">
|
||||
<h1 class="text-5xl font-bold mb-4">Magic Spell</h1>
|
||||
|
||||
@if (Model.IsSuccess)
|
||||
{
|
||||
<div class="p-4 bg-green-100 dark:bg-green-900 rounded-lg mb-6">
|
||||
<p class="text-green-800 dark:text-green-200">The spell was applied successfully!</p>
|
||||
<p class="text-green-800 dark:text-green-200 opacity-80">Now you can close this page.</p>
|
||||
<div class="alert alert-success">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="stroke-current shrink-0 h-6 w-6" fill="none" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z" /></svg>
|
||||
<span>The spell was applied successfully!</span>
|
||||
<p>Now you can close this page.</p>
|
||||
</div>
|
||||
}
|
||||
else if (Model.CurrentSpell == null)
|
||||
{
|
||||
<div class="p-4 bg-yellow-100 dark:bg-yellow-900 rounded-lg">
|
||||
<p class="text-yellow-800 dark:text-yellow-200">The spell was expired or does not exist.</p>
|
||||
<div class="alert alert-warning">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="stroke-current shrink-0 h-6 w-6" fill="none" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z" /></svg>
|
||||
<span>The spell was expired or does not exist.</span>
|
||||
</div>
|
||||
}
|
||||
else
|
||||
{
|
||||
<div
|
||||
class="px-4 py-12 bg-white dark:bg-gray-800 text-gray-900 dark:text-white shadow-lg rounded-lg mb-6">
|
||||
<div class="mb-2">
|
||||
<p>
|
||||
<span class="font-medium">The spell is for </span>
|
||||
<span
|
||||
class="font-bold">@System.Text.RegularExpressions.Regex.Replace(Model.CurrentSpell!.Type.ToString(), "([a-z])([A-Z])", "$1 $2")</span>
|
||||
</p>
|
||||
<p><span class="font-medium">for @@</span>@Model.CurrentSpell.Account?.Name</p>
|
||||
</div>
|
||||
<div class="text-sm opacity-80">
|
||||
@if (Model.CurrentSpell.ExpiresAt.HasValue)
|
||||
{
|
||||
<p>Available until @Model.CurrentSpell.ExpiresAt.Value.ToDateTimeUtc().ToString("g")</p>
|
||||
}
|
||||
@if (Model.CurrentSpell.AffectedAt.HasValue)
|
||||
{
|
||||
<p>Available after @Model.CurrentSpell.AffectedAt.Value.ToDateTimeUtc().ToString("g")</p>
|
||||
}
|
||||
</div>
|
||||
<p class="text-sm opacity-80">Would you like to apply this spell?</p>
|
||||
</div>
|
||||
|
||||
<form method="post" class="mt-4">
|
||||
<input type="hidden" asp-for="CurrentSpell!.Id"/>
|
||||
|
||||
@if (Model.CurrentSpell?.Type == MagicSpellType.AuthPasswordReset)
|
||||
{
|
||||
<div class="mb-4">
|
||||
<label
|
||||
asp-for="NewPassword"
|
||||
class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-2"
|
||||
>
|
||||
New Password
|
||||
</label>
|
||||
<input type="password"
|
||||
asp-for="NewPassword"
|
||||
required
|
||||
minlength="8"
|
||||
style="padding: 0.5rem 1rem"
|
||||
placeholder="Your new password"
|
||||
class="w-full border-2 border-gray-300 dark:border-gray-600 rounded-lg
|
||||
focus:ring-2 focus:ring-blue-400
|
||||
dark:text-white bg-gray-100 dark:bg-gray-800"/>
|
||||
<div class="card bg-base-100 shadow-xl">
|
||||
<div class="card-body">
|
||||
<h2 class="card-title">
|
||||
@System.Text.RegularExpressions.Regex.Replace(Model.CurrentSpell!.Type.ToString(), "([a-z])([A-Z])", "$1 $2")
|
||||
</h2>
|
||||
<p>for @@ @Model.CurrentSpell.Account?.Name</p>
|
||||
<div class="text-sm opacity-80">
|
||||
@if (Model.CurrentSpell.ExpiresAt.HasValue)
|
||||
{
|
||||
<p>Available until @Model.CurrentSpell.ExpiresAt.Value.ToDateTimeUtc().ToString("g")</p>
|
||||
}
|
||||
@if (Model.CurrentSpell.AffectedAt.HasValue)
|
||||
{
|
||||
<p>Available after @Model.CurrentSpell.AffectedAt.Value.ToDateTimeUtc().ToString("g")</p>
|
||||
}
|
||||
</div>
|
||||
}
|
||||
<p class="text-sm opacity-80">Would you like to apply this spell?</p>
|
||||
|
||||
<button type="submit"
|
||||
class="px-6 py-3 bg-blue-500 text-white rounded-lg hover:bg-blue-600 transition-colors
|
||||
transform hover:scale-105 focus:outline-none focus:ring-2 focus:ring-blue-400">
|
||||
Apply
|
||||
</button>
|
||||
</form>
|
||||
<form method="post" class="mt-4">
|
||||
<input type="hidden" asp-for="CurrentSpell!.Id"/>
|
||||
|
||||
@if (Model.CurrentSpell?.Type == MagicSpellType.AuthPasswordReset)
|
||||
{
|
||||
<div class="form-control w-full max-w-xs">
|
||||
<label class="label" asp-for="NewPassword">
|
||||
<span class="label-text">New Password</span>
|
||||
</label>
|
||||
<input type="password"
|
||||
asp-for="NewPassword"
|
||||
required
|
||||
minlength="8"
|
||||
placeholder="Your new password"
|
||||
class="input input-bordered w-full max-w-xs"/>
|
||||
</div>
|
||||
}
|
||||
|
||||
<div class="card-actions justify-end mt-4">
|
||||
<button type="submit" class="btn btn-primary">Apply</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
|
||||
<div class="mt-8 text-center text-sm">
|
||||
<div class="font-semibold text-gray-700 dark:text-gray-300 mb-1">Solar Network</div>
|
||||
<div class="text-gray-600 dark:text-gray-400">
|
||||
<a href="https://solsynth.dev" class="hover:text-blue-600 dark:hover:text-blue-400 transition-colors">
|
||||
Solsynth LLC
|
||||
</a>
|
||||
© @DateTime.Now.Year
|
||||
<br/>
|
||||
Powered by
|
||||
<a href="https://github.com/Solsynth/DysonNetwork"
|
||||
class="hover:text-blue-600 dark:hover:text-blue-400 transition-colors">
|
||||
DysonNetwork.Sphere
|
||||
</a>
|
||||
<div class="mt-8 text-center text-sm">
|
||||
<div class="font-semibold mb-1">Solar Network</div>
|
||||
<div class="text-base-content/70">
|
||||
<a href="https://solsynth.dev" class="link link-hover">
|
||||
Solsynth LLC
|
||||
</a>
|
||||
© @DateTime.Now.Year
|
||||
<br/>
|
||||
Powered by
|
||||
<a href="https://github.com/Solsynth/DysonNetwork" class="link link-hover">
|
||||
DysonNetwork.Sphere
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -6,7 +6,8 @@
|
||||
"css:build": "npx @tailwindcss/cli -i ./wwwroot/css/site.css -o ./wwwroot/css/styles.css"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@tailwindcss/cli": "^4.1.7",
|
||||
"@tailwindcss/postcss": "^4.1.7",
|
||||
"@tailwindcss/cli": "^4.1.7"
|
||||
"daisyui": "^5.0.46"
|
||||
}
|
||||
}
|
@ -1,10 +1,88 @@
|
||||
@import "tailwindcss";
|
||||
|
||||
@plugin "daisyui";
|
||||
|
||||
@layer theme, base, components, utilities;
|
||||
|
||||
@import "tailwindcss/theme.css" layer(theme);
|
||||
@import "tailwindcss/preflight.css" layer(base);
|
||||
@import "tailwindcss/utilities.css" layer(utilities);
|
||||
|
||||
@theme {
|
||||
--font-sans: "Nunito", sans-serif;
|
||||
--font-mono: "Noto Sans Mono", monospace;
|
||||
}
|
||||
|
||||
@plugin "daisyui/theme" {
|
||||
name: "light";
|
||||
default: true;
|
||||
prefersdark: false;
|
||||
color-scheme: "light";
|
||||
--color-base-100: oklch(100% 0 0);
|
||||
--color-base-200: oklch(98% 0 0);
|
||||
--color-base-300: oklch(95% 0 0);
|
||||
--color-base-content: oklch(21% 0.006 285.885);
|
||||
--color-primary: oklch(62% 0.0873 281deg);
|
||||
--color-primary-content: oklch(93% 0.034 272.788);
|
||||
--color-secondary: oklch(62% 0.214 259.815);
|
||||
--color-secondary-content: oklch(94% 0.028 342.258);
|
||||
--color-accent: oklch(77% 0.152 181.912);
|
||||
--color-accent-content: oklch(38% 0.063 188.416);
|
||||
--color-neutral: oklch(14% 0.005 285.823);
|
||||
--color-neutral-content: oklch(92% 0.004 286.32);
|
||||
--color-info: oklch(82% 0.111 230.318);
|
||||
--color-info-content: oklch(29% 0.066 243.157);
|
||||
--color-success: oklch(79% 0.209 151.711);
|
||||
--color-success-content: oklch(37% 0.077 168.94);
|
||||
--color-warning: oklch(82% 0.189 84.429);
|
||||
--color-warning-content: oklch(41% 0.112 45.904);
|
||||
--color-error: oklch(71% 0.194 13.428);
|
||||
--color-error-content: oklch(27% 0.105 12.094);
|
||||
--radius-selector: 0.5rem;
|
||||
--radius-field: 0.5rem;
|
||||
--radius-box: 1rem;
|
||||
--size-selector: 0.28125rem;
|
||||
--size-field: 0.28125rem;
|
||||
--border: 1px;
|
||||
--depth: 1;
|
||||
--noise: 1;
|
||||
}
|
||||
|
||||
@plugin "daisyui/theme" {
|
||||
name: "dark";
|
||||
default: false;
|
||||
prefersdark: true;
|
||||
color-scheme: "dark";
|
||||
--color-base-100: oklch(0% 0 0);
|
||||
--color-base-200: oklch(20% 0.016 285.938);
|
||||
--color-base-300: oklch(25% 0.013 285.805);
|
||||
--color-base-content: oklch(97.807% 0.029 256.847);
|
||||
--color-primary: oklch(50% 0.0873 281deg);
|
||||
--color-primary-content: oklch(96% 0.018 272.314);
|
||||
--color-secondary: oklch(62% 0.214 259.815);
|
||||
--color-secondary-content: oklch(94% 0.028 342.258);
|
||||
--color-accent: oklch(77% 0.152 181.912);
|
||||
--color-accent-content: oklch(38% 0.063 188.416);
|
||||
--color-neutral: oklch(21% 0.006 285.885);
|
||||
--color-neutral-content: oklch(92% 0.004 286.32);
|
||||
--color-info: oklch(82% 0.111 230.318);
|
||||
--color-info-content: oklch(29% 0.066 243.157);
|
||||
--color-success: oklch(79% 0.209 151.711);
|
||||
--color-success-content: oklch(37% 0.077 168.94);
|
||||
--color-warning: oklch(82% 0.189 84.429);
|
||||
--color-warning-content: oklch(41% 0.112 45.904);
|
||||
--color-error: oklch(64% 0.246 16.439);
|
||||
--color-error-content: oklch(27% 0.105 12.094);
|
||||
--radius-selector: 0.5rem;
|
||||
--radius-field: 0.5rem;
|
||||
--radius-box: 1rem;
|
||||
--size-selector: 0.28125rem;
|
||||
--size-field: 0.28125rem;
|
||||
--border: 1px;
|
||||
--depth: 1;
|
||||
--noise: 1;
|
||||
}
|
||||
|
||||
@layer base {
|
||||
html, body {
|
||||
padding: 0;
|
||||
@ -12,6 +90,10 @@
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.material-symbols-outlined {
|
||||
font-variation-settings: 'FILL' 1, 'wght' 700, 'GRAD' 0, 'opsz' 48;
|
||||
}
|
||||
|
||||
/* For Firefox. */
|
||||
* {
|
||||
scrollbar-width: none;
|
||||
@ -23,14 +105,6 @@
|
||||
}
|
||||
}
|
||||
|
||||
.btn-primary {
|
||||
@apply px-4 py-2 bg-blue-500 text-white rounded-lg hover:bg-blue-600 transition-colors dark:bg-blue-600 dark:hover:bg-blue-700;
|
||||
}
|
||||
|
||||
.btn-text {
|
||||
@apply text-sm font-semibold leading-6 text-gray-900 dark:text-gray-100 hover:text-gray-700 dark:hover:text-gray-300;
|
||||
}
|
||||
|
||||
.container-default {
|
||||
@apply max-w-7xl mx-auto px-4 sm:px-6 lg:px-8;
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@ -70,6 +70,7 @@
|
||||
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003APutObjectArgs_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003FLibrary_003FApplication_0020Support_003FJetBrains_003FRider2025_002E1_003Fresharper_002Dhost_003FSourcesCache_003F6efe388c7585d5dd5587416a55298550b030c2a107edf45f988791297c3ffa_003FPutObjectArgs_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
||||
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AQueryable_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003FLibrary_003FApplication_0020Support_003FJetBrains_003FRider2025_002E1_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F42d8f09d6a294d00a6f49efc989927492fe00_003F4e_003F26d1ee34_003FQueryable_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
||||
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AQueryable_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003FLibrary_003FApplication_0020Support_003FJetBrains_003FRider2025_002E1_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003Fcbafb95b4df34952928f87356db00c8f2fe00_003F9b_003F8ba036bb_003FQueryable_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
||||
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003ARazorPage_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003FLibrary_003FApplication_0020Support_003FJetBrains_003FRider2025_002E1_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F81d2924a2bbd4b0c864a1d23cbf5f0893d200_003F5f_003Fc110be1c_003FRazorPage_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
||||
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AResizeOptions_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003FLibrary_003FApplication_0020Support_003FJetBrains_003FRider2025_002E1_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003Fef3339e864a448e2b1ec6fa7bbf4c6661fee00_003F48_003F0209e410_003FResizeOptions_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
||||
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AResourceManagerStringLocalizerFactory_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003FLibrary_003FApplication_0020Support_003FJetBrains_003FRider2025_002E1_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003Fb62f365d06c44ad695ff75960cdf97a2a800_003Fe4_003Ff6ba93b7_003FResourceManagerStringLocalizerFactory_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
||||
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003ARSA_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003FLibrary_003FApplication_0020Support_003FJetBrains_003FRider2025_002E1_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003Fee4f989f6b8042b59b2654fdc188e287243600_003F8b_003F44e5f855_003FRSA_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
||||
|
Reference in New Issue
Block a user