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.
+
+
+
+
+ Send
+
+
+
+
+@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;