diff --git a/.editorconfig b/.editorconfig index 461a672..3d8621d 100644 --- a/.editorconfig +++ b/.editorconfig @@ -3,9 +3,6 @@ root = true # All files [*] indent_style = space - -# Xml files -[*.xml] indent_size = 2 # C# files @@ -14,7 +11,6 @@ indent_size = 2 #### Core EditorConfig Options #### # Indentation and spacing -indent_size = 2 tab_width = 2 # New line preferences diff --git a/.vscode/settings.json b/.vscode/settings.json index e7ef11d..4f189e7 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,5 +1,6 @@ { "cSpell.words": [ + "onclick", "prerender", "rendermode" ] diff --git a/src/AltGen.Web.Client/Components/Layout/Header.razor b/src/AltGen.Web.Client/Components/Layout/Header.razor new file mode 100644 index 0000000..712158e --- /dev/null +++ b/src/AltGen.Web.Client/Components/Layout/Header.razor @@ -0,0 +1,126 @@ +@rendermode @(new InteractiveWebAssemblyRenderMode(prerender: false)) +@inject IJSRuntime JsRuntime +@implements IAsyncDisposable + +@* TODO: Create providers context. + - Load providers and present in table + - Allow form to add new provider + - Handle changing default provider + *@ + +
+ +
+ + +
+ +
+ + + + + + + + + + @for (int i = 0; i < 5; i++) + { + + + + + + } + +
ProviderProvider KeyDefault
Provider @(i + 1)Key @(i + 1)
+
+
+
+
+ + +
+
+ + +
+
+ + +
+ +
+
+
+
+ +@code { + private IJSObjectReference? _jsModule; + private ElementReference dialogElement; + + protected override async Task OnAfterRenderAsync(bool firstRender) + { + if (firstRender) + { + _jsModule = await JsRuntime.InvokeAsync(JsFunctions.Import, ComponentAssets.JsModule); + } + } + + private async Task HandleConfigButtonClick() + { + if (_jsModule is null) + { + return; + } + + await _jsModule.InvokeVoidAsync(JsFunctions.ShowDialog, dialogElement); + } + + private async Task HandleCloseButtonClick() + { + if (_jsModule is null) + { + return; + } + + await _jsModule.InvokeVoidAsync(JsFunctions.CloseDialog, dialogElement); + } + + async ValueTask IAsyncDisposable.DisposeAsync() + { + if (_jsModule is not null) + { + try + { + await _jsModule.DisposeAsync(); + } + catch (JSDisconnectedException) + { + } + } + } + + static class ComponentAssets + { + public const string JsModule = "./Components/Layout/Header.razor.js"; + } + + static class JsFunctions + { + public const string Import = "import"; + public const string ShowDialog = "showDialog"; + public const string CloseDialog = "closeDialog"; + } +} \ No newline at end of file diff --git a/src/AltGen.Web.Client/Components/Layout/Header.razor.css b/src/AltGen.Web.Client/Components/Layout/Header.razor.css new file mode 100644 index 0000000..9c1834d --- /dev/null +++ b/src/AltGen.Web.Client/Components/Layout/Header.razor.css @@ -0,0 +1,59 @@ +.config-button, +.close-button{ + display: flex; + align-items: center; + justify-content: center; + padding: 0.25rem; + border-radius: 0.25rem; +} + +.config-button svg, +.close-button svg { + height: 1rem; + width: 1rem; +} + +.providers-container { + display: flex; + flex-direction: column; + gap: 1.25rem; + padding: 1.25rem; + position: relative; +} + +.close-button { + position: absolute; + top: 0; + right: 0; + background-color: transparent; + border: none; + cursor: pointer; +} + +.form-container { + display: flex; + flex-direction: column; +} + +.form-container form { + display: flex; + flex-direction: column; + gap: 0.5rem; +} + +.form-group { + display: flex; + flex-direction: column; + gap: 0.25rem; +} + +.form-group.row { + flex-direction: row; + align-items: center; + gap: 0.5rem; +} + +.form-group label { + font-size: 0.875rem; + font-weight: bold; +} \ No newline at end of file diff --git a/src/AltGen.Web.Client/Components/Layout/Header.razor.js b/src/AltGen.Web.Client/Components/Layout/Header.razor.js new file mode 100644 index 0000000..7f111f1 --- /dev/null +++ b/src/AltGen.Web.Client/Components/Layout/Header.razor.js @@ -0,0 +1,17 @@ +/** + * @summary Shows a dialog element by calling the `showModal` method on it. + * @param {HTMLDialogElement} dialog - The dialog element to show + * @returns {void} + */ +export function showDialog(dialog) { + dialog.showModal(); +} + +/** + * @summary Closes a dialog element by calling the `close` method on it. + * @param {HTMLDialogElement} dialog - The dialog element to close + * @returns {void} + */ +export function closeDialog(dialog) { + dialog.close(); +} \ No newline at end of file diff --git a/src/AltGen.Web.Client/Components/Pages/Home.razor b/src/AltGen.Web.Client/Components/Pages/Home.razor index 27cda34..9cd7b02 100644 --- a/src/AltGen.Web.Client/Components/Pages/Home.razor +++ b/src/AltGen.Web.Client/Components/Pages/Home.razor @@ -4,6 +4,10 @@ @page "/" @rendermode @(new InteractiveWebAssemblyRenderMode(prerender: false)) +@* TODO: Present configured providers a dropdown. + If there is a default provider, use it. + *@ + AltGen.Web

AI Generated Alt Text

diff --git a/src/AltGen.Web/Components/App.razor b/src/AltGen.Web/Components/App.razor index 30088b9..89706a7 100644 --- a/src/AltGen.Web/Components/App.razor +++ b/src/AltGen.Web/Components/App.razor @@ -2,18 +2,18 @@ - - - - - - - + + + + + + + - - + + diff --git a/src/AltGen.Web/Components/Layout/MainLayout.razor b/src/AltGen.Web/Components/Layout/MainLayout.razor index 96fbbe6..b272580 100644 --- a/src/AltGen.Web/Components/Layout/MainLayout.razor +++ b/src/AltGen.Web/Components/Layout/MainLayout.razor @@ -1,9 +1,14 @@ @inherits LayoutComponentBase +@using AltGen.Web.Client.Components.Layout -@Body +
+ +
+ @Body +
- An unhandled error has occurred. - Reload - 🗙 -
+ An unhandled error has occurred. + Reload + 🗙 + \ No newline at end of file diff --git a/src/AltGen.Web/Components/Layout/MainLayout.razor.css b/src/AltGen.Web/Components/Layout/MainLayout.razor.css index 60cec92..4a150e5 100644 --- a/src/AltGen.Web/Components/Layout/MainLayout.razor.css +++ b/src/AltGen.Web/Components/Layout/MainLayout.razor.css @@ -1,20 +1,20 @@ #blazor-error-ui { - color-scheme: light only; - background: lightyellow; - bottom: 0; - box-shadow: 0 -1px 2px rgba(0, 0, 0, 0.2); - box-sizing: border-box; - display: none; - left: 0; - padding: 0.6rem 1.25rem 0.7rem 1.25rem; - position: fixed; - width: 100%; - z-index: 1000; + color-scheme: light only; + background: lightyellow; + bottom: 0; + box-shadow: 0 -1px 2px rgba(0, 0, 0, 0.2); + box-sizing: border-box; + display: none; + left: 0; + padding: 0.6rem 1.25rem 0.7rem 1.25rem; + position: fixed; + width: 100%; + z-index: 1000; } - #blazor-error-ui .dismiss { - cursor: pointer; - position: absolute; - right: 0.75rem; - top: 0.5rem; - } +#blazor-error-ui .dismiss { + cursor: pointer; + position: absolute; + right: 0.75rem; + top: 0.5rem; +} \ No newline at end of file diff --git a/src/AltGen.Web/Components/Pages/Error.razor b/src/AltGen.Web/Components/Pages/Error.razor index 576cc2d..94d1e4f 100644 --- a/src/AltGen.Web/Components/Pages/Error.razor +++ b/src/AltGen.Web/Components/Pages/Error.razor @@ -8,29 +8,31 @@ @if (ShowRequestId) { -

- Request ID: @RequestId -

+

+ Request ID: @RequestId +

}

Development Mode

- Swapping to Development environment will display more detailed information about the error that occurred. + Swapping to Development environment will display more detailed information about the error that + occurred.

- The Development environment shouldn't be enabled for deployed applications. - It can result in displaying sensitive information from exceptions to end users. - For local debugging, enable the Development environment by setting the ASPNETCORE_ENVIRONMENT environment variable to Development - and restarting the app. + The Development environment shouldn't be enabled for deployed applications. + It can result in displaying sensitive information from exceptions to end users. + For local debugging, enable the Development environment by setting the + ASPNETCORE_ENVIRONMENT environment variable to Development + and restarting the app.

-@code{ - [CascadingParameter] - private HttpContext? HttpContext { get; set; } +@code { + [CascadingParameter] + private HttpContext? HttpContext { get; set; } - private string? RequestId { get; set; } - private bool ShowRequestId => !string.IsNullOrEmpty(RequestId); + private string? RequestId { get; set; } + private bool ShowRequestId => !string.IsNullOrEmpty(RequestId); - protected override void OnInitialized() => - RequestId = Activity.Current?.Id ?? HttpContext?.TraceIdentifier; + protected override void OnInitialized() => + RequestId = Activity.Current?.Id ?? HttpContext?.TraceIdentifier; } diff --git a/src/AltGen.Web/Components/Routes.razor b/src/AltGen.Web/Components/Routes.razor index 84128a6..c4b588c 100644 --- a/src/AltGen.Web/Components/Routes.razor +++ b/src/AltGen.Web/Components/Routes.razor @@ -1,11 +1,11 @@  - - - - - - -

Sorry, there's nothing at this address.

-
-
+ + + + + + +

Sorry, there's nothing at this address.

+
+
diff --git a/src/AltGen.Web/wwwroot/app.css b/src/AltGen.Web/wwwroot/app.css index 5388357..47b064d 100644 --- a/src/AltGen.Web/wwwroot/app.css +++ b/src/AltGen.Web/wwwroot/app.css @@ -1,38 +1,44 @@ h1:focus { - outline: none; + outline: none; } .valid.modified:not([type=checkbox]) { - outline: 1px solid #26b050; + outline: 1px solid #26b050; } .invalid { - outline: 1px solid #e50000; + outline: 1px solid #e50000; } .validation-message { - color: #e50000; + color: #e50000; } .blazor-error-boundary { - background: url(data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iNTYiIGhlaWdodD0iNDkiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIG92ZXJmbG93PSJoaWRkZW4iPjxkZWZzPjxjbGlwUGF0aCBpZD0iY2xpcDAiPjxyZWN0IHg9IjIzNSIgeT0iNTEiIHdpZHRoPSI1NiIgaGVpZ2h0PSI0OSIvPjwvY2xpcFBhdGg+PC9kZWZzPjxnIGNsaXAtcGF0aD0idXJsKCNjbGlwMCkiIHRyYW5zZm9ybT0idHJhbnNsYXRlKC0yMzUgLTUxKSI+PHBhdGggZD0iTTI2My41MDYgNTFDMjY0LjcxNyA1MSAyNjUuODEzIDUxLjQ4MzcgMjY2LjYwNiA1Mi4yNjU4TDI2Ny4wNTIgNTIuNzk4NyAyNjcuNTM5IDUzLjYyODMgMjkwLjE4NSA5Mi4xODMxIDI5MC41NDUgOTIuNzk1IDI5MC42NTYgOTIuOTk2QzI5MC44NzcgOTMuNTEzIDI5MSA5NC4wODE1IDI5MSA5NC42NzgyIDI5MSA5Ny4wNjUxIDI4OS4wMzggOTkgMjg2LjYxNyA5OUwyNDAuMzgzIDk5QzIzNy45NjMgOTkgMjM2IDk3LjA2NTEgMjM2IDk0LjY3ODIgMjM2IDk0LjM3OTkgMjM2LjAzMSA5NC4wODg2IDIzNi4wODkgOTMuODA3MkwyMzYuMzM4IDkzLjAxNjIgMjM2Ljg1OCA5Mi4xMzE0IDI1OS40NzMgNTMuNjI5NCAyNTkuOTYxIDUyLjc5ODUgMjYwLjQwNyA1Mi4yNjU4QzI2MS4yIDUxLjQ4MzcgMjYyLjI5NiA1MSAyNjMuNTA2IDUxWk0yNjMuNTg2IDY2LjAxODNDMjYwLjczNyA2Ni4wMTgzIDI1OS4zMTMgNjcuMTI0NSAyNTkuMzEzIDY5LjMzNyAyNTkuMzEzIDY5LjYxMDIgMjU5LjMzMiA2OS44NjA4IDI1OS4zNzEgNzAuMDg4N0wyNjEuNzk1IDg0LjAxNjEgMjY1LjM4IDg0LjAxNjEgMjY3LjgyMSA2OS43NDc1QzI2Ny44NiA2OS43MzA5IDI2Ny44NzkgNjkuNTg3NyAyNjcuODc5IDY5LjMxNzkgMjY3Ljg3OSA2Ny4xMTgyIDI2Ni40NDggNjYuMDE4MyAyNjMuNTg2IDY2LjAxODNaTTI2My41NzYgODYuMDU0N0MyNjEuMDQ5IDg2LjA1NDcgMjU5Ljc4NiA4Ny4zMDA1IDI1OS43ODYgODkuNzkyMSAyNTkuNzg2IDkyLjI4MzcgMjYxLjA0OSA5My41Mjk1IDI2My41NzYgOTMuNTI5NSAyNjYuMTE2IDkzLjUyOTUgMjY3LjM4NyA5Mi4yODM3IDI2Ny4zODcgODkuNzkyMSAyNjcuMzg3IDg3LjMwMDUgMjY2LjExNiA4Ni4wNTQ3IDI2My41NzYgODYuMDU0N1oiIGZpbGw9IiNGRkU1MDAiIGZpbGwtcnVsZT0iZXZlbm9kZCIvPjwvZz48L3N2Zz4=) no-repeat 1rem/1.8rem, #b32121; - padding: 1rem 1rem 1rem 3.7rem; - color: white; + background: url(data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iNTYiIGhlaWdodD0iNDkiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIG92ZXJmbG93PSJoaWRkZW4iPjxkZWZzPjxjbGlwUGF0aCBpZD0iY2xpcDAiPjxyZWN0IHg9IjIzNSIgeT0iNTEiIHdpZHRoPSI1NiIgaGVpZ2h0PSI0OSIvPjwvY2xpcFBhdGg+PC9kZWZzPjxnIGNsaXAtcGF0aD0idXJsKCNjbGlwMCkiIHRyYW5zZm9ybT0idHJhbnNsYXRlKC0yMzUgLTUxKSI+PHBhdGggZD0iTTI2My41MDYgNTFDMjY0LjcxNyA1MSAyNjUuODEzIDUxLjQ4MzcgMjY2LjYwNiA1Mi4yNjU4TDI2Ny4wNTIgNTIuNzk4NyAyNjcuNTM5IDUzLjYyODMgMjkwLjE4NSA5Mi4xODMxIDI5MC41NDUgOTIuNzk1IDI5MC42NTYgOTIuOTk2QzI5MC44NzcgOTMuNTEzIDI5MSA5NC4wODE1IDI5MSA5NC42NzgyIDI5MSA5Ny4wNjUxIDI4OS4wMzggOTkgMjg2LjYxNyA5OUwyNDAuMzgzIDk5QzIzNy45NjMgOTkgMjM2IDk3LjA2NTEgMjM2IDk0LjY3ODIgMjM2IDk0LjM3OTkgMjM2LjAzMSA5NC4wODg2IDIzNi4wODkgOTMuODA3MkwyMzYuMzM4IDkzLjAxNjIgMjM2Ljg1OCA5Mi4xMzE0IDI1OS40NzMgNTMuNjI5NCAyNTkuOTYxIDUyLjc5ODUgMjYwLjQwNyA1Mi4yNjU4QzI2MS4yIDUxLjQ4MzcgMjYyLjI5NiA1MSAyNjMuNTA2IDUxWk0yNjMuNTg2IDY2LjAxODNDMjYwLjczNyA2Ni4wMTgzIDI1OS4zMTMgNjcuMTI0NSAyNTkuMzEzIDY5LjMzNyAyNTkuMzEzIDY5LjYxMDIgMjU5LjMzMiA2OS44NjA4IDI1OS4zNzEgNzAuMDg4N0wyNjEuNzk1IDg0LjAxNjEgMjY1LjM4IDg0LjAxNjEgMjY3LjgyMSA2OS43NDc1QzI2Ny44NiA2OS43MzA5IDI2Ny44NzkgNjkuNTg3NyAyNjcuODc5IDY5LjMxNzkgMjY3Ljg3OSA2Ny4xMTgyIDI2Ni40NDggNjYuMDE4MyAyNjMuNTg2IDY2LjAxODNaTTI2My41NzYgODYuMDU0N0MyNjEuMDQ5IDg2LjA1NDcgMjU5Ljc4NiA4Ny4zMDA1IDI1OS43ODYgODkuNzkyMSAyNTkuNzg2IDkyLjI4MzcgMjYxLjA0OSA5My41Mjk1IDI2My41NzYgOTMuNTI5NSAyNjYuMTE2IDkzLjUyOTUgMjY3LjM4NyA5Mi4yODM3IDI2Ny4zODcgODkuNzkyMSAyNjcuMzg3IDg3LjMwMDUgMjY2LjExNiA4Ni4wNTQ3IDI2My41NzYgODYuMDU0N1oiIGZpbGw9IiNGRkU1MDAiIGZpbGwtcnVsZT0iZXZlbm9kZCIvPjwvZz48L3N2Zz4=) no-repeat 1rem/1.8rem, #b32121; + padding: 1rem 1rem 1rem 3.7rem; + color: white; } - .blazor-error-boundary::after { - content: "An error has occurred." - } +.blazor-error-boundary::after { + content: "An error has occurred." +} .darker-border-checkbox.form-check-input { - border-color: #929292; + border-color: #929292; } -.form-floating > .form-control-plaintext::placeholder, .form-floating > .form-control::placeholder { - color: var(--bs-secondary-color); - text-align: end; +.form-floating>.form-control-plaintext::placeholder, +.form-floating>.form-control::placeholder { + color: var(--bs-secondary-color); + text-align: end; } -.form-floating > .form-control-plaintext:focus::placeholder, .form-floating > .form-control:focus::placeholder { - text-align: start; +.form-floating>.form-control-plaintext:focus::placeholder, +.form-floating>.form-control:focus::placeholder { + text-align: start; +} + +dialog { + padding: 0; } \ No newline at end of file