diff --git a/PancakesWeb/Components/Pages/Home.razor b/PancakesWeb/Components/Pages/Home.razor index e8bf596..123064a 100644 --- a/PancakesWeb/Components/Pages/Home.razor +++ b/PancakesWeb/Components/Pages/Home.razor @@ -1,12 +1,15 @@ @page "/" +@using System.ComponentModel.DataAnnotations +@using System.Text.Json @using PancakesWeb.Data +@using PancakesWeb.Schema Home

pancakes

I'm a cat enby (they/it) from Australia + title="they/them/their/theirs/themself or it/it/its/its/itself in English">they/it) from Australia that likes cats, Linux, and programming. You can find my links, projects, and other pages here.

Accounts

@@ -121,4 +124,41 @@ } -
\ No newline at end of file + +

Notify

+

Send me a push notification. This will be a silent notification on my phone with no popup, vibration, or sound.

+ + + + + + + + + +@code { + [Inject] private HttpClient Http { get; set; } = null!; + [Inject] private IConfiguration Config { get; set; } = null!; + + [SupplyParameterFromForm] private NtfyModel Ntfy { get; set; } = new NtfyModel(); + + private async Task SubmitNtfy() + { + var ntfy = new NtfyRequest + { + Topic = Config["Ntfy:Topic"]!, + Message = Ntfy.Message, + Title = "pancakes.gay", + Priority = 2, + Tags = ["black_cat"] + }; + + await Http.PostAsJsonAsync(Config["Ntfy:Url"], ntfy, JsonSerializerOptions.Web); + } + + public class NtfyModel + { + [StringLength(128)] + public string Message { get; set; } = ""; + } +} \ No newline at end of file diff --git a/PancakesWeb/Program.cs b/PancakesWeb/Program.cs index 3eff7fd..2f7d3fa 100644 --- a/PancakesWeb/Program.cs +++ b/PancakesWeb/Program.cs @@ -5,6 +5,14 @@ var builder = WebApplication.CreateBuilder(args); // Add services to the container. builder.Services.AddRazorComponents() .AddInteractiveServerComponents(); +builder.Services.AddHttpClient(); + +builder.Configuration.AddEnvironmentVariables(); + +if (builder.Configuration["Ntfy:Url"] == null) + throw new Exception("Ntfy:Url is unset"); +if (builder.Configuration["Ntfy:Topic"] == null) + throw new Exception("Ntfy:Topic is unset"); var app = builder.Build(); diff --git a/PancakesWeb/Schema/NtfyRequest.cs b/PancakesWeb/Schema/NtfyRequest.cs new file mode 100644 index 0000000..3503fd0 --- /dev/null +++ b/PancakesWeb/Schema/NtfyRequest.cs @@ -0,0 +1,88 @@ +using System.Text.Json.Serialization; + +namespace PancakesWeb.Schema; + +public class NtfyRequest +{ + public required string Topic { get; set; } + + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public string? Message { get; set; } + + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public string? Title { get; set; } + + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public List? Tags { get; set; } + + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public int? Priority { get; set; } + + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public List? Actions { get; set; } + + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public string? Click { get; set; } + + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public string? Attach { get; set; } + + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public bool? Markdown { get; set; } + + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public string? Icon { get; set; } + + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public string? Filename { get; set; } + + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public string? Delay { get; set; } + + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public string? Email { get; set; } + + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public string? Call { get; set; } +} + +[JsonDerivedType(typeof(NtfyViewAction), "view")] +[JsonDerivedType(typeof(NtfyBroadcastAction), "broadcast")] +[JsonDerivedType(typeof(NtfyHttpAction), "http")] +[JsonPolymorphic(TypeDiscriminatorPropertyName = "action", + UnknownDerivedTypeHandling = JsonUnknownDerivedTypeHandling.FallBackToBaseType)] +public abstract class NtfyAction +{ + public required string Label { get; set; } + + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public bool? Clear { get; set; } +} + +public class NtfyViewAction : NtfyAction +{ + public required string Url { get; set; } +} + +public class NtfyBroadcastAction : NtfyAction +{ + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public string? Intent { get; set; } + + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public Dictionary? Extras { get; set; } +} + +public class NtfyHttpAction : NtfyAction +{ + public required string Url { get; set; } + + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public string? Method { get; set; } + + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public Dictionary? Headers { get; set; } + + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public string? Body { get; set; } +} \ No newline at end of file diff --git a/PancakesWeb/wwwroot/style.css b/PancakesWeb/wwwroot/style.css index d34fd5f..ce1d315 100644 --- a/PancakesWeb/wwwroot/style.css +++ b/PancakesWeb/wwwroot/style.css @@ -109,7 +109,7 @@ pre code { text-wrap: nowrap; } -button { +button, input[type=submit] { display: inline-block; padding: 0.5em 1em; @@ -121,12 +121,28 @@ button { border: none; border-radius: var(--radius); cursor: pointer; + transition: 0.2s background-color; } -button:hover, button:focus { +button:hover, button:focus, input[type=submit]:hover, input[type=submit]:focus { background-color: color-mix(in srgb, var(--accent) 80%, var(--background)); } +input, textarea { + padding: 0.5rem; + outline: none; + + background-color: var(--foreground); + color: var(--text); + border: 1px solid var(--border-color); + border-radius: var(--radius); + transition: 0.2s border; +} + +input, textarea:focus { + border-color: var(--accent); +} + .copy-code-button { position: absolute; top: 0; @@ -166,6 +182,10 @@ pre code:hover + .copy-code-button, .copy-code-button:hover { text-decoration: none; } +.validation-errors { + color: var(--error); +} + @keyframes title-fade-in { 0% { margin-top: 0;