summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--HyperBooru.cs3
-rw-r--r--Migrations/20230809044429_Initial.Designer.cs206
-rw-r--r--Migrations/20230809044429_Initial.cs118
-rw-r--r--Migrations/HyperBooruDbContextModelSnapshot.cs203
-rw-r--r--Pages/Shared/_Layout.cshtml2
-rw-r--r--Pages/TagDefinitions.cshtml104
-rw-r--r--Pages/TagDefinitions.cshtml.cs16
-rw-r--r--Pages/TagDefinitions.cshtml.css16
-rw-r--r--Pages/ViewMedia.cshtml21
-rw-r--r--Server.csproj12
-rw-r--r--TagController.cs2
-rw-r--r--wwwroot/styles/global.css76
12 files changed, 750 insertions, 29 deletions
diff --git a/HyperBooru.cs b/HyperBooru.cs
index 9ccd323..e0e1b2d 100644
--- a/HyperBooru.cs
+++ b/HyperBooru.cs
@@ -1,3 +1,4 @@
+using Microsoft.EntityFrameworkCore;
using System.Text.Json.Serialization;
namespace HyperBooru;
@@ -20,7 +21,7 @@ public class HyperBooru {
using var scope = app.Services.CreateScope();
using var db = scope.ServiceProvider.GetRequiredService<HyperBooruDbContext>();
- db.Database.EnsureCreated();
+ db.Database.Migrate();
#if DEBUG
app.UseSwagger();
diff --git a/Migrations/20230809044429_Initial.Designer.cs b/Migrations/20230809044429_Initial.Designer.cs
new file mode 100644
index 0000000..78a0ca3
--- /dev/null
+++ b/Migrations/20230809044429_Initial.Designer.cs
@@ -0,0 +1,206 @@
+// <auto-generated />
+using System;
+using HyperBooru;
+using Microsoft.EntityFrameworkCore;
+using Microsoft.EntityFrameworkCore.Infrastructure;
+using Microsoft.EntityFrameworkCore.Migrations;
+using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
+
+#nullable disable
+
+namespace HyperBooru.Migrations
+{
+ [DbContext(typeof(HyperBooruDbContext))]
+ [Migration("20230809044429_Initial")]
+ partial class Initial
+ {
+ /// <inheritdoc />
+ protected override void BuildTargetModel(ModelBuilder modelBuilder)
+ {
+#pragma warning disable 612, 618
+ modelBuilder
+ .HasAnnotation("ProductVersion", "7.0.10")
+ .HasAnnotation("Proxies:ChangeTracking", false)
+ .HasAnnotation("Proxies:CheckEquality", false)
+ .HasAnnotation("Proxies:LazyLoading", true);
+
+ modelBuilder.Entity("HyperBooru.DbObject", b =>
+ {
+ b.Property<int>("ObjectId")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("INTEGER");
+
+ b.Property<string>("Discriminator")
+ .IsRequired()
+ .HasColumnType("TEXT");
+
+ b.Property<Guid>("Guid")
+ .HasColumnType("TEXT");
+
+ b.Property<int>("ObjectType")
+ .HasColumnType("INTEGER");
+
+ b.HasKey("ObjectId");
+
+ b.HasIndex("Guid");
+
+ b.ToTable("Objects");
+
+ b.HasDiscriminator<string>("Discriminator").HasValue("DbObject");
+
+ b.UseTphMappingStrategy();
+ });
+
+ modelBuilder.Entity("HyperBooru.DbUploadedFile", b =>
+ {
+ b.Property<int>("UploadedFileId")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("INTEGER");
+
+ b.Property<DateTime?>("CreateTime")
+ .HasColumnType("TEXT");
+
+ b.Property<string>("Filename")
+ .HasColumnType("TEXT");
+
+ b.Property<DateTime?>("LastAccessTime")
+ .HasColumnType("TEXT");
+
+ b.Property<DateTime?>("LastWriteTime")
+ .HasColumnType("TEXT");
+
+ b.Property<int>("MediaObjectId")
+ .HasColumnType("INTEGER");
+
+ b.Property<string>("OriginalChecksum")
+ .IsRequired()
+ .HasColumnType("TEXT");
+
+ b.Property<DateTime>("UploadTime")
+ .HasColumnType("TEXT");
+
+ b.HasKey("UploadedFileId");
+
+ b.HasIndex("MediaObjectId");
+
+ b.ToTable("UploadedFiles");
+ });
+
+ modelBuilder.Entity("HyperBooru.DbMedia", b =>
+ {
+ b.HasBaseType("HyperBooru.DbObject");
+
+ b.Property<string>("Checksum")
+ .IsRequired()
+ .HasColumnType("TEXT");
+
+ b.Property<string>("LongDescription")
+ .HasColumnType("TEXT");
+
+ b.Property<string>("MimeType")
+ .IsRequired()
+ .HasColumnType("TEXT");
+
+ b.Property<string>("ShortDescription")
+ .HasColumnType("TEXT");
+
+ b.HasDiscriminator().HasValue("DbMedia");
+ });
+
+ modelBuilder.Entity("HyperBooru.DbTag", b =>
+ {
+ b.HasBaseType("HyperBooru.DbObject");
+
+ b.Property<DateTime>("CreateTime")
+ .HasColumnType("TEXT");
+
+ b.Property<int>("TagDefinitionObjectId")
+ .HasColumnType("INTEGER");
+
+ b.Property<int>("TargetObjectId")
+ .HasColumnType("INTEGER");
+
+ b.HasIndex("TagDefinitionObjectId");
+
+ b.HasIndex("TargetObjectId");
+
+ b.HasDiscriminator().HasValue("DbTag");
+ });
+
+ modelBuilder.Entity("HyperBooru.DbTagDefinition", b =>
+ {
+ b.HasBaseType("HyperBooru.DbObject");
+
+ b.Property<int?>("DbTagDefinitionObjectId")
+ .HasColumnType("INTEGER");
+
+ b.Property<string>("Name")
+ .IsRequired()
+ .HasColumnType("TEXT");
+
+ b.Property<string>("Namespace")
+ .HasColumnType("TEXT");
+
+ b.Property<int>("Source")
+ .HasColumnType("INTEGER");
+
+ b.HasIndex("DbTagDefinitionObjectId");
+
+ b.HasDiscriminator().HasValue("DbTagDefinition");
+ });
+
+ modelBuilder.Entity("HyperBooru.DbUploadedFile", b =>
+ {
+ b.HasOne("HyperBooru.DbMedia", "Media")
+ .WithMany("UploadedFiles")
+ .HasForeignKey("MediaObjectId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+
+ b.Navigation("Media");
+ });
+
+ modelBuilder.Entity("HyperBooru.DbTag", b =>
+ {
+ b.HasOne("HyperBooru.DbTagDefinition", "TagDefinition")
+ .WithMany()
+ .HasForeignKey("TagDefinitionObjectId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+
+ b.HasOne("HyperBooru.DbObject", "Target")
+ .WithMany("Tags")
+ .HasForeignKey("TargetObjectId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+
+ b.Navigation("TagDefinition");
+
+ b.Navigation("Target");
+ });
+
+ modelBuilder.Entity("HyperBooru.DbTagDefinition", b =>
+ {
+ b.HasOne("HyperBooru.DbTagDefinition", null)
+ .WithMany("ImplicitTags")
+ .HasForeignKey("DbTagDefinitionObjectId");
+ });
+
+ modelBuilder.Entity("HyperBooru.DbObject", b =>
+ {
+ b.Navigation("Tags");
+ });
+
+ modelBuilder.Entity("HyperBooru.DbMedia", b =>
+ {
+ b.Navigation("UploadedFiles");
+ });
+
+ modelBuilder.Entity("HyperBooru.DbTagDefinition", b =>
+ {
+ b.Navigation("ImplicitTags");
+ });
+#pragma warning restore 612, 618
+ }
+ }
+}
diff --git a/Migrations/20230809044429_Initial.cs b/Migrations/20230809044429_Initial.cs
new file mode 100644
index 0000000..0126c13
--- /dev/null
+++ b/Migrations/20230809044429_Initial.cs
@@ -0,0 +1,118 @@
+using System;
+using Microsoft.EntityFrameworkCore.Migrations;
+
+#nullable disable
+
+namespace HyperBooru.Migrations
+{
+ /// <inheritdoc />
+ public partial class Initial : Migration
+ {
+ /// <inheritdoc />
+ protected override void Up(MigrationBuilder migrationBuilder)
+ {
+ migrationBuilder.CreateTable(
+ name: "Objects",
+ columns: table => new
+ {
+ ObjectId = table.Column<int>(type: "INTEGER", nullable: false)
+ .Annotation("Sqlite:Autoincrement", true),
+ Guid = table.Column<Guid>(type: "TEXT", nullable: false),
+ ObjectType = table.Column<int>(type: "INTEGER", nullable: false),
+ Discriminator = table.Column<string>(type: "TEXT", nullable: false),
+ Checksum = table.Column<string>(type: "TEXT", nullable: true),
+ MimeType = table.Column<string>(type: "TEXT", nullable: true),
+ ShortDescription = table.Column<string>(type: "TEXT", nullable: true),
+ LongDescription = table.Column<string>(type: "TEXT", nullable: true),
+ TagDefinitionObjectId = table.Column<int>(type: "INTEGER", nullable: true),
+ CreateTime = table.Column<DateTime>(type: "TEXT", nullable: true),
+ TargetObjectId = table.Column<int>(type: "INTEGER", nullable: true),
+ Source = table.Column<int>(type: "INTEGER", nullable: true),
+ Namespace = table.Column<string>(type: "TEXT", nullable: true),
+ Name = table.Column<string>(type: "TEXT", nullable: true),
+ DbTagDefinitionObjectId = table.Column<int>(type: "INTEGER", nullable: true)
+ },
+ constraints: table =>
+ {
+ table.PrimaryKey("PK_Objects", x => x.ObjectId);
+ table.ForeignKey(
+ name: "FK_Objects_Objects_DbTagDefinitionObjectId",
+ column: x => x.DbTagDefinitionObjectId,
+ principalTable: "Objects",
+ principalColumn: "ObjectId");
+ table.ForeignKey(
+ name: "FK_Objects_Objects_TagDefinitionObjectId",
+ column: x => x.TagDefinitionObjectId,
+ principalTable: "Objects",
+ principalColumn: "ObjectId",
+ onDelete: ReferentialAction.Cascade);
+ table.ForeignKey(
+ name: "FK_Objects_Objects_TargetObjectId",
+ column: x => x.TargetObjectId,
+ principalTable: "Objects",
+ principalColumn: "ObjectId",
+ onDelete: ReferentialAction.Cascade);
+ });
+
+ migrationBuilder.CreateTable(
+ name: "UploadedFiles",
+ columns: table => new
+ {
+ UploadedFileId = table.Column<int>(type: "INTEGER", nullable: false)
+ .Annotation("Sqlite:Autoincrement", true),
+ OriginalChecksum = table.Column<string>(type: "TEXT", nullable: false),
+ Filename = table.Column<string>(type: "TEXT", nullable: true),
+ UploadTime = table.Column<DateTime>(type: "TEXT", nullable: false),
+ LastAccessTime = table.Column<DateTime>(type: "TEXT", nullable: true),
+ LastWriteTime = table.Column<DateTime>(type: "TEXT", nullable: true),
+ CreateTime = table.Column<DateTime>(type: "TEXT", nullable: true),
+ MediaObjectId = table.Column<int>(type: "INTEGER", nullable: false)
+ },
+ constraints: table =>
+ {
+ table.PrimaryKey("PK_UploadedFiles", x => x.UploadedFileId);
+ table.ForeignKey(
+ name: "FK_UploadedFiles_Objects_MediaObjectId",
+ column: x => x.MediaObjectId,
+ principalTable: "Objects",
+ principalColumn: "ObjectId",
+ onDelete: ReferentialAction.Cascade);
+ });
+
+ migrationBuilder.CreateIndex(
+ name: "IX_Objects_DbTagDefinitionObjectId",
+ table: "Objects",
+ column: "DbTagDefinitionObjectId");
+
+ migrationBuilder.CreateIndex(
+ name: "IX_Objects_Guid",
+ table: "Objects",
+ column: "Guid");
+
+ migrationBuilder.CreateIndex(
+ name: "IX_Objects_TagDefinitionObjectId",
+ table: "Objects",
+ column: "TagDefinitionObjectId");
+
+ migrationBuilder.CreateIndex(
+ name: "IX_Objects_TargetObjectId",
+ table: "Objects",
+ column: "TargetObjectId");
+
+ migrationBuilder.CreateIndex(
+ name: "IX_UploadedFiles_MediaObjectId",
+ table: "UploadedFiles",
+ column: "MediaObjectId");
+ }
+
+ /// <inheritdoc />
+ protected override void Down(MigrationBuilder migrationBuilder)
+ {
+ migrationBuilder.DropTable(
+ name: "UploadedFiles");
+
+ migrationBuilder.DropTable(
+ name: "Objects");
+ }
+ }
+}
diff --git a/Migrations/HyperBooruDbContextModelSnapshot.cs b/Migrations/HyperBooruDbContextModelSnapshot.cs
new file mode 100644
index 0000000..566b66c
--- /dev/null
+++ b/Migrations/HyperBooruDbContextModelSnapshot.cs
@@ -0,0 +1,203 @@
+// <auto-generated />
+using System;
+using HyperBooru;
+using Microsoft.EntityFrameworkCore;
+using Microsoft.EntityFrameworkCore.Infrastructure;
+using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
+
+#nullable disable
+
+namespace HyperBooru.Migrations
+{
+ [DbContext(typeof(HyperBooruDbContext))]
+ partial class HyperBooruDbContextModelSnapshot : ModelSnapshot
+ {
+ protected override void BuildModel(ModelBuilder modelBuilder)
+ {
+#pragma warning disable 612, 618
+ modelBuilder
+ .HasAnnotation("ProductVersion", "7.0.10")
+ .HasAnnotation("Proxies:ChangeTracking", false)
+ .HasAnnotation("Proxies:CheckEquality", false)
+ .HasAnnotation("Proxies:LazyLoading", true);
+
+ modelBuilder.Entity("HyperBooru.DbObject", b =>
+ {
+ b.Property<int>("ObjectId")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("INTEGER");
+
+ b.Property<string>("Discriminator")
+ .IsRequired()
+ .HasColumnType("TEXT");
+
+ b.Property<Guid>("Guid")
+ .HasColumnType("TEXT");
+
+ b.Property<int>("ObjectType")
+ .HasColumnType("INTEGER");
+
+ b.HasKey("ObjectId");
+
+ b.HasIndex("Guid");
+
+ b.ToTable("Objects");
+
+ b.HasDiscriminator<string>("Discriminator").HasValue("DbObject");
+
+ b.UseTphMappingStrategy();
+ });
+
+ modelBuilder.Entity("HyperBooru.DbUploadedFile", b =>
+ {
+ b.Property<int>("UploadedFileId")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("INTEGER");
+
+ b.Property<DateTime?>("CreateTime")
+ .HasColumnType("TEXT");
+
+ b.Property<string>("Filename")
+ .HasColumnType("TEXT");
+
+ b.Property<DateTime?>("LastAccessTime")
+ .HasColumnType("TEXT");
+
+ b.Property<DateTime?>("LastWriteTime")
+ .HasColumnType("TEXT");
+
+ b.Property<int>("MediaObjectId")
+ .HasColumnType("INTEGER");
+
+ b.Property<string>("OriginalChecksum")
+ .IsRequired()
+ .HasColumnType("TEXT");
+
+ b.Property<DateTime>("UploadTime")
+ .HasColumnType("TEXT");
+
+ b.HasKey("UploadedFileId");
+
+ b.HasIndex("MediaObjectId");
+
+ b.ToTable("UploadedFiles");
+ });
+
+ modelBuilder.Entity("HyperBooru.DbMedia", b =>
+ {
+ b.HasBaseType("HyperBooru.DbObject");
+
+ b.Property<string>("Checksum")
+ .IsRequired()
+ .HasColumnType("TEXT");
+
+ b.Property<string>("LongDescription")
+ .HasColumnType("TEXT");
+
+ b.Property<string>("MimeType")
+ .IsRequired()
+ .HasColumnType("TEXT");
+
+ b.Property<string>("ShortDescription")
+ .HasColumnType("TEXT");
+
+ b.HasDiscriminator().HasValue("DbMedia");
+ });
+
+ modelBuilder.Entity("HyperBooru.DbTag", b =>
+ {
+ b.HasBaseType("HyperBooru.DbObject");
+
+ b.Property<DateTime>("CreateTime")
+ .HasColumnType("TEXT");
+
+ b.Property<int>("TagDefinitionObjectId")
+ .HasColumnType("INTEGER");
+
+ b.Property<int>("TargetObjectId")
+ .HasColumnType("INTEGER");
+
+ b.HasIndex("TagDefinitionObjectId");
+
+ b.HasIndex("TargetObjectId");
+
+ b.HasDiscriminator().HasValue("DbTag");
+ });
+
+ modelBuilder.Entity("HyperBooru.DbTagDefinition", b =>
+ {
+ b.HasBaseType("HyperBooru.DbObject");
+
+ b.Property<int?>("DbTagDefinitionObjectId")
+ .HasColumnType("INTEGER");
+
+ b.Property<string>("Name")
+ .IsRequired()
+ .HasColumnType("TEXT");
+
+ b.Property<string>("Namespace")
+ .HasColumnType("TEXT");
+
+ b.Property<int>("Source")
+ .HasColumnType("INTEGER");
+
+ b.HasIndex("DbTagDefinitionObjectId");
+
+ b.HasDiscriminator().HasValue("DbTagDefinition");
+ });
+
+ modelBuilder.Entity("HyperBooru.DbUploadedFile", b =>
+ {
+ b.HasOne("HyperBooru.DbMedia", "Media")
+ .WithMany("UploadedFiles")
+ .HasForeignKey("MediaObjectId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+
+ b.Navigation("Media");
+ });
+
+ modelBuilder.Entity("HyperBooru.DbTag", b =>
+ {
+ b.HasOne("HyperBooru.DbTagDefinition", "TagDefinition")
+ .WithMany()
+ .HasForeignKey("TagDefinitionObjectId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+
+ b.HasOne("HyperBooru.DbObject", "Target")
+ .WithMany("Tags")
+ .HasForeignKey("TargetObjectId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+
+ b.Navigation("TagDefinition");
+
+ b.Navigation("Target");
+ });
+
+ modelBuilder.Entity("HyperBooru.DbTagDefinition", b =>
+ {
+ b.HasOne("HyperBooru.DbTagDefinition", null)
+ .WithMany("ImplicitTags")
+ .HasForeignKey("DbTagDefinitionObjectId");
+ });
+
+ modelBuilder.Entity("HyperBooru.DbObject", b =>
+ {
+ b.Navigation("Tags");
+ });
+
+ modelBuilder.Entity("HyperBooru.DbMedia", b =>
+ {
+ b.Navigation("UploadedFiles");
+ });
+
+ modelBuilder.Entity("HyperBooru.DbTagDefinition", b =>
+ {
+ b.Navigation("ImplicitTags");
+ });
+#pragma warning restore 612, 618
+ }
+ }
+}
diff --git a/Pages/Shared/_Layout.cshtml b/Pages/Shared/_Layout.cshtml
index be445cc..9cdb952 100644
--- a/Pages/Shared/_Layout.cshtml
+++ b/Pages/Shared/_Layout.cshtml
@@ -16,7 +16,7 @@
<body>
<div id="navbar">
<a href="/">Home</a>
- <a href="/tags">Tags</a>
+ <a href="/TagDefinitions">Tags</a>
</div>
<div id="content" style="overflow:@(ViewBag.ContentScroll ? "auto" : "hidden");margin:@(ViewBag.ContentMargin ?? "0");">
@RenderBody()
diff --git a/Pages/TagDefinitions.cshtml b/Pages/TagDefinitions.cshtml
new file mode 100644
index 0000000..a05f5d5
--- /dev/null
+++ b/Pages/TagDefinitions.cshtml
@@ -0,0 +1,104 @@
+@page
+@model HyperBooru.Pages.TagDefinitionsModel
+@{
+ ViewBag.Title = "Tag Definitions";
+}
+
+<script type="text/javascript">
+ async function createDefinition(e) {
+ var form = new FormData();
+
+ form.append('name', e.querySelector('#name').value);
+ form.append('namespace', e.querySelector('#namespace').value);
+
+ var resp = await fetch('/api/tag/def', {
+ method: 'post',
+ body: form
+ });
+
+ if(!resp.ok) {
+ alert('Error creating tag definition!');
+ showCreateDialog(false);
+ } else {
+ window.location.reload();
+ }
+ }
+
+ async function deleteTagDefinition() {
+ var dialog = document.getElementById('delete-dialog');
+
+ var resp = await fetch(`/api/tag/def/${dialog.dataset.guid}`, {
+ method: 'delete'
+ });
+
+ if(!resp.ok) {
+ alert('Error deleting tag definition!');
+ showDeleteDialog(false);
+ } else {
+ window.location.reload()
+ }
+ }
+
+ function showCreateDialog(visible) {
+ document.getElementById('create-dialog').classList.toggle('visible', visible);
+ }
+
+ function showDeleteDialog(visible) {
+ var dialog = document.getElementById('delete-dialog');
+ if(visible == false) {
+ dialog.classList.toggle('visible', false);
+ } else {
+ dialog.classList.toggle('visible', true);
+ dialog.dataset.guid = visible;
+ }
+ }
+</script>
+
+<link rel="stylesheet" type="text/css" href="@(nameof(HyperBooru)).styles.css"/>
+
+<table id="tag-definitions" class="data-table">
+ <tr>
+ <th>Guid</th>
+ <th>Source</th>
+ <th>Namespace</th>
+ <th>Name</th>
+ <th></th>
+ </tr>
+ @foreach(var tagDef in Model.TagDefinitions) {
+ <tr>
+ <td>@tagDef.Guid</td>
+ <td>@tagDef.Source</td>
+ <td>@tagDef.Namespace</td>
+ <td>@tagDef.Name</td>
+ <td><button onclick="showDeleteDialog('@tagDef.Guid')">Delete</button></td>
+ </tr>
+ }
+</table>
+
+<div class="button-container">
+ <button onclick="showCreateDialog(true)">Create</button>
+</div>
+
+<div id="create-dialog" class="dialog">
+ <p>Create a new tag definition</p>
+ <hr/>
+ <form onsubmit="createDefinition(this)">
+ <label>Name</label>
+ <input id="name" type="text" required/>
+ <label>Namespace</label>
+ <input id="namespace" type="text"/>
+ <div class="button-container">
+ <button class="secondary" onclick="showCreateDialog(false)">Cancel</button>
+ <button type="submit">Create</button>
+ </div>
+ </form>
+</div>
+
+<div id="delete-dialog" class="dialog">
+ <p>Are you sure you want to delete this tag definition?</p>
+ <hr/>
+ <div class="button-container">
+ <button onclick="showDeleteDialog(false)" class="secondary">Cancel</button>
+ <button onclick="deleteTagDefinition()">Confirm</button>
+ </div>
+</div>
diff --git a/Pages/TagDefinitions.cshtml.cs b/Pages/TagDefinitions.cshtml.cs
new file mode 100644
index 0000000..e2253d6
--- /dev/null
+++ b/Pages/TagDefinitions.cshtml.cs
@@ -0,0 +1,16 @@
+using Microsoft.AspNetCore.Mvc;
+using Microsoft.AspNetCore.Mvc.RazorPages;
+
+namespace HyperBooru.Pages;
+
+public class TagDefinitionsModel : PageModel {
+ public IEnumerable<DbTagDefinition> TagDefinitions =>
+ db.TagDefinitions;
+
+ private HyperBooruDbContext db;
+
+ public TagDefinitionsModel(HyperBooruDbContext db) =>
+ this.db = db;
+
+ public void OnGet() {}
+}
diff --git a/Pages/TagDefinitions.cshtml.css b/Pages/TagDefinitions.cshtml.css
new file mode 100644
index 0000000..0a9e226
--- /dev/null
+++ b/Pages/TagDefinitions.cshtml.css
@@ -0,0 +1,16 @@
+form > input {
+ width: 100%;
+}
+
+div.button-container {
+ display: flex;
+ justify-content: flex-end;
+}
+
+table#tag-definitions td:first-child {
+ font-family: 'Lucida Console';
+}
+
+table#tag-definitions td > button {
+ margin-top: 0;
+} \ No newline at end of file
diff --git a/Pages/ViewMedia.cshtml b/Pages/ViewMedia.cshtml
index 0f433df..3d0ce4a 100644
--- a/Pages/ViewMedia.cshtml
+++ b/Pages/ViewMedia.cshtml
@@ -17,6 +17,10 @@
}
}
+ function showDeleteDialog(visible) {
+ document.getElementById('delete-dialog').classList.toggle('visible', visible);
+ }
+
function selectPane(tab) {
var tabs = Array.from(document.querySelectorAll('div#metadata-header > a'));
@@ -76,7 +80,7 @@
}
</table>
<div class="button-container">
- <button onclick="deleteMedia()">Delete</button>
+ <button onclick="showDeleteDialog(true)">Delete</button>
</div>
</div>
<div id="metadata-tags">
@@ -85,7 +89,18 @@
<th>Tag Name</th>
</tr>
</table>
- <button>Add Tag</button>
+ <div class="button-container">
+ <button>Add Tag</button>
+ </div>
</div>
</div>
-</div> \ No newline at end of file
+</div>
+
+<div id="delete-dialog" class="dialog">
+ <p>Delete this media?</p>
+ <hr/>
+ <div class="button-container">
+ <button class="secondary" onclick="showDeleteDialog(false)">Cancel</button>
+ <button onclick="deleteMedia()">Confirm</button>
+ </div>
+</div>
diff --git a/Server.csproj b/Server.csproj
index 12b3a92..3a582e2 100644
--- a/Server.csproj
+++ b/Server.csproj
@@ -9,10 +9,14 @@
</PropertyGroup>
<ItemGroup>
- <PackageReference Include="Magick.NET-Q16-AnyCPU" Version="13.1.3" />
- <PackageReference Include="Microsoft.EntityFrameworkCore" Version="7.0.7" />
- <PackageReference Include="Microsoft.EntityFrameworkCore.Proxies" Version="7.0.7" />
- <PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="7.0.7" />
+ <PackageReference Include="Magick.NET-Q16-AnyCPU" Version="13.2.0" />
+ <PackageReference Include="Microsoft.EntityFrameworkCore" Version="7.0.10" />
+ <PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="7.0.10">
+ <PrivateAssets>all</PrivateAssets>
+ <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
+ </PackageReference>
+ <PackageReference Include="Microsoft.EntityFrameworkCore.Proxies" Version="7.0.10" />
+ <PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="7.0.10" />
<PackageReference Include="Mime-Detective" Version="23.6.1" />
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.5.0" />
</ItemGroup>
diff --git a/TagController.cs b/TagController.cs
index b97b066..5c9fa39 100644
--- a/TagController.cs
+++ b/TagController.cs
@@ -3,7 +3,7 @@
namespace HyperBooru;
[ApiController]
-[Route("tag")]
+[Route("/api/tag")]
public class TagController : Controller {
private HyperBooruDbContext db;
diff --git a/wwwroot/styles/global.css b/wwwroot/styles/global.css
index caf773a..2b007f8 100644
--- a/wwwroot/styles/global.css
+++ b/wwwroot/styles/global.css
@@ -1,6 +1,10 @@
:root {
- --col-bg: #222;
- --col-navbar-bg: magenta;
+ --col-accent-pri: #0aa;
+ --col-bg: #222;
+ --col-dialog-bg: #333;
+ --col-navbar-bg: var(--col-accent-pri);
+ --col-button-pri: var(--col-accent-pri);
+ --col-button-sec: #555;
}
body {
@@ -15,30 +19,42 @@ a {
text-decoration: none;
}
-input {
+button, input[type=submit] {
color: white;
- box-sizing: border-box;
- border: 1px solid #aaa;
- background: rgba(0, 0, 0, 0.3);
- border-radius: 5px;
-}
-
-button {
- background: #f0f;
+ background: var(--col-button-pri);
border-radius: 10px;
border: none;
box-sizing: border-box;
height: 30px;
- margin-top: 10px;
- padding: 0 7px 0 7px;
+ margin: 10px 5px 0 5px;
+ padding: 0 9px 0 9px;
+}
+
+button.secondary {
+ background: var(--col-button-sec);
+}
+
+button:hover, input[type=submit]:hover {
+ filter: grayscale(0.9) brightness(2.5);
+}
+
+button:active, input[type=submit]:active {
+ filter: grayscale(0.9) brightness(3.5);
}
-button:hover {
- background: #f8f;
+input {
+ background: rgba(0, 0, 0, 0);
+ border-radius: 5px;
+ border: 1px solid #aaa;
+ box-sizing: border-box;
+ color: white;
+ height: 25px !important;
+ margin-bottom: 10px;
}
-button:active {
- background: #fff;
+/* necessary for use inside flex containers */
+hr {
+ width: 100%;
}
table.data-table {
@@ -55,10 +71,32 @@ table.data-table > tbody > tr > td {
padding: 4px;
}
-table.data-table > tbody > tr:nth-child(2n):not(:last-child) {
+table.data-table > tbody > tr:nth-child(2n) {
background: rgba(255, 255, 255, 0.2);
}
table.data-table > tbody > tr > td:not(:last-child) {
border-right: 1px solid white;
-} \ No newline at end of file
+}
+
+div.dialog {
+ background: var(--col-dialog-bg);
+ border-radius: 20px;
+ box-shadow: 0px 5px 10px 10px rgb(0 0 0 / 25%);
+ display: flex;
+ flex-direction: column;
+ left: 50%;
+ opacity: 0;
+ padding: 20px;
+ position: absolute;
+ top: 50%;
+ transform: translate(-50%, -50%);
+ transition: visibility 0.1s, opacity 0.1s linear;
+ visibility: hidden;
+ width: 450px;
+}
+
+div.dialog.visible {
+ opacity: 1;
+ visibility: visible;
+}