Compare commits

...
20 Commits
Author SHA1 Message Date
BuildTools 8ccbe8cf65 ModalComponent Show und Close-Funktionsnamen normiert 2024-06-26 20:37:49 +02:00
BuildTools 1e79620272 Angefangen, Gläser-Klasse zu implementieren 2024-06-26 20:37:17 +02:00
BuildTools 8435545bec Tests mit Prozentualer Umverteilung bei der Stärke 2024-03-03 18:16:37 +01:00
BuildTools b704dbc30e Stärkeauswahl eingebaut und erstellen vom CocktailCode hinzugefügt 2024-03-02 22:16:13 +01:00
BuildTools 2e10170636 ReadLine() eingebaut, da es so zuverlässiger funktioniert 2024-03-02 22:15:41 +01:00
BuildTools c2e6880d4e Notizen ergänzt 2024-03-02 22:15:20 +01:00
BuildTools d046723ff1 Symbol für nicht-alkoholische Cocktails eingebaut 2024-03-02 22:15:08 +01:00
BuildTools fc8ffecbd2 IsTappable() Funktion eingebaut um zu prüfen, ob ein Cocktail aktuell mit der Maschine gezapft werden kann 2024-03-02 22:14:50 +01:00
BuildTools 25d38ee63d SVG durch Bootstrap-Icons ersetzt 2024-03-02 22:13:56 +01:00
BuildTools c2fba2c743 Aktueller Datenstand 2024-03-02 22:12:09 +01:00
BuildTools 468824c786 ReadOnly-Propery IsAlcoholic ergänzt 2024-03-02 22:09:24 +01:00
BuildTools 2d71eac005 Bootstrap-Icons hinzugefügt 2024-03-02 22:08:48 +01:00
BuildTools af867d248d Warnings entfernt 2024-02-28 19:54:09 +01:00
BuildTools 2ad3da8b20 Pages auf Englisch umbenannt 2024-02-28 19:53:53 +01:00
BuildTools 67ae87b78d Aktueller Datenstand 2024-02-28 19:52:57 +01:00
BuildTools 7718d893cc Filler Angepasst - Pos gilt jetzt pro Typ 2024-02-28 19:52:39 +01:00
BuildTools 6a1dfb0e4f Ersteller und Counter zu Cocktail-Klasse hinzugefügt 2024-02-28 19:51:38 +01:00
BuildTools 5331a1c9d1 Passwortdialog für Einstellungen eingebaut 2024-02-28 19:50:42 +01:00
BuildTools 7ee75d0de3 Flaschen bearbeiten auf Extra Form gepackt 2024-02-28 19:49:59 +01:00
BuildTools ccb0404477 Code u. Page zusammengefasst 2024-02-28 19:48:20 +01:00
2099 changed files with 15170 additions and 332 deletions

No files matched your search

+1 -1
View File
@@ -3,7 +3,7 @@
"isRoot": true,
"tools": {
"dotnet-ef": {
"version": "8.0.0",
"version": "8.0.2",
"commands": [
"dotnet-ef"
]
+13 -1
View File
@@ -3,8 +3,20 @@
public class Cocktail
{
public int Id { get; set; }
public string Name { get; set; } = "";
public string Name { get; set; } = null!;
public string? Ersteller { get; set; }
public string? ImageURL { get; set; }
public int Counter { get; set; }
public bool IsAlcoholic { get
{
return Cocktailflaschen.Any(f => f.Flasche.Alkoholisch);
}
}
public List<CocktailFlasche> Cocktailflaschen { get; set; } = new();
}
}
+2 -2
View File
@@ -6,8 +6,8 @@
public int Id { get; set; }
public int CocktailID { get; set; }
public int FlascheID { get; set; }
public Flasche Flasche { get; set; }
public Cocktail Cocktail { get; set; }
public Flasche Flasche { get; set; } = null!;
public Cocktail Cocktail { get; set; } = null!;
public int Reihenfolge { get; set; }
public int Menge { get; set; }
+14 -13
View File
@@ -10,8 +10,7 @@ namespace CocktailWeb.Data
public DbSet<CocktailFlasche> CocktailFlaschen { get; set; }
public DbSet<Cocktail> Cocktails { get; set; }
public DbSet<Filler> Fillers { get; set; }
public DbSet<Glas> Glaeser { get; set; }
public DbSet<Glas> Glasses { get; set; }
public DbDataContext(IConfiguration configuration)
{
@@ -35,18 +34,20 @@ namespace CocktailWeb.Data
new Filler() { Id = 1, Pos = 1, Type = Filler.FillerType.Pump },
new Filler() { Id = 2, Pos = 2, Type = Filler.FillerType.Pump },
new Filler() { Id = 3, Pos = 3, Type = Filler.FillerType.Pump },
new Filler() { Id = 4, Pos = 4, Type = Filler.FillerType.Pourer },
new Filler() { Id = 5, Pos = 5, Type = Filler.FillerType.Pourer },
new Filler() { Id = 6, Pos = 6, Type = Filler.FillerType.Pourer },
new Filler() { Id = 7, Pos = 7, Type = Filler.FillerType.Pourer },
new Filler() { Id = 8, Pos = 8, Type = Filler.FillerType.Pourer },
new Filler() { Id = 9, Pos = 9, Type = Filler.FillerType.Pourer },
new Filler() { Id = 10, Pos = 10, Type = Filler.FillerType.Pourer },
new Filler() { Id = 11, Pos = 11, Type = Filler.FillerType.Pourer },
new Filler() { Id = 12, Pos = 12, Type = Filler.FillerType.Pump },
new Filler() { Id = 13, Pos = 13, Type = Filler.FillerType.Pump },
new Filler() { Id = 14, Pos = 14, Type = Filler.FillerType.Pump }
new Filler() { Id = 4, Pos = 1, Type = Filler.FillerType.Pourer },
new Filler() { Id = 5, Pos = 2, Type = Filler.FillerType.Pourer },
new Filler() { Id = 6, Pos = 3, Type = Filler.FillerType.Pourer },
new Filler() { Id = 7, Pos = 4, Type = Filler.FillerType.Pourer },
new Filler() { Id = 8, Pos = 5, Type = Filler.FillerType.Pourer },
new Filler() { Id = 9, Pos = 6, Type = Filler.FillerType.Pourer },
new Filler() { Id = 10, Pos = 7, Type = Filler.FillerType.Pourer },
new Filler() { Id = 11, Pos = 8, Type = Filler.FillerType.Pourer },
new Filler() { Id = 12, Pos = 4, Type = Filler.FillerType.Pump },
new Filler() { Id = 13, Pos = 5, Type = Filler.FillerType.Pump },
new Filler() { Id = 14, Pos = 6, Type = Filler.FillerType.Pump }
);
modelBuilder.Entity<Filler>().HasIndex(p => new {p.Type, p.Pos}).IsUnique();
modelBuilder.Entity<Glas>().ToTable("Glaeser");
+6 -2
View File
@@ -3,9 +3,13 @@
public class Glas
{
public int Id { get; set; }
public string Name { get
public string? Name { get; set; }
public string DisplayName { get
{
return $"{Fuellmenge} ml";
string name = "";
if (Name != null) name += $"{Name} - ";
name += $"{Fuellmenge} ml";
return name;
}
}
public int Fuellmenge { get; set; }
Binary file not shown.
Binary file not shown.
View File
Whitespace-only changes.
+3 -1
View File
@@ -2,12 +2,14 @@
{
public class GeneralSettings
{
public int MaxAllowedUploadSizeInMB { get; set; } = 10;
public string ImageUploadDir { get; set; } = "images";
public string SerialPort { get; set; } = "COM5";
public int Baudrate { get; set; } = 115200;
public string? SettingsPassword { get; set; }
}
}
@@ -0,0 +1,269 @@
// <auto-generated />
using System;
using CocktailWeb.Data;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Migrations;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
#nullable disable
namespace CocktailWeb.Migrations
{
[DbContext(typeof(DbDataContext))]
[Migration("20240228182043_ModifyCocktailAddErstellerCounter")]
partial class ModifyCocktailAddErstellerCounter
{
/// <inheritdoc />
protected override void BuildTargetModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder.HasAnnotation("ProductVersion", "8.0.1");
modelBuilder.Entity("CocktailWeb.Data.Cocktail", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("INTEGER");
b.Property<int>("Counter")
.HasColumnType("INTEGER");
b.Property<string>("Ersteller")
.HasColumnType("TEXT");
b.Property<string>("ImageURL")
.HasColumnType("TEXT");
b.Property<string>("Name")
.IsRequired()
.HasColumnType("TEXT");
b.HasKey("Id");
b.ToTable("Cocktails");
});
modelBuilder.Entity("CocktailWeb.Data.CocktailFlasche", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("INTEGER");
b.Property<int>("CocktailID")
.HasColumnType("INTEGER");
b.Property<int>("FlascheID")
.HasColumnType("INTEGER");
b.Property<int>("Menge")
.HasColumnType("INTEGER");
b.Property<int>("Reihenfolge")
.HasColumnType("INTEGER");
b.HasKey("Id");
b.HasIndex("CocktailID");
b.HasIndex("FlascheID");
b.ToTable("CocktailFlaschen");
});
modelBuilder.Entity("CocktailWeb.Data.Filler", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("INTEGER");
b.Property<int?>("FlascheId")
.HasColumnType("INTEGER");
b.Property<int>("Pos")
.HasColumnType("INTEGER");
b.Property<int>("Type")
.HasColumnType("INTEGER");
b.HasKey("Id");
b.HasIndex("FlascheId");
b.ToTable("Fillers");
b.HasData(
new
{
Id = 1,
Pos = 1,
Type = 0
},
new
{
Id = 2,
Pos = 2,
Type = 0
},
new
{
Id = 3,
Pos = 3,
Type = 0
},
new
{
Id = 4,
Pos = 4,
Type = 1
},
new
{
Id = 5,
Pos = 5,
Type = 1
},
new
{
Id = 6,
Pos = 6,
Type = 1
},
new
{
Id = 7,
Pos = 7,
Type = 1
},
new
{
Id = 8,
Pos = 8,
Type = 1
},
new
{
Id = 9,
Pos = 9,
Type = 1
},
new
{
Id = 10,
Pos = 10,
Type = 1
},
new
{
Id = 11,
Pos = 11,
Type = 1
},
new
{
Id = 12,
Pos = 12,
Type = 0
},
new
{
Id = 13,
Pos = 13,
Type = 0
},
new
{
Id = 14,
Pos = 14,
Type = 0
});
});
modelBuilder.Entity("CocktailWeb.Data.Flasche", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("INTEGER");
b.Property<bool>("Alkoholisch")
.HasColumnType("INTEGER");
b.Property<string>("ImageURL")
.HasColumnType("TEXT");
b.Property<string>("Name")
.IsRequired()
.HasColumnType("TEXT");
b.HasKey("Id");
b.ToTable("Flaschen", (string)null);
b.HasData(
new
{
Id = 1,
Alkoholisch = true,
Name = "Jägermeister"
},
new
{
Id = 2,
Alkoholisch = true,
Name = "Wodka"
});
});
modelBuilder.Entity("CocktailWeb.Data.Glas", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("INTEGER");
b.Property<int>("Fuellmenge")
.HasColumnType("INTEGER");
b.Property<string>("ImageURL")
.HasColumnType("TEXT");
b.HasKey("Id");
b.ToTable("Glaeser", (string)null);
});
modelBuilder.Entity("CocktailWeb.Data.CocktailFlasche", b =>
{
b.HasOne("CocktailWeb.Data.Cocktail", "Cocktail")
.WithMany("Cocktailflaschen")
.HasForeignKey("CocktailID")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("CocktailWeb.Data.Flasche", "Flasche")
.WithMany()
.HasForeignKey("FlascheID")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Cocktail");
b.Navigation("Flasche");
});
modelBuilder.Entity("CocktailWeb.Data.Filler", b =>
{
b.HasOne("CocktailWeb.Data.Flasche", "Flasche")
.WithMany()
.HasForeignKey("FlascheId");
b.Navigation("Flasche");
});
modelBuilder.Entity("CocktailWeb.Data.Cocktail", b =>
{
b.Navigation("Cocktailflaschen");
});
#pragma warning restore 612, 618
}
}
}
@@ -0,0 +1,39 @@
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace CocktailWeb.Migrations
{
/// <inheritdoc />
public partial class ModifyCocktailAddErstellerCounter : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AddColumn<int>(
name: "Counter",
table: "Cocktails",
type: "INTEGER",
nullable: false,
defaultValue: 0);
migrationBuilder.AddColumn<string>(
name: "Ersteller",
table: "Cocktails",
type: "TEXT",
nullable: true);
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropColumn(
name: "Counter",
table: "Cocktails");
migrationBuilder.DropColumn(
name: "Ersteller",
table: "Cocktails");
}
}
}
@@ -0,0 +1,272 @@
// <auto-generated />
using System;
using CocktailWeb.Data;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Migrations;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
#nullable disable
namespace CocktailWeb.Migrations
{
[DbContext(typeof(DbDataContext))]
[Migration("20240228183936_ModiyFillerUniquePosType")]
partial class ModiyFillerUniquePosType
{
/// <inheritdoc />
protected override void BuildTargetModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder.HasAnnotation("ProductVersion", "8.0.1");
modelBuilder.Entity("CocktailWeb.Data.Cocktail", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("INTEGER");
b.Property<int>("Counter")
.HasColumnType("INTEGER");
b.Property<string>("Ersteller")
.HasColumnType("TEXT");
b.Property<string>("ImageURL")
.HasColumnType("TEXT");
b.Property<string>("Name")
.IsRequired()
.HasColumnType("TEXT");
b.HasKey("Id");
b.ToTable("Cocktails");
});
modelBuilder.Entity("CocktailWeb.Data.CocktailFlasche", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("INTEGER");
b.Property<int>("CocktailID")
.HasColumnType("INTEGER");
b.Property<int>("FlascheID")
.HasColumnType("INTEGER");
b.Property<int>("Menge")
.HasColumnType("INTEGER");
b.Property<int>("Reihenfolge")
.HasColumnType("INTEGER");
b.HasKey("Id");
b.HasIndex("CocktailID");
b.HasIndex("FlascheID");
b.ToTable("CocktailFlaschen");
});
modelBuilder.Entity("CocktailWeb.Data.Filler", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("INTEGER");
b.Property<int?>("FlascheId")
.HasColumnType("INTEGER");
b.Property<int>("Pos")
.HasColumnType("INTEGER");
b.Property<int>("Type")
.HasColumnType("INTEGER");
b.HasKey("Id");
b.HasIndex("FlascheId");
b.HasIndex("Type", "Pos")
.IsUnique();
b.ToTable("Fillers");
b.HasData(
new
{
Id = 1,
Pos = 1,
Type = 0
},
new
{
Id = 2,
Pos = 2,
Type = 0
},
new
{
Id = 3,
Pos = 3,
Type = 0
},
new
{
Id = 4,
Pos = 1,
Type = 1
},
new
{
Id = 5,
Pos = 2,
Type = 1
},
new
{
Id = 6,
Pos = 3,
Type = 1
},
new
{
Id = 7,
Pos = 4,
Type = 1
},
new
{
Id = 8,
Pos = 5,
Type = 1
},
new
{
Id = 9,
Pos = 6,
Type = 1
},
new
{
Id = 10,
Pos = 7,
Type = 1
},
new
{
Id = 11,
Pos = 8,
Type = 1
},
new
{
Id = 12,
Pos = 4,
Type = 0
},
new
{
Id = 13,
Pos = 5,
Type = 0
},
new
{
Id = 14,
Pos = 6,
Type = 0
});
});
modelBuilder.Entity("CocktailWeb.Data.Flasche", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("INTEGER");
b.Property<bool>("Alkoholisch")
.HasColumnType("INTEGER");
b.Property<string>("ImageURL")
.HasColumnType("TEXT");
b.Property<string>("Name")
.IsRequired()
.HasColumnType("TEXT");
b.HasKey("Id");
b.ToTable("Flaschen", (string)null);
b.HasData(
new
{
Id = 1,
Alkoholisch = true,
Name = "Jägermeister"
},
new
{
Id = 2,
Alkoholisch = true,
Name = "Wodka"
});
});
modelBuilder.Entity("CocktailWeb.Data.Glas", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("INTEGER");
b.Property<int>("Fuellmenge")
.HasColumnType("INTEGER");
b.Property<string>("ImageURL")
.HasColumnType("TEXT");
b.HasKey("Id");
b.ToTable("Glaeser", (string)null);
});
modelBuilder.Entity("CocktailWeb.Data.CocktailFlasche", b =>
{
b.HasOne("CocktailWeb.Data.Cocktail", "Cocktail")
.WithMany("Cocktailflaschen")
.HasForeignKey("CocktailID")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("CocktailWeb.Data.Flasche", "Flasche")
.WithMany()
.HasForeignKey("FlascheID")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Cocktail");
b.Navigation("Flasche");
});
modelBuilder.Entity("CocktailWeb.Data.Filler", b =>
{
b.HasOne("CocktailWeb.Data.Flasche", "Flasche")
.WithMany()
.HasForeignKey("FlascheId");
b.Navigation("Flasche");
});
modelBuilder.Entity("CocktailWeb.Data.Cocktail", b =>
{
b.Navigation("Cocktailflaschen");
});
#pragma warning restore 612, 618
}
}
}
@@ -0,0 +1,182 @@
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace CocktailWeb.Migrations
{
/// <inheritdoc />
public partial class ModiyFillerUniquePosType : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.UpdateData(
table: "Fillers",
keyColumn: "Id",
keyValue: 4,
column: "Pos",
value: 1);
migrationBuilder.UpdateData(
table: "Fillers",
keyColumn: "Id",
keyValue: 5,
column: "Pos",
value: 2);
migrationBuilder.UpdateData(
table: "Fillers",
keyColumn: "Id",
keyValue: 6,
column: "Pos",
value: 3);
migrationBuilder.UpdateData(
table: "Fillers",
keyColumn: "Id",
keyValue: 7,
column: "Pos",
value: 4);
migrationBuilder.UpdateData(
table: "Fillers",
keyColumn: "Id",
keyValue: 8,
column: "Pos",
value: 5);
migrationBuilder.UpdateData(
table: "Fillers",
keyColumn: "Id",
keyValue: 9,
column: "Pos",
value: 6);
migrationBuilder.UpdateData(
table: "Fillers",
keyColumn: "Id",
keyValue: 10,
column: "Pos",
value: 7);
migrationBuilder.UpdateData(
table: "Fillers",
keyColumn: "Id",
keyValue: 11,
column: "Pos",
value: 8);
migrationBuilder.UpdateData(
table: "Fillers",
keyColumn: "Id",
keyValue: 12,
column: "Pos",
value: 4);
migrationBuilder.UpdateData(
table: "Fillers",
keyColumn: "Id",
keyValue: 13,
column: "Pos",
value: 5);
migrationBuilder.UpdateData(
table: "Fillers",
keyColumn: "Id",
keyValue: 14,
column: "Pos",
value: 6);
migrationBuilder.CreateIndex(
name: "IX_Fillers_Type_Pos",
table: "Fillers",
columns: new[] { "Type", "Pos" },
unique: true);
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropIndex(
name: "IX_Fillers_Type_Pos",
table: "Fillers");
migrationBuilder.UpdateData(
table: "Fillers",
keyColumn: "Id",
keyValue: 4,
column: "Pos",
value: 4);
migrationBuilder.UpdateData(
table: "Fillers",
keyColumn: "Id",
keyValue: 5,
column: "Pos",
value: 5);
migrationBuilder.UpdateData(
table: "Fillers",
keyColumn: "Id",
keyValue: 6,
column: "Pos",
value: 6);
migrationBuilder.UpdateData(
table: "Fillers",
keyColumn: "Id",
keyValue: 7,
column: "Pos",
value: 7);
migrationBuilder.UpdateData(
table: "Fillers",
keyColumn: "Id",
keyValue: 8,
column: "Pos",
value: 8);
migrationBuilder.UpdateData(
table: "Fillers",
keyColumn: "Id",
keyValue: 9,
column: "Pos",
value: 9);
migrationBuilder.UpdateData(
table: "Fillers",
keyColumn: "Id",
keyValue: 10,
column: "Pos",
value: 10);
migrationBuilder.UpdateData(
table: "Fillers",
keyColumn: "Id",
keyValue: 11,
column: "Pos",
value: 11);
migrationBuilder.UpdateData(
table: "Fillers",
keyColumn: "Id",
keyValue: 12,
column: "Pos",
value: 12);
migrationBuilder.UpdateData(
table: "Fillers",
keyColumn: "Id",
keyValue: 13,
column: "Pos",
value: 13);
migrationBuilder.UpdateData(
table: "Fillers",
keyColumn: "Id",
keyValue: 14,
column: "Pos",
value: 14);
}
}
}
@@ -23,6 +23,12 @@ namespace CocktailWeb.Migrations
.ValueGeneratedOnAdd()
.HasColumnType("INTEGER");
b.Property<int>("Counter")
.HasColumnType("INTEGER");
b.Property<string>("Ersteller")
.HasColumnType("TEXT");
b.Property<string>("ImageURL")
.HasColumnType("TEXT");
@@ -32,7 +38,7 @@ namespace CocktailWeb.Migrations
b.HasKey("Id");
b.ToTable("Cocktails");
b.ToTable("Cocktails", (string)null);
});
modelBuilder.Entity("CocktailWeb.Data.CocktailFlasche", b =>
@@ -59,7 +65,7 @@ namespace CocktailWeb.Migrations
b.HasIndex("FlascheID");
b.ToTable("CocktailFlaschen");
b.ToTable("CocktailFlaschen", (string)null);
});
modelBuilder.Entity("CocktailWeb.Data.Filler", b =>
@@ -81,7 +87,10 @@ namespace CocktailWeb.Migrations
b.HasIndex("FlascheId");
b.ToTable("Fillers");
b.HasIndex("Type", "Pos")
.IsUnique();
b.ToTable("Fillers", (string)null);
b.HasData(
new
@@ -105,67 +114,67 @@ namespace CocktailWeb.Migrations
new
{
Id = 4,
Pos = 4,
Pos = 1,
Type = 1
},
new
{
Id = 5,
Pos = 5,
Pos = 2,
Type = 1
},
new
{
Id = 6,
Pos = 6,
Pos = 3,
Type = 1
},
new
{
Id = 7,
Pos = 7,
Pos = 4,
Type = 1
},
new
{
Id = 8,
Pos = 8,
Pos = 5,
Type = 1
},
new
{
Id = 9,
Pos = 9,
Pos = 6,
Type = 1
},
new
{
Id = 10,
Pos = 10,
Pos = 7,
Type = 1
},
new
{
Id = 11,
Pos = 11,
Pos = 8,
Type = 1
},
new
{
Id = 12,
Pos = 12,
Pos = 4,
Type = 0
},
new
{
Id = 13,
Pos = 13,
Pos = 5,
Type = 0
},
new
{
Id = 14,
Pos = 14,
Pos = 6,
Type = 0
});
});
+256 -32
View File
@@ -17,46 +17,110 @@
@if (SelectedCocktail == null)
{
<h3>Cocktail konnte nicht gefunden werden</h3>
}
else
{
<div class="card mb-3" style="max-width: 540px;">
<div class="row g-0">
<div class="col-md-4">
<img src="@SelectedCocktail.ImageURL" class="img-fluid rounded-start" alt="...">
</div>
<div class="col-md-8">
<div class="card-body">
<h5 class="card-title">@SelectedCocktail.Name</h5>
<p class="card-text">
<h6>Zutaten:</h6>
<ul>
@foreach (var Zutat in SelectedCocktail.Cocktailflaschen.OrderBy(f => f.Reihenfolge))
<div class="d-flex gap-3">
<div class="card mb-3 w-100">
<div class="row g-0">
<div class="col-md-8">
<div class="card-body">
<h5 class="card-title">Einstellungen</h5>
<p class="card-text">
<h6>
Stärke
</h6>
@if (!UseNewIntensityCalc)
{
@if (MaschinenFiller != null && MaschinenFiller.Exists(f => f.Flasche == Zutat.Flasche))
{
<li>@Zutat.Flasche?.Name (@Zutat.Menge ml)</li>
}
else
{
@* Zutat nicht in MaschinenFiller gefunden - Daher ist Maschine nicht damit bestückt*@
<li class="text-danger">@Zutat.Flasche?.Name (@Zutat.Menge ml) (nicht geladen)</li>
}
<div class="btn-group" role="group">
<button @onclick="() => SetIntensity(-60)" class="btn @(SelectedCocktail.IsAlcoholic ? "" : "disabled") btn-@(DrinkIntensity <= -60 ? "" : "outline-")success"><i class="bi bi-peace fs-5"></i></button>
<button @onclick="() => SetIntensity(-40)" class="btn @(SelectedCocktail.IsAlcoholic ? "" : "disabled") btn-@(DrinkIntensity <= -40 ? "" : "outline-")success"><i class="bi bi-dash fs-5"></i></button>
<button @onclick="() => SetIntensity(-20)" class="btn @(SelectedCocktail.IsAlcoholic ? "" : "disabled") btn-@(DrinkIntensity <= -20 ? "" : "outline-")success"><i class="bi bi-dash"></i></button>
<button @onclick="() => SetIntensity(0)" class="btn @(SelectedCocktail.IsAlcoholic ? "" : "disabled") btn-@(DrinkIntensity == 0 ? "" : "")warning"><i class="bi bi-circle"></i></button>
<button @onclick="() => SetIntensity(20)" class="btn @(SelectedCocktail.IsAlcoholic ? "" : "disabled") btn-@(DrinkIntensity >= 20 ? "" : "outline-")danger"><i class="bi bi-plus"></i></button>
<button @onclick="() => SetIntensity(40)" class="btn @(SelectedCocktail.IsAlcoholic ? "" : "disabled") btn-@(DrinkIntensity >= 40 ? "" : "outline-")danger"><i class="bi bi-plus fs-5"></i></button>
<button @onclick="() => SetIntensity(60)" class="btn @(SelectedCocktail.IsAlcoholic ? "" : "disabled") btn-@(DrinkIntensity >= 60 ? "" : "outline-")danger"><i class="bi bi-radioactive fs-5"></i></button>
</div>
}
</ul>
</p>
else
{
<div class="btn-group" role="group">
<button @onclick="() => SetIntensityPercentual(-3)" class="btn @(SelectedCocktail.IsAlcoholic ? "" : "disabled") btn-@(DrinkIntensity <= -3 ? "" : "outline-")success"><i class="bi bi-peace fs-5"></i></button>
<button @onclick="() => SetIntensityPercentual(-2)" class="btn @(SelectedCocktail.IsAlcoholic ? "" : "disabled") btn-@(DrinkIntensity <= -2 ? "" : "outline-")success"><i class="bi bi-dash fs-5"></i></button>
<button @onclick="() => SetIntensityPercentual(-1)" class="btn @(SelectedCocktail.IsAlcoholic ? "" : "disabled") btn-@(DrinkIntensity <= -1 ? "" : "outline-")success"><i class="bi bi-dash"></i></button>
<button @onclick="() => SetIntensityPercentual(0)" class="btn @(SelectedCocktail.IsAlcoholic ? "" : "disabled") btn-@(DrinkIntensity == 0 ? "" : "")warning"><i class="bi bi-circle"></i></button>
<button @onclick="() => SetIntensityPercentual(1)" class="btn @(SelectedCocktail.IsAlcoholic ? "" : "disabled") btn-@(DrinkIntensity >= 1 ? "" : "outline-")danger"><i class="bi bi-plus"></i></button>
<button @onclick="() => SetIntensityPercentual(2)" class="btn @(SelectedCocktail.IsAlcoholic ? "" : "disabled") btn-@(DrinkIntensity >= 2 ? "" : "outline-")danger"><i class="bi bi-plus fs-5"></i></button>
<button @onclick="() => SetIntensityPercentual(3)" class="btn @(SelectedCocktail.IsAlcoholic ? "" : "disabled") btn-@(DrinkIntensity >= 3 ? "" : "outline-")danger"><i class="bi bi-radioactive fs-5"></i></button>
</div>
}
</p>
@if (ErrorMessage != null)
{
<div class="alert alert-danger" role="alert">
@ErrorMessage
</div>
}
@if (CocktailCode != null)
{
<div class="alert alert-dark" style="white-space: pre-line" role="alert">
@CocktailCode
</div>
}
<button class="btn btn-primary" @onclick=CreateCocktailCode>Lets goooooo!</button>
</div>
</div>
</div>
</div>
<div class="card mb-3 w-100">
<div class="row g-0">
<div class="col-md-4">
<img src="@SelectedCocktail.ImageURL" class="img-fluid rounded-start" alt="...">
</div>
<div class="col-md-8">
<div class="card-body">
<h5 class="card-title">@SelectedCocktail.Name</h5>
<p class="card-text">
<h6>Rezept:</h6>
<table class="table-primary table-borderless w-100">
@{
int i = 1;
}
@foreach (var Zutat in SelectedCocktail.Cocktailflaschen.OrderBy(f => f.Reihenfolge))
{
<tr class="@(ZutatInMaschine(Zutat) ? "" : "text-danger")">
<td>@i.</td>
<td>@Zutat.Flasche?.Name</td>
<td class="text-end">@Zutat.Menge ml</td>
@if (DrinkIntensity != 0)
{
<td>=></td>
<td class="text-end">@ModifiedCocktail?.Cocktailflaschen.First(cf => cf.FlascheID == Zutat.FlascheID).Menge ml</td>
}
<td class="text-end">@(ZutatInMaschine(Zutat) ? "" : "fehlt")</td>
</tr>
i++;
}
<tr>
<td></td>
<td>Gesamt</td>
<td class="text-end">@SelectedCocktail.Cocktailflaschen.Sum(cf => cf.Menge) ml</td>
@if (DrinkIntensity != 0)
{
<td>=></td>
<td class="text-end">@ModifiedCocktail?.Cocktailflaschen.Sum(cf => cf.Menge) ml</td>
}
<td class="text-end"></td>
</tr>
</table>
</p>
</div>
</div>
</div>
</div>
</div>
@if (ValideMische)
{
<button class="btn btn-primary">Lets goooooo!</button>
} else
{
<button class="btn btn-outline-primary">Lets goooooo!</button>
}
}
@@ -65,21 +129,181 @@ else
public string? CocktailId { get; set; }
private DbDataContext? _DataContext;
private Cocktail? SelectedCocktail;
private Cocktail? ModifiedCocktail;
private List<Filler>? MaschinenFiller;
//private List<CocktailFlasche> ModifiedCocktailRecipe = new();
private bool ValideMische = true;
private int DrinkIntensity = 0;
private bool UseNewIntensityCalc = false;
private string? ErrorMessage;
private string? CocktailCode;
protected override async Task OnInitializedAsync()
{
int id = Convert.ToInt32(CocktailId);
//Staerke_Off.Add();
_DataContext ??= await DataContextFactory.CreateDbContextAsync();
if (_DataContext != null)
{
SelectedCocktail = _DataContext.Cocktails.Include(c => c.Cocktailflaschen).ThenInclude(cf => cf.Flasche).Single(c => c.Id == id);
ModifiedCocktail = _DataContext.Cocktails.Include(c => c.Cocktailflaschen).ThenInclude(cf => cf.Flasche).AsNoTracking().Single(c => c.Id == id);
MaschinenFiller = _DataContext.Fillers.Include(f => f.Flasche).OrderBy(f => f.Pos).ToList();
}
// if (SelectedCocktail != null)
// {
// foreach (CocktailFlasche cf in SelectedCocktail.Cocktailflaschen)
// {
// ModifiedCocktailRecipe.Add(new CocktailFlasche() {
// Flasche = cf.Flasche,
// Menge = cf.Menge
// });
// }
// }
}
private bool ZutatInMaschine(CocktailFlasche zutat)
{
return (MaschinenFiller != null && MaschinenFiller.Exists(f => f.Flasche == zutat.Flasche));
}
/// <summary>
/// Prüft, ob der Cocktail gesendet werden kann
/// </summary>
/// <returns></returns>
private bool IsValid()
{
ErrorMessage = null;
if (ModifiedCocktail == null || MaschinenFiller == null)
{
ErrorMessage = "Cocktail nicht gefunden.";
return false;
}
if (ModifiedCocktail.Cocktailflaschen.Count == 0)
{
ErrorMessage = "Der Cocktail enthält keine Zutaten";
return false;
}
if (!ModifiedCocktail.Cocktailflaschen.All(cf => MaschinenFiller.Any(mf => mf.Flasche?.Id == cf.FlascheID)))
{
ErrorMessage = "Es sind nicht alle Zutaten in der Cocktailmaschine geladen!";
return false;
}
return true;
}
/// <summary>
/// Erstellt den für die Arduino-Steuerung erforderlichen Code
/// </summary>
private void CreateCocktailCode()
{
CocktailCode = null;
if (!IsValid() || ModifiedCocktail == null || MaschinenFiller == null) return;
List<string> lines = new();
lines.Add("START");
@foreach (CocktailFlasche Zutat in ModifiedCocktail.Cocktailflaschen.OrderBy(f => f.Reihenfolge))
{
string line = "";
Filler Filler = MaschinenFiller.First(mf => mf.Flasche?.Id == Zutat.FlascheID);
if (Filler.Type == Filler.FillerType.Pump)
{
line = $"P{Filler.Pos}={Zutat.Menge}";
}
else if (Filler.Type == Filler.FillerType.Pourer)
{
line = $"F{Filler.Pos}={Zutat.Menge}";
}
lines.Add(line);
}
lines.Add("ZIEL");
CocktailCode = String.Join("\r\n", lines.ToArray());
}
/// <summary>
/// Setzt die Alkoholintensität und berechnet die Mengen für ModifiedCocktail entsprechend neu
/// </summary>
/// <param name="intensity">Zugabe/Abzug von Alkohol in Prozent</param>
private void SetIntensity(int intensity)
{
DrinkIntensity = intensity;
if (ModifiedCocktail == null || SelectedCocktail == null) return;
foreach (CocktailFlasche cf in ModifiedCocktail.Cocktailflaschen)
{
int OriginalMenge = SelectedCocktail.Cocktailflaschen.First(scf => scf.Id == cf.Id).Menge;
if (cf.Flasche.Alkoholisch)
{
cf.Menge = OriginalMenge + (OriginalMenge * intensity / 100);
}
else
{
cf.Menge = OriginalMenge - (OriginalMenge * intensity / 100);
}
}
// Durch das anteilige Umrechnen ändert sich die Gesamtmenge, daher passen wir die Mengen nochmal an
int AktGesMenge = ModifiedCocktail.Cocktailflaschen.Sum(cf => cf.Menge);
int OrigMenge = SelectedCocktail.Cocktailflaschen.Sum(cf => cf.Menge);
foreach (CocktailFlasche cf in ModifiedCocktail.Cocktailflaschen)
{
cf.Menge = (int)((float)cf.Menge / AktGesMenge * OrigMenge);
}
}
// ToDo: Ggf. noch Rundungsfehler drin oder wirklich noch grobe Fehler in der Mathematik.. Gesamtmenge passt irgendwie nicht.
/// <summary>
/// Ändert die Alkoholintensität basierend auf den Prozentwerten anstatt der Menge
/// </summary>
/// <param name="intensitylevel">Intensitätslevel (z.B. -1, 0, 1,2 ...)</param>
private void SetIntensityPercentual(int intensitylevel)
{
DrinkIntensity = intensitylevel;
if (ModifiedCocktail == null || SelectedCocktail == null) return;
int DivideParts = 4; // Gibt an, in wieviele Teile die nicht-alkoholische Gesamtmenge aufgeteilt wird. Sollte mindestens 1 oder 2 mehr als das Max.Intensitätslevel sein
float IncreasePerLevel_pct; // Gibt an, um welchen Anteil in % die alkoholischen Getränke steigen.
float SumAlcoholic_ml = SelectedCocktail.Cocktailflaschen.Where(cf => cf.Flasche.Alkoholisch).Sum(cf => cf.Menge); // Summe in ml der Alkoholhaltigen Zutaten
float SumNonAlcoholic_ml = SelectedCocktail.Cocktailflaschen.Where(cf => !cf.Flasche.Alkoholisch).Sum(cf => cf.Menge); // Summe in ml der Alkoholfreien Zutaten
float SumTotal = SumAlcoholic_ml + SumNonAlcoholic_ml;
float SumAlcoholic_pct = SumAlcoholic_ml / SumTotal * 100; //Prozentwert an alkoholhaltigen Zutaten
float SumNonAlcoholic_pct = SumNonAlcoholic_ml / SumTotal * 100; //Prozentwert an alkoholhaltigen Zutaten
float SumBasis_ml = intensitylevel >= 0 ? SumNonAlcoholic_ml : SumAlcoholic_ml; // Wenn Intensität > 0, dann ist Summenbasis nichtalkoholisch, ansonsten alkoholisch
if (intensitylevel >= 0)
{
/// Wenn alkoholhaltiges 30% ausmacht, teilen wir den Rest (alkoholfreis, 70%) durch die o.g. DivideParts, damit wir wissen um wieviel Prozent pro Stufe wir erhöhen können
IncreasePerLevel_pct = SumNonAlcoholic_pct / DivideParts;
}
else
{
// Cocktail abschwächen, daher teilen wir in die andere Richtung auf
IncreasePerLevel_pct = SumAlcoholic_pct / DivideParts;
}
foreach (CocktailFlasche cf in ModifiedCocktail.Cocktailflaschen)
{
float OrigMenge = SelectedCocktail.Cocktailflaschen.First(f => f.Id == cf.Id).Menge;
// Herausfinden, wieviel Prozent die Zutat in ihrem Bereich (Alkoholisch/Nichtalkoholisch) ausmacht
float ZutatIncrease_pct = IncreasePerLevel_pct / SumBasis_ml * cf.Menge;
float ZutatMenge_pct = (float)OrigMenge / SumTotal * 100;
// Neue Menge in Prozent: ZutatMenge_pct + ZutatIncrease_pct
if (!cf.Flasche.Alkoholisch ^ intensitylevel < 0 )
{
ZutatIncrease_pct *= -1;
}
cf.Menge = (int)Math.Round(OrigMenge / ZutatMenge_pct * (ZutatMenge_pct + (ZutatIncrease_pct * intensitylevel)), 0, MidpointRounding.AwayFromZero);
}
}
}
+7 -1
View File
@@ -28,7 +28,13 @@
<img class="card-img-top" style="width:100%; min-height:70vh; object-fit:cover;" src="@($"/img/cocktail-default.jpg")" alt="@c.Name">
}
<div class="card-footer">
<h5 class="card-title">@c.Name</h5>
<h5 class="card-title">
@c.Name
@if(!c.IsAlcoholic)
{
<i class="bi bi-car-front ms-2 text-info"></i>
}
</h5>
<!--<p class="card-text">
Testy
</p>-->
+24 -6
View File
@@ -12,19 +12,37 @@ namespace CocktailWeb.Pages
private DbDataContext? _DataContext;
private List<Cocktail> CocktailListe { get; set; } = new();
private List<Filler>? MaschinenFiller;
protected override async Task OnInitializedAsync()
{
await ShowCocktails();
}
private async Task ShowCocktails()
{
_DataContext ??= await DataContextFactory.CreateDbContextAsync();
if (_DataContext != null)
{
CocktailListe = await _DataContext.Cocktails.OrderBy(f => f.Name).ToListAsync();
MaschinenFiller = _DataContext.Fillers
.Include(f => f.Flasche)
.OrderBy(f => f.Pos).ToList();
CocktailListe = await _DataContext.Cocktails
.Include(c => c.Cocktailflaschen)
.ThenInclude(cf => cf.Flasche)
.OrderBy(c => c.Name)
.ToListAsync();
}
}
/// <summary>
/// Prüft, ob der angegebene Cocktail aktuell machbar ist (true) oder ob mindestens eine Flasche nicht auf der Maschine fehlt (false)
/// </summary>
/// <param name="cocktail"></param>
/// <returns></returns>
private bool IsTappable(Cocktail cocktail)
{
if (MaschinenFiller != null)
{
return cocktail.Cocktailflaschen.All(cf => MaschinenFiller.Any(mf => mf.Flasche == cf.Flasche));
}
return false;
}
}
}
+17 -1
View File
@@ -9,6 +9,22 @@ Welcome to your new app.
<a href="/cocktails">
Cocktails</a>
@code {
@code {
// Menüauswahl:
// - Cocktails
// - Alkoholfreie?
// - Favoriten
// - Top 10?
// - Spiel und Spaß
// - - Zufallscocktail
// - - Zufallsmische
// - Einstellungen?
// Maschineneinstellungen
// - Standardglas
// - Max. Ausgießermenge pro Ausguss (aktuell 30ml)
// - Benötigte Zeit für max. Ausgießermenge (1400ms bei 30ml aktuell) - Maschine rechnet kleinere Mengen entsprechend um
// - Ggf. X- und Z-Positionen für die Filler
}
+2 -2
View File
@@ -33,7 +33,7 @@
private string modalClass = "";
private bool showBackdrop = false;
public async Task OpenModal()
public async Task ShowAsync()
{
modalDisplay = "block;";
await Task.Delay(100);//Delay allows bootstrap to perform nice fade animation
@@ -41,7 +41,7 @@
showBackdrop = true;
}
public async Task Close()
public async Task CloseAsync()
{
modalDisplay = "none";
await Task.Delay(250);//Delay allows bootstrap to perform nice fade animation
+2 -2
View File
@@ -23,7 +23,7 @@
bool Sending = false;
bool Receiving = false;
public async Task SendData()
public void SendData()
{
if (Sending) return; // nichts senden, wenn bereits am Senden
Sending = true;
@@ -57,7 +57,7 @@
SerialPort port = (SerialPort)sender;
if (port != null)
{
var text = port.ReadExisting();
var text = port.ReadLine();
Console.WriteLine(text);
receivedText = text;
InvokeAsync(StateHasChanged);
@@ -16,13 +16,26 @@
<div class="d-flex gap-3">
<div class="border border-2 rounded p-3 w-100">
<h4>Mein Cocktail</h4>
<div class="mb-3">
<label class="form-label" for="cocktailname">Cocktailname</label>
<input id="cocktailname" name="cocktailname" type="text" class="form-control" @bind="@EditCocktail.Name" />
</div>
<div class="mb-3">
<label class="form-label" for="ersteller">Ersteller</label>
<input id="ersteller" name="ersteller" type="text" class="form-control" @bind="@EditCocktail.Ersteller" />
</div>
<div class="mb-3">
<label class="form-label" for="cocktailimage">Bild</label>
<div class="mb-2">
@if (EditCocktail.ImageURL != null)
{
<img style="max-width:128px;" src="@EditCocktail.ImageURL" />
} else
{
<div>Kein Bild vorhanden</div>
}
</div>
<label class="form-label" for="cocktailimage">Neues Bild hochladen</label>
<InputFile OnChange="Bild_OnChange" class="form-control" id="cocktailimage" name="cocktailimage" accept=".jpg,.png,.jpeg,.gif,.webp" />
</div>
@@ -44,18 +57,18 @@
<th>@cf.Flasche.Name</th>
<td>
<div class="input-group">
<input class="form-control" id="Menge" name="menge" type="text" @bind="@cf.Menge" />
<input class="form-control" id="Menge" name="menge" type="number" @bind="@cf.Menge" />
<span class="input-group-text">ml</span>
</div>
</td>
<td>
<div class="btn-group">
<button class="btn btn-outline-secondary" @onclick="args => FlascheReihenfolge(args, cf,-2)">
<button class="btn btn-outline-primary" @onclick="args => FlascheReihenfolge(args, cf,-2)">
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-caret-up-fill" viewBox="0 0 16 16">
<path d="m7.247 4.86-4.796 5.481c-.566.647-.106 1.659.753 1.659h9.592a1 1 0 0 0 .753-1.659l-4.796-5.48a1 1 0 0 0-1.506 0z" />
</svg>
</button>
<button class="btn btn-outline-secondary" @onclick="args => FlascheReihenfolge(args, cf ,2)">
<button class="btn btn-outline-primary" @onclick="args => FlascheReihenfolge(args, cf ,2)">
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-caret-down-fill" viewBox="0 0 16 16">
<path d="M7.247 11.14 2.451 5.658C1.885 5.013 2.345 4 3.204 4h9.592a1 1 0 0 1 .753 1.659l-4.796 5.48a1 1 0 0 1-1.506 0z" />
</svg>
@@ -72,6 +85,12 @@
</td>
</tr>
}
<tr>
<th></th>
<th>Gesamt</th>
<td>@EditCocktail.Cocktailflaschen.Sum(cf => cf.Menge)</td>
<td colspan="2"></td>
</tr>
}
</tbody>
</table>
@@ -92,7 +111,7 @@
{
@foreach (Flasche fl in FlaschenListe)
{
<li class="list-group-item list-group-item-action align-middle" @onclick="args => FlascheHinzufuegen(args,fl)">
<li class="list-group-item list-group-item-action align-middle z-0" @onclick="args => FlascheHinzufuegen(args,fl)">
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-plus-circle text-success" viewBox="0 0 16 16">
<path d="M8 15A7 7 0 1 1 8 1a7 7 0 0 1 0 14m0 1A8 8 0 1 0 8 0a8 8 0 0 0 0 16" />
<path d="M8 4a.5.5 0 0 1 .5.5v3h3a.5.5 0 0 1 0 1h-3v3a.5.5 0 0 1-1 0v-3h-3a.5.5 0 0 1 0-1h3v-3A.5.5 0 0 1 8 4" />
@@ -6,13 +6,13 @@ using Microsoft.EntityFrameworkCore;
namespace CocktailWeb.Pages.Settings
{
public partial class CocktailHinzufuegen
public partial class CocktailEdit
{
[Parameter]
public string? id { get; set; }
public List<Flasche> FlaschenListe { get; set; } = new();
public Cocktail? EditCocktail;
public Cocktail EditCocktail = null!;
private IBrowserFile? CocktaiLBildDatei;
private DbDataContext? _DataContext;
@@ -104,7 +104,7 @@ namespace CocktailWeb.Pages.Settings
try
{
// Bild hochladen
var relativeuploadpath = Path.Join(Config.Value.ImageUploadDir, $"{EditCocktail.Id}{Path.GetExtension(CocktaiLBildDatei.Name)}");
var relativeuploadpath = Path.Join(Config.Value.ImageUploadDir, $"cocktail_{EditCocktail.Id}{Path.GetExtension(CocktaiLBildDatei.Name)}");
var fullpath = Path.Join(env.WebRootPath, relativeuploadpath);
string? folder = Path.GetDirectoryName(fullpath);
if (folder != null && !Path.Exists(folder)) Directory.CreateDirectory(folder);
+49 -2
View File
@@ -21,7 +21,7 @@
<tr>
<td class="p-0" style="width:64px"><img src="@c.ImageURL" style="max-width:100%; max-height:auto;" /></td>
<td style="vertical-align:middle;">@c.Name</td>
<td style="text-align:right; vertical-align:middle;" >
<td style="text-align:right; vertical-align:middle;">
<a class="btn btn-primary" href="/settings/cocktails/edit/@c.Id">Bearbeiten</a>
<button name="submit" type="submit" class="btn btn-outline-danger" @onclick="() => ConfirmDelete(c)">Löschen</button>
</td>
@@ -29,7 +29,6 @@
}
</tbody>
</table>
</div>
<ModalComponent @ref="modal">
@@ -42,3 +41,51 @@
<button class="btn btn-primary" @onclick="CloseDialog">Nee</button>
</Footer>
</ModalComponent>
@code {
private DbDataContext? _DataContext;
private ModalComponent modal = null!;
private Cocktail? SelectedCocktail;
private List<Cocktail> CocktailListe { get; set; } = new();
protected override async Task OnInitializedAsync()
{
await ShowCocktails();
}
private async Task ShowCocktails()
{
_DataContext ??= await DataContextFactory.CreateDbContextAsync();
if (_DataContext != null)
{
CocktailListe = await _DataContext.Cocktails.OrderBy(f => f.Name).ToListAsync();
}
}
private async Task ConfirmDelete(Cocktail c)
{
SelectedCocktail = c;
await modal.ShowAsync();
}
private async Task CloseDialog()
{
SelectedCocktail = null;
await modal.CloseAsync();
}
private async Task DeleteCocktail(MouseEventArgs e)
{
if (SelectedCocktail != null)
{
_DataContext ??= await DataContextFactory.CreateDbContextAsync();
if (_DataContext != null)
{
_DataContext.Cocktails.Remove(SelectedCocktail);
await _DataContext.SaveChangesAsync();
await ShowCocktails();
}
}
await CloseDialog();
}
}
@@ -1,58 +0,0 @@
using CocktailWeb;
using CocktailWeb.Data;
using Microsoft.AspNetCore.Components;
using Microsoft.AspNetCore.Components.Forms;
using Microsoft.AspNetCore.Components.Web;
using Microsoft.EntityFrameworkCore;
namespace CocktailWeb.Pages.Settings
{
public partial class Cocktails
{
private DbDataContext? _DataContext;
private ModalComponent modal = null!;
private Cocktail? SelectedCocktail;
private List<Cocktail> CocktailListe { get; set; } = new();
protected override async Task OnInitializedAsync()
{
await ShowCocktails();
}
private async Task ShowCocktails()
{
_DataContext ??= await DataContextFactory.CreateDbContextAsync();
if (_DataContext != null)
{
CocktailListe = await _DataContext.Cocktails.OrderBy(f => f.Name).ToListAsync();
}
}
private async Task ConfirmDelete(Cocktail c)
{
SelectedCocktail = c;
await modal.OpenModal();
}
private async Task CloseDialog()
{
SelectedCocktail = null;
await modal.Close();
}
private async Task DeleteCocktail(MouseEventArgs e)
{
if (SelectedCocktail != null)
{
_DataContext ??= await DataContextFactory.CreateDbContextAsync();
if (_DataContext != null)
{
_DataContext.Cocktails.Remove(SelectedCocktail);
await _DataContext.SaveChangesAsync();
await ShowCocktails();
}
}
await CloseDialog();
}
}
}
-73
View File
@@ -1,73 +0,0 @@
@using Microsoft.AspNetCore.Components.Sections
@using Microsoft.EntityFrameworkCore
@using CocktailWeb.Data
@page "/settings/flaschen"
@inject IDbContextFactory<DbDataContext> FlascheDataContextFactory;
<PageTitle>Flaschen</PageTitle>
<SectionContent SectionId="TopRow.Title">
<label>Einstellungen - Zutaten</label>
</SectionContent>
@if (CreateFormVisible && FlascheToCreate != null)
{
<h3>Flasche hinzufügen</h3>
<div class="row">
<label for="Name" class="col-4 col-form-label">Name</label>
<div class="col-8">
<input id="Name" name="Name" type="text" class="form-control" @bind="@FlascheToCreate.Name" />
</div>
</div>
<div class="form-group row">
<div class="offset-4 col-8">
<button name="submit" type="submit" class="btn btn-primary" @onclick="CreateNewFlasche">Hinzufügen</button>
</div>
</div>
}
else
{
<button name="submit" type="submit" class="btn btn-primary" @onclick="ShowCreateForm">Flasche hinzufügen</button>
}
@if (FlaschenListe != null && FlaschenListe.Count > 0)
{
<div class="table-responsive mt-3">
<table class="table table-striped table-hover table-bordered table-dark border-dark">
<thead>
<tr>
<th scope="col">Name</th>
<th style="text-align:right;" scope="col">Action</th>
</tr>
</thead>
<tbody>
@foreach (var flasche in FlaschenListe)
{
@if (EditFormVisible && FlascheToUpdate != null && FlascheToUpdate.Id == flasche.Id)
{
<tr>
<td> <input id="Name" name="Name" type="text" class="form-control" @bind="@FlascheToUpdate.Name" /></td>
<td><button name="submit" type="submit" class="btn btn-primary" @onclick="() => UpdateEmployee(FlascheToUpdate)">Speichern</button></td>
</tr>
}
else
{
<tr>
<td>@flasche.Name</td>
<td style="text-align:right;">
<button name="submit" type="submit" class="btn btn-primary" @onclick="() => ShowEditForm(flasche)">Bearbeiten</button>
<button name="submit" type="submit" class="btn btn-outline-danger" @onclick="() => DeleteFlasche(flasche)">Löschen</button>
</td>
</tr>
}
}
</tbody>
</table>
</div>
}
@code {
}
@@ -1,84 +0,0 @@
using SQLitePCL;
using Microsoft.EntityFrameworkCore;
using CocktailWeb.Data;
namespace CocktailWeb.Pages.Settings
{
public partial class Flaschen
{
public bool CreateFormVisible { get; set; }
public bool EditFormVisible { get; set; }
public Flasche? FlascheToCreate { get; set; }
public Flasche? FlascheToUpdate { get; set; }
public List<Flasche>? FlaschenListe { get; set; }
private DbDataContext? _DataContext;
protected override async Task OnInitializedAsync()
{
CreateFormVisible = false;
await ShowFlaschen();
}
public void ShowCreateForm()
{
FlascheToCreate = new Flasche();
CreateFormVisible = true;
}
public async Task CreateNewFlasche()
{
_DataContext ??= await FlascheDataContextFactory.CreateDbContextAsync();
if (FlascheToCreate != null && _DataContext != null)
{
_DataContext.Flaschen.Add(FlascheToCreate);
await _DataContext.SaveChangesAsync();
}
CreateFormVisible = false;
await ShowFlaschen();
}
public async Task ShowFlaschen()
{
_DataContext ??= await FlascheDataContextFactory.CreateDbContextAsync();
if (_DataContext != null)
{
FlaschenListe = await _DataContext.Flaschen.OrderBy(f => f.Name).ToListAsync();
}
}
public async Task ShowEditForm(Flasche flasche)
{
_DataContext ??= await FlascheDataContextFactory.CreateDbContextAsync();
FlascheToUpdate = _DataContext.Flaschen.FirstOrDefault(f => f.Id == flasche.Id);
EditFormVisible = true;
}
public async Task UpdateEmployee(Flasche flasche)
{
_DataContext ??= await FlascheDataContextFactory.CreateDbContextAsync();
if (_DataContext != null && flasche != null)
{
_DataContext.Flaschen.Update(flasche);
await _DataContext.SaveChangesAsync();
}
EditFormVisible = false;
}
public async Task DeleteFlasche(Flasche flasche)
{
_DataContext ??= await FlascheDataContextFactory.CreateDbContextAsync();
if (_DataContext != null && flasche != null)
{
_DataContext.Flaschen.Remove(flasche);
await _DataContext.SaveChangesAsync();
}
await ShowFlaschen();
}
}
}
-10
View File
@@ -1,10 +0,0 @@
@page "/settings/glaeser"
@using Microsoft.AspNetCore.Components.Sections
<SectionContent SectionId="TopRow.Title">
<label>Einstellungen - Gläser</label>
</SectionContent>
@code {
}
+147
View File
@@ -0,0 +1,147 @@
@page "/settings/glasses/edit"
@page "/settings/glasses/edit/{id}"
@using CocktailWeb.Data
@using Microsoft.AspNetCore.Components.Sections
@using Microsoft.EntityFrameworkCore
@using Microsoft.Extensions.Options
@inject IDbContextFactory<DbDataContext> DataContextFactory;
@inject NavigationManager nav;
@inject IWebHostEnvironment env;
@inject IOptions<GeneralSettings> Config;
<SectionContent SectionId="TopRow.Title">
<label>Glas bearbeiten</label>
</SectionContent>
<EditForm EditContext="editContext" OnValidSubmit="OnSubmit">
<div class="d-flex gap-3">
<div class="border border-2 rounded p-3 w-100">
<div class="mb-3">
<label class="form-label" for="name">Name (optional)</label>
<input class="form-control" id="name" name="name" type="text" @bind=@curGlas.Name />
</div>
<div class="mb-3">
<label class="form-label" for="menge">Füllmenge</label>
<div class="input-group">
<input class="form-control text-end" id="menge" name="menge" type="number" @bind=@curGlas.Fuellmenge />
<span class="input-group-text">ml</span>
<button type="button" class="btn btn-secondary" @onclick="() => ModifyAmount(-10)"><i class="bi bi-dash"></i></button>
<button type="button" class="btn btn-secondary" @onclick="() => ModifyAmount(10)"><i class="bi bi-plus"></i></button>
</div>
<div class="form-text"><ValidationMessage For="() => curGlas.Fuellmenge" /></div>
</div>
<button type="submit" name="submit" class="btn btn-primary">Speichern</button>
<button type="button" @onclick="@(() => nav.NavigateTo(PrevPageURL))" class="btn btn-secondary">Abbrechen</button>
</div>
<div class="border border-2 rounded p-3 w-100">
<div class="mb-3">
<label class="form-label" for="image">Bild</label>
<div class="mb-2">
@if (curGlas.ImageURL != null)
{
<img style="max-width:128px;" src="@curGlas.ImageURL" />
}
else
{
<div>Kein Bild vorhanden</div>
}
</div>
<label class="form-label" for="image">Neues Bild hochladen</label>
<InputFile OnChange="Bild_OnChange" class="form-control" id="image" name="image" accept=".jpg,.png,.jpeg,.gif,.webp" />
</div>
</div>
</div>
</EditForm>
@code {
[Parameter]
public string? id { get; set; }
public Glas curGlas = null!;
public IBrowserFile? NewImage;
private DbDataContext? _DataContext;
private string PrevPageURL = "/settings/glasses";
EditContext? editContext;
ValidationMessageStore? valMessages;
protected override async Task OnInitializedAsync()
{
if (id != null)
{
_DataContext ??= await DataContextFactory.CreateDbContextAsync();
if (_DataContext != null) curGlas = _DataContext.Glasses.Single(f => f.Id == Convert.ToInt32(id));
}
curGlas ??= new(); // Falls keine ID angegeben wurde oder der Eintrag in der Datenbank nicht gefunden wurde, gehen wir davon aus dass ein neuer Eintrag erstellt wird.
editContext = new(curGlas);
editContext.OnValidationRequested += editContext_OnValidationRequested;
valMessages = new(editContext);
}
private void Bild_OnChange(InputFileChangeEventArgs e)
{
NewImage = e.GetMultipleFiles().FirstOrDefault();
}
private void ModifyAmount(int amount)
{
curGlas.Fuellmenge = Math.Max(curGlas.Fuellmenge + amount, 0);
}
private void editContext_OnValidationRequested(object? sender, ValidationRequestedEventArgs args)
{
valMessages?.Clear();
if (curGlas.Fuellmenge <= 0) valMessages?.Add(() => curGlas.Fuellmenge, "Füllmenge muss größer 0 sein!");
}
private async Task OnSubmit()
{
_DataContext ??= await DataContextFactory.CreateDbContextAsync();
if (curGlas != null && _DataContext != null)
{
if (id != null)
{
_DataContext.Glasses.Update(curGlas);
}
else
{
_DataContext.Glasses.Add(curGlas);
}
await _DataContext.SaveChangesAsync();
if (NewImage != null)
{
try
{
// Bild hochladen
var relativeuploadpath = Path.Join(Config.Value.ImageUploadDir, $"glas_{curGlas.Id}{Path.GetExtension(NewImage.Name)}");
var fullpath = Path.Join(env.WebRootPath, relativeuploadpath);
string? folder = Path.GetDirectoryName(fullpath);
if (folder != null && !Path.Exists(folder)) Directory.CreateDirectory(folder);
Stream stream = NewImage.OpenReadStream(maxAllowedSize: Config.Value.MaxAllowedUploadSizeInMB * 1024 * 1024);
FileStream fs = File.Create(fullpath);
await stream.CopyToAsync(fs);
stream.Close();
fs.Close();
curGlas.ImageURL = relativeuploadpath;
// URL hinterlegen und wieder speichern
_DataContext.Glasses.Update(curGlas);
await _DataContext.SaveChangesAsync();
}
catch (Exception ex)
{
Console.WriteLine($"Error uploading image: {ex.Message}");
}
}
}
nav.NavigateTo(PrevPageURL);
}
}
+90
View File
@@ -0,0 +1,90 @@
@page "/settings/glasses"
@using CocktailWeb.Data
@using Microsoft.AspNetCore.Components.Sections
@using Microsoft.EntityFrameworkCore
@inject IDbContextFactory<DbDataContext> DataContextFactory
<SectionContent SectionId="TopRow.Title">
<label>Einstellungen - Gläser</label>
</SectionContent>
<a class="btn btn-primary mb-3" href="/settings/glasses/edit">Glas hinzufügen</a>
<div class="table-responsive">
<table class="table table-striped table-hover table-bordered table-dark border-dark">
<tbody>
@foreach (Glas g in GlassList)
{
<tr>
<td class="p-0" style="width:64px"><img src="@g.ImageURL" style="max-width:100%; max-height:auto;" /></td>
<td style="vertical-align:middle;">@g.DisplayName</td>
<td style="text-align:right; vertical-align:middle;">
<a class="btn btn-primary" href="/settings/glasses/edit/@g.Id">Bearbeiten</a>
<button name="submit" type="submit" class="btn btn-outline-danger" @onclick="() => ConfirmDeleteAsync(g)">Löschen</button>
</td>
</tr>
}
</tbody>
</table>
</div>
<ModalComponent @ref="modal">
<Title>Löschen bestätigen</Title>
<Body>
Willst du das Glas wirklich löschen?
</Body>
<Footer>
<button class="btn btn-danger" @onclick="DeleteGlassAsync">Jo</button>
<button class="btn btn-primary" @onclick="CloseDialogAsync">Nee</button>
</Footer>
</ModalComponent>
@code {
private List<Glas> GlassList = new();
private DbDataContext? _DataContext;
private ModalComponent modal = null!;
private Glas? SelectedGlas;
protected override async Task OnInitializedAsync()
{
await ShowGlassesAsync();
}
private async Task ShowGlassesAsync()
{
_DataContext ??= await DataContextFactory.CreateDbContextAsync();
if (_DataContext != null)
{
GlassList = _DataContext.Glasses.OrderBy(g => g.Fuellmenge).ToList();
}
}
private async Task ConfirmDeleteAsync(Glas g)
{
SelectedGlas = g;
await modal.ShowAsync();
}
private async Task DeleteGlassAsync()
{
if (SelectedGlas == null) return;
_DataContext ??= await DataContextFactory.CreateDbContextAsync();
if (_DataContext != null)
{
_DataContext.Glasses.Remove(SelectedGlas);
await _DataContext.SaveChangesAsync();
await ShowGlassesAsync();
}
await CloseDialogAsync();
}
private async Task CloseDialogAsync()
{
SelectedGlas = null;
await modal.CloseAsync();
}
}
@@ -0,0 +1,124 @@
@page "/settings/ingredients/edit"
@page "/settings/ingredients/edit/{id}"
@using CocktailWeb.Data
@using Microsoft.AspNetCore.Components.Sections
@using Microsoft.EntityFrameworkCore
@using Microsoft.Extensions.Options
@inject IDbContextFactory<DbDataContext> DataContextFactory;
@inject NavigationManager nav;
@inject IWebHostEnvironment env;
@inject IOptions<GeneralSettings> Config;
<SectionContent SectionId="TopRow.Title">
<label>Zutat bearbeiten</label>
</SectionContent>
<div class="d-flex gap-3">
<div class="border border-2 rounded p-3 w-100">
<div class="mb-3">
<label class="form-label" for="name">Name</label>
<input id="cocktailname" name="name" type="text" class="form-control" @bind="@curFlasche.Name" />
</div>
<div class="form-check mb-3">
<InputCheckbox class="form-check-input" id="IsAlcoholic" @bind-Value=@curFlasche.Alkoholisch>Alkoholisch</InputCheckbox>
<label class="form-check-label" for="IsAlcoholic">
<i class="bi bi-stars text-success"></i>Alkoholisch
</label>
</div>
<button @onclick="OnSubmit" class="btn btn-primary">Speichern</button>
<button @onclick="@(() => nav.NavigateTo("/settings/ingredients"))" class="btn btn-secondary">Abbrechen</button>
</div>
<div class="border border-2 rounded p-3 w-100">
<div class="mb-3">
<label class="form-label" for="image">Bild</label>
<div class="mb-2">
@if (curFlasche.ImageURL != null)
{
<img style="max-width:128px;" src="@curFlasche.ImageURL" />
}
else
{
<div>Kein Bild vorhanden</div>
}
</div>
<label class="form-label" for="image">Neues Bild hochladen</label>
<InputFile OnChange="Bild_OnChange" class="form-control" id="image" name="image" accept=".jpg,.png,.jpeg,.gif,.webp" />
</div>
</div>
</div>
@code {
[Parameter]
public string? id { get; set; }
public Flasche curFlasche = null!;
public IBrowserFile? NewImage;
private DbDataContext? _DataContext;
protected override async Task OnInitializedAsync()
{
if (id != null)
{
_DataContext ??= await DataContextFactory.CreateDbContextAsync();
if (_DataContext != null) curFlasche = _DataContext.Flaschen.Single(f => f.Id == Convert.ToInt32(id));
}
// Falls keine ID angegeben wurde oder der Eintrag in der Datenbank nicht gefunden wurde, gehen wir davon aus dass ein neuer Eintrag erstellt wird.
if (curFlasche == null) curFlasche = new();
//await InvokeAsync(StateHasChanged);
}
public void Bild_OnChange(InputFileChangeEventArgs e)
{
NewImage = e.GetMultipleFiles().FirstOrDefault();
//this.StateHasChanged(); War in nem Stackexchange.. Nötig?
}
private async Task OnSubmit(EventArgs e)
{
_DataContext ??= await DataContextFactory.CreateDbContextAsync();
if (curFlasche != null && _DataContext != null)
{
if (id != null)
{
_DataContext.Flaschen.Update(curFlasche);
}
else
{
_DataContext.Flaschen.Add(curFlasche);
}
await _DataContext.SaveChangesAsync();
if (NewImage != null)
{
try
{
// Bild hochladen
var relativeuploadpath = Path.Join(Config.Value.ImageUploadDir, $"ingredient_{curFlasche.Id}{Path.GetExtension(NewImage.Name)}");
var fullpath = Path.Join(env.WebRootPath, relativeuploadpath);
string? folder = Path.GetDirectoryName(fullpath);
if (folder != null && !Path.Exists(folder)) Directory.CreateDirectory(folder);
Stream stream = NewImage.OpenReadStream(maxAllowedSize: Config.Value.MaxAllowedUploadSizeInMB * 1024 * 1024);
FileStream fs = File.Create(fullpath);
await stream.CopyToAsync(fs);
stream.Close();
fs.Close();
curFlasche.ImageURL = relativeuploadpath;
// URL hinterlegen und wieder speichern
_DataContext.Flaschen.Update(curFlasche);
await _DataContext.SaveChangesAsync();
}
catch (Exception ex)
{
Console.WriteLine($"Error uploading image: {ex.Message}");
}
}
}
nav.NavigateTo("/settings/ingredients");
}
}
@@ -0,0 +1,138 @@
@using Microsoft.AspNetCore.Components.Sections
@using Microsoft.EntityFrameworkCore
@using CocktailWeb.Data
@page "/settings/ingredients"
@inject IDbContextFactory<DbDataContext> FlascheDataContextFactory;
<PageTitle>Zutaten</PageTitle>
<SectionContent SectionId="TopRow.Title">
<label>Einstellungen - Zutaten</label>
</SectionContent>
<a class="btn btn-primary mb-3" href="/settings/ingredients/edit">Neue Zutat</a>
@if (IngredientsList != null && IngredientsList.Count > 0)
{
<div class="table-responsive mt-3">
<table class="table table-striped table-hover table-bordered table-dark border-dark">
<tbody>
@foreach (var fl in IngredientsList)
{
<tr>
<td class="p-0" style="width:64px"><img src="@fl.ImageURL" style="max-width:100%; max-height:auto;" /></td>
<td style="vertical-align:middle;">
@fl.Name
@if (fl.Alkoholisch)
{
<i class="bi bi-stars text-success"></i>
}
</td>
<td style="text-align:right; vertical-align:middle;">
<a class="btn btn-primary" href="/settings/ingredients/edit/@fl.Id">Bearbeiten</a>
<button name="submit" type="submit" class="btn btn-outline-danger" @onclick="() => ConfirmDelete(fl)">Löschen</button>
@*
<a class="btn btn-primary" href="/settings/cocktails/edit/@c.Id">Bearbeiten</a>
<button name="submit" type="submit" class="btn btn-outline-danger" @onclick="() => ConfirmDelete(c)">Löschen</button>
*@
</td>
</tr>
}
</tbody>
</table>
</div>
}
<ModalComponent @ref="dlgDelete">
<Title>Löschen bestätigen</Title>
<Body>
Willst du die Zutat wirklich löschen?<br />
Achtung, die Zutat wird auch aus den Maschineneinstellungen entfernt, falls sie dort verwendet worden sein sollte.
</Body>
<Footer>
<button class="btn btn-danger" @onclick="DeleteIngredient">Jo</button>
<button class="btn btn-primary" @onclick="() => CloseDialog(dlgDelete)">Nee</button>
</Footer>
</ModalComponent>
<ModalComponent @ref="dlgInfo">
<Title>Löschen nicht möglich</Title>
<Body>
Die Zutat kann nicht gelöscht werden, da Sie noch in Cocktails verwendet wird:<br />
@InfoText
</Body>
<Footer>
<button class="btn btn-primary" @onclick="() => CloseDialog(dlgInfo)">OK</button>
</Footer>
</ModalComponent>
@code {
public List<Flasche>? IngredientsList { get; set; }
private DbDataContext? _DataContext;
private Flasche? SelectedIngredient;
private ModalComponent dlgDelete = null!;
private ModalComponent dlgInfo = null!;
private string? InfoText;
protected override async Task OnInitializedAsync()
{
await FillIngredientsList();
}
public async Task FillIngredientsList()
{
_DataContext ??= await FlascheDataContextFactory.CreateDbContextAsync();
if (_DataContext != null)
{
IngredientsList = await _DataContext.Flaschen.OrderBy(f => f.Name).ToListAsync();
}
}
private async Task ConfirmDelete(Flasche fl)
{
_DataContext ??= await FlascheDataContextFactory.CreateDbContextAsync();
if (_DataContext == null) throw new Exception("Error creating DataContext");
var CocktailsWithIngredient = _DataContext.Cocktails.Include(c => c.Cocktailflaschen).Where(cf => cf.Cocktailflaschen.Any(cff => cff.Flasche == fl)).OrderBy(c => c.Name).ToList();
if (CocktailsWithIngredient.Count > 0)
{
InfoText = String.Join(", ", CocktailsWithIngredient.Select(c => c.Name).ToArray());
await dlgInfo.ShowAsync();
}
else
{
SelectedIngredient = fl;
await dlgDelete.ShowAsync();
}
}
public async Task DeleteIngredient()
{
_DataContext ??= await FlascheDataContextFactory.CreateDbContextAsync();
if (_DataContext != null && SelectedIngredient != null)
{
// Zutat aus Maschine rausnehmen (alle Filler, die die Flasche enthalten, auf null setzen)
_DataContext.Fillers.Where(f => f.Flasche == SelectedIngredient)?.ForEachAsync(fil => fil.Flasche = null);
_DataContext.Flaschen.Remove(SelectedIngredient);
await _DataContext.SaveChangesAsync();
await FillIngredientsList();
}
await CloseDialog(dlgDelete);
}
private async Task CloseDialog(ModalComponent dlg)
{
SelectedIngredient = null;
await dlg.CloseAsync();
}
}
@@ -1,4 +1,4 @@
@page "/settings/maschine";
@page "/settings/machine";
@using Microsoft.EntityFrameworkCore
@using CocktailWeb.Data
@using Microsoft.AspNetCore.Components.Sections
@@ -4,7 +4,7 @@ using Microsoft.AspNetCore.Components.Web;
using Microsoft.EntityFrameworkCore;
namespace CocktailWeb.Pages.Settings
{
partial class Maschine
partial class Machine
{
private DbDataContext? _DataContext;
private List<Filler> Fillers { get; set; } = new();
@@ -35,7 +35,7 @@ namespace CocktailWeb.Pages.Settings
{
SelectedFiller = f;
SelectedFlasche = f.Flasche;
await modal.OpenModal();
await modal.ShowAsync();
}
@@ -63,7 +63,7 @@ namespace CocktailWeb.Pages.Settings
{
SelectedFiller = null;
SelectedFlasche = null;
await modal.Close();
await modal.CloseAsync();
}
}
}
+100 -14
View File
@@ -1,4 +1,7 @@
@using Microsoft.AspNetCore.Components.Sections
@using Microsoft.Extensions.Options
@inject IOptions<GeneralSettings> Config
@inject NavigationManager navman
<div class="d-flex align-items-center fixed-top justify-content-between px-4 bg-dark border-primary-subtle" style="border-bottom: 1px solid #d6d5d5; height: 56px; align-items: center; top: 0; z-index: 1;">
<div class="d-flex gap-3 align-items-center">
@@ -10,24 +13,107 @@
<SectionOutlet SectionId="Title" />
</div>
<div class="dropdown show">
<a class="btn btn-secondary dropdown-toggle" role="button" id="dropdownMenuLink" data-bs-toggle="dropdown" aria-expanded="false">
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-gear-fill" viewBox="0 0 16 16">
<path d="M9.405 1.05c-.413-1.4-2.397-1.4-2.81 0l-.1.34a1.464 1.464 0 0 1-2.105.872l-.31-.17c-1.283-.698-2.686.705-1.987 1.987l.169.311c.446.82.023 1.841-.872 2.105l-.34.1c-1.4.413-1.4 2.397 0 2.81l.34.1a1.464 1.464 0 0 1 .872 2.105l-.17.31c-.698 1.283.705 2.686 1.987 1.987l.311-.169a1.464 1.464 0 0 1 2.105.872l.1.34c.413 1.4 2.397 1.4 2.81 0l.1-.34a1.464 1.464 0 0 1 2.105-.872l.31.17c1.283.698 2.686-.705 1.987-1.987l-.169-.311a1.464 1.464 0 0 1 .872-2.105l.34-.1c1.4-.413 1.4-2.397 0-2.81l-.34-.1a1.464 1.464 0 0 1-.872-2.105l.17-.31c.698-1.283-.705-2.686-1.987-1.987l-.311.169a1.464 1.464 0 0 1-2.105-.872zM8 10.93a2.929 2.929 0 1 1 0-5.86 2.929 2.929 0 0 1 0 5.858z" />
</svg>
Einstellungen
</a>
<div class="dropdown-menu dropdown-menu-end" aria-labelledby="dropdownMenuLink">
<a class="dropdown-item" href="/settings/maschine">Maschine</a>
<a class="dropdown-item" href="/settings/flaschen">Zutaten</a>
<a class="dropdown-item" href="/settings/cocktails">Cocktails</a>
<a class="dropdown-item" href="/settings/glaeser">Gläser</a>
<a class="dropdown-item" href="/serialtest">Serial Test</a>
</div>
<div>
@Environment.MachineName:@navman.ToAbsoluteUri(navman.BaseUri).Port
</div>
@* Einstellungen-Dropdown Menü*@
@if (SettingsUnlocked || Config.Value.SettingsPassword == "" || Config.Value.SettingsPassword == null)
{
<div class="dropdown show z-2">
<a class="btn btn-secondary dropdown-toggle z-2" role="button" id="dropdownMenuLink" data-bs-toggle="dropdown" aria-expanded="false">
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-gear-fill" viewBox="0 0 16 16">
<path d="M9.405 1.05c-.413-1.4-2.397-1.4-2.81 0l-.1.34a1.464 1.464 0 0 1-2.105.872l-.31-.17c-1.283-.698-2.686.705-1.987 1.987l.169.311c.446.82.023 1.841-.872 2.105l-.34.1c-1.4.413-1.4 2.397 0 2.81l.34.1a1.464 1.464 0 0 1 .872 2.105l-.17.31c-.698 1.283.705 2.686 1.987 1.987l.311-.169a1.464 1.464 0 0 1 2.105.872l.1.34c.413 1.4 2.397 1.4 2.81 0l.1-.34a1.464 1.464 0 0 1 2.105-.872l.31.17c1.283.698 2.686-.705 1.987-1.987l-.169-.311a1.464 1.464 0 0 1 .872-2.105l.34-.1c1.4-.413 1.4-2.397 0-2.81l-.34-.1a1.464 1.464 0 0 1-.872-2.105l.17-.31c.698-1.283-.705-2.686-1.987-1.987l-.311.169a1.464 1.464 0 0 1-2.105-.872zM8 10.93a2.929 2.929 0 1 1 0-5.86 2.929 2.929 0 0 1 0 5.858z" />
</svg>
Einstellungen
</a>
<div class="dropdown-menu dropdown-menu-end z-2" aria-labelledby="dropdownMenuLink">
<a class="dropdown-item z-3 position-relative" href="/settings/machine">Maschine</a>
<a class="dropdown-item z-3 position-relative" href="/settings/ingredients">Zutaten</a>
<a class="dropdown-item z-3 position-relative" href="/settings/cocktails">Cocktails</a>
<a class="dropdown-item z-3 position-relative" href="/settings/glasses">Gläser</a>
<a class="dropdown-item z-3 position-relative" href="/serialtest">Serial Test</a>
@if (Config.Value.SettingsPassword != "" && Config.Value.SettingsPassword != null)
{
<a class="dropdown-item z-3 position-relative" @onclick=LockSettings>Einstellungen sperren</a>
}
</div>
</div>
}
else
{
<div class="d-flex gap-3 align-items-center">
<a class="btn btn-secondary" @onclick=OpenDialog>
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-lock" viewBox="0 0 16 16">
<path d="M8 1a2 2 0 0 1 2 2v4H6V3a2 2 0 0 1 2-2m3 6V3a3 3 0 0 0-6 0v4a2 2 0 0 0-2 2v5a2 2 0 0 0 2 2h6a2 2 0 0 0 2-2V9a2 2 0 0 0-2-2M5 8h6a1 1 0 0 1 1 1v5a1 1 0 0 1-1 1H5a1 1 0 0 1-1-1V9a1 1 0 0 1 1-1" />
</svg>
Einstellungen
</a>
</div>
}
</div>
<ModalComponent @ref="Pwd_Dialog">
<Title>Passwort eingeben</Title>
<Body>
<label class="form-label" for="settingspassword">Passwort</label>
<input class="form-control" id="settingspassword" name="settingspassword" type="text" @bind=@Pwd_inputPassword />
<label class="text-danger">@Pwd_ErrorText</label>
</Body>
<Footer>
<button type="button" class="btn btn-secondary" @onclick="PasswordDialog_Cancel">Abbrechen</button>
<button type="button" class="btn btn-primary" @onclick="PasswordDialog_OK">OK</button>
</Footer>
</ModalComponent>
@code {
public static SectionOutlet Title = new();
public bool SettingsUnlocked;
ModalComponent Pwd_Dialog = null!;
public string? Pwd_inputPassword;
public string? Pwd_ErrorText;
private async Task PasswordDialog_OK(MouseEventArgs e)
{
if (Pwd_inputPassword == Config.Value.SettingsPassword)
{
SettingsUnlocked = true;
await CloseDialog();
}
else
{
Pwd_inputPassword = null;
Pwd_ErrorText = "Falsches Passwort";
}
}
private void LockSettings()
{
SettingsUnlocked = false;
}
private async Task PasswordDialog_Cancel(MouseEventArgs e)
{
await CloseDialog();
}
private async Task OpenDialog()
{
await Pwd_Dialog.ShowAsync();
}
private async Task CloseDialog()
{
Pwd_ErrorText = null;
Pwd_inputPassword = null;
await Pwd_Dialog.CloseAsync();
}
}
@@ -3,3 +3,6 @@ dotnet ef migrations add <Name>
Datenbank mit aktualisieren mit der neuen Migration:
dotnet ef database update
Update der Tools:
dotnet tool update --global dotnet-ef
Binary file not shown.
+2 -1
View File
@@ -13,6 +13,7 @@
"MaxAllowedUploadSizeInMB": 10,
"ImageUploadDir": "images",
"SerialPort": "COM5",
"Baudrate": 115200
"Baudrate": 115200,
"SettingsPassword": ""
}
}
@@ -0,0 +1,4 @@
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-0-circle-fill" viewBox="0 0 16 16">
<path d="M8 4.951c-1.008 0-1.629 1.09-1.629 2.895v.31c0 1.81.627 2.895 1.629 2.895s1.623-1.09 1.623-2.895v-.31c0-1.8-.621-2.895-1.623-2.895"/>
<path d="M16 8A8 8 0 1 1 0 8a8 8 0 0 1 16 0m-8.012 4.158c1.858 0 2.96-1.582 2.96-3.99V7.84c0-2.426-1.079-3.996-2.936-3.996-1.864 0-2.965 1.588-2.965 3.996v.328c0 2.42 1.09 3.99 2.941 3.99"/>
</svg>

After

Width:  |  Height:  |  Size: 476 B

@@ -0,0 +1,4 @@
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-0-circle" viewBox="0 0 16 16">
<path d="M7.988 12.158c-1.851 0-2.941-1.57-2.941-3.99V7.84c0-2.408 1.101-3.996 2.965-3.996 1.857 0 2.935 1.57 2.935 3.996v.328c0 2.408-1.101 3.99-2.959 3.99M8 4.951c-1.008 0-1.629 1.09-1.629 2.895v.31c0 1.81.627 2.895 1.629 2.895s1.623-1.09 1.623-2.895v-.31c0-1.8-.621-2.895-1.623-2.895"/>
<path d="M16 8A8 8 0 1 1 0 8a8 8 0 0 1 16 0M1 8a7 7 0 1 0 14 0A7 7 0 0 0 1 8"/>
</svg>

After

Width:  |  Height:  |  Size: 507 B

@@ -0,0 +1,4 @@
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-0-square-fill" viewBox="0 0 16 16">
<path d="M8 4.951c-1.008 0-1.629 1.09-1.629 2.895v.31c0 1.81.627 2.895 1.629 2.895s1.623-1.09 1.623-2.895v-.31c0-1.8-.621-2.895-1.623-2.895"/>
<path d="M2 0a2 2 0 0 0-2 2v12a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V2a2 2 0 0 0-2-2zm5.988 12.158c-1.851 0-2.941-1.57-2.941-3.99V7.84c0-2.408 1.101-3.996 2.965-3.996 1.857 0 2.935 1.57 2.935 3.996v.328c0 2.408-1.101 3.99-2.959 3.99"/>
</svg>

After

Width:  |  Height:  |  Size: 514 B

@@ -0,0 +1,4 @@
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-0-square" viewBox="0 0 16 16">
<path d="M7.988 12.158c-1.851 0-2.941-1.57-2.941-3.99V7.84c0-2.408 1.101-3.996 2.965-3.996 1.857 0 2.935 1.57 2.935 3.996v.328c0 2.408-1.101 3.99-2.959 3.99M8 4.951c-1.008 0-1.629 1.09-1.629 2.895v.31c0 1.81.627 2.895 1.629 2.895s1.623-1.09 1.623-2.895v-.31c0-1.8-.621-2.895-1.623-2.895"/>
<path d="M0 2a2 2 0 0 1 2-2h12a2 2 0 0 1 2 2v12a2 2 0 0 1-2 2H2a2 2 0 0 1-2-2zm15 0a1 1 0 0 0-1-1H2a1 1 0 0 0-1 1v12a1 1 0 0 0 1 1h12a1 1 0 0 0 1-1z"/>
</svg>

After

Width:  |  Height:  |  Size: 579 B

@@ -0,0 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-1-circle-fill" viewBox="0 0 16 16">
<path d="M16 8A8 8 0 1 1 0 8a8 8 0 0 1 16 0M9.283 4.002H7.971L6.072 5.385v1.271l1.834-1.318h.065V12h1.312z"/>
</svg>

After

Width:  |  Height:  |  Size: 250 B

@@ -0,0 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-1-circle" viewBox="0 0 16 16">
<path d="M1 8a7 7 0 1 0 14 0A7 7 0 0 0 1 8m15 0A8 8 0 1 1 0 8a8 8 0 0 1 16 0M9.283 4.002V12H7.971V5.338h-.065L6.072 6.656V5.385l1.899-1.383z"/>
</svg>

After

Width:  |  Height:  |  Size: 279 B

@@ -0,0 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-1-square-fill" viewBox="0 0 16 16">
<path d="M2 0a2 2 0 0 0-2 2v12a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V2a2 2 0 0 0-2-2zm7.283 4.002V12H7.971V5.338h-.065L6.072 6.656V5.385l1.899-1.383z"/>
</svg>

After

Width:  |  Height:  |  Size: 286 B

@@ -0,0 +1,4 @@
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-1-square" viewBox="0 0 16 16">
<path d="M9.283 4.002V12H7.971V5.338h-.065L6.072 6.656V5.385l1.899-1.383z"/>
<path d="M0 2a2 2 0 0 1 2-2h12a2 2 0 0 1 2 2v12a2 2 0 0 1-2 2H2a2 2 0 0 1-2-2zm15 0a1 1 0 0 0-1-1H2a1 1 0 0 0-1 1v12a1 1 0 0 0 1 1h12a1 1 0 0 0 1-1z"/>
</svg>

After

Width:  |  Height:  |  Size: 366 B

@@ -0,0 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-123" viewBox="0 0 16 16">
<path d="M2.873 11.297V4.142H1.699L0 5.379v1.137l1.64-1.18h.06v5.961zm3.213-5.09v-.063c0-.618.44-1.169 1.196-1.169.676 0 1.174.44 1.174 1.106 0 .624-.42 1.101-.807 1.526L4.99 10.553v.744h4.78v-.99H6.643v-.069L8.41 8.252c.65-.724 1.237-1.332 1.237-2.27C9.646 4.849 8.723 4 7.308 4c-1.573 0-2.36 1.064-2.36 2.15v.057zm6.559 1.883h.786c.823 0 1.374.481 1.379 1.179.01.707-.55 1.216-1.421 1.21-.77-.005-1.326-.419-1.379-.953h-1.095c.042 1.053.938 1.918 2.464 1.918 1.478 0 2.642-.839 2.62-2.144-.02-1.143-.922-1.651-1.551-1.714v-.063c.535-.09 1.347-.66 1.326-1.678-.026-1.053-.933-1.855-2.359-1.845-1.5.005-2.317.88-2.348 1.898h1.116c.032-.498.498-.944 1.206-.944.703 0 1.206.435 1.206 1.07.005.64-.504 1.106-1.2 1.106h-.75z"/>
</svg>

After

Width:  |  Height:  |  Size: 854 B

@@ -0,0 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-2-circle-fill" viewBox="0 0 16 16">
<path d="M16 8A8 8 0 1 1 0 8a8 8 0 0 1 16 0M6.646 6.24c0-.691.493-1.306 1.336-1.306.756 0 1.313.492 1.313 1.236 0 .697-.469 1.23-.902 1.705l-2.971 3.293V12h5.344v-1.107H7.268v-.077l1.974-2.22.096-.107c.688-.763 1.287-1.428 1.287-2.43 0-1.266-1.031-2.215-2.613-2.215-1.758 0-2.637 1.19-2.637 2.402v.065h1.271v-.07Z"/>
</svg>

After

Width:  |  Height:  |  Size: 457 B

@@ -0,0 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-2-circle" viewBox="0 0 16 16">
<path d="M1 8a7 7 0 1 0 14 0A7 7 0 0 0 1 8m15 0A8 8 0 1 1 0 8a8 8 0 0 1 16 0M6.646 6.24v.07H5.375v-.064c0-1.213.879-2.402 2.637-2.402 1.582 0 2.613.949 2.613 2.215 0 1.002-.6 1.667-1.287 2.43l-.096.107-1.974 2.22v.077h3.498V12H5.422v-.832l2.97-3.293c.434-.475.903-1.008.903-1.705 0-.744-.557-1.236-1.313-1.236-.843 0-1.336.615-1.336 1.306"/>
</svg>

After

Width:  |  Height:  |  Size: 477 B

@@ -0,0 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-2-square-fill" viewBox="0 0 16 16">
<path d="M2 0a2 2 0 0 0-2 2v12a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V2a2 2 0 0 0-2-2zm4.646 6.24v.07H5.375v-.064c0-1.213.879-2.402 2.637-2.402 1.582 0 2.613.949 2.613 2.215 0 1.002-.6 1.667-1.287 2.43l-.096.107-1.974 2.22v.077h3.498V12H5.422v-.832l2.97-3.293c.434-.475.903-1.008.903-1.705 0-.744-.557-1.236-1.313-1.236-.843 0-1.336.615-1.336 1.306"/>
</svg>

After

Width:  |  Height:  |  Size: 484 B

@@ -0,0 +1,4 @@
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-2-square" viewBox="0 0 16 16">
<path d="M6.646 6.24v.07H5.375v-.064c0-1.213.879-2.402 2.637-2.402 1.582 0 2.613.949 2.613 2.215 0 1.002-.6 1.667-1.287 2.43l-.096.107-1.974 2.22v.077h3.498V12H5.422v-.832l2.97-3.293c.434-.475.903-1.008.903-1.705 0-.744-.557-1.236-1.313-1.236-.843 0-1.336.615-1.336 1.306"/>
<path d="M0 2a2 2 0 0 1 2-2h12a2 2 0 0 1 2 2v12a2 2 0 0 1-2 2H2a2 2 0 0 1-2-2zm15 0a1 1 0 0 0-1-1H2a1 1 0 0 0-1 1v12a1 1 0 0 0 1 1h12a1 1 0 0 0 1-1z"/>
</svg>

After

Width:  |  Height:  |  Size: 564 B

@@ -0,0 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-3-circle-fill" viewBox="0 0 16 16">
<path d="M16 8A8 8 0 1 1 0 8a8 8 0 0 1 16 0m-8.082.414c.92 0 1.535.54 1.541 1.318.012.791-.615 1.36-1.588 1.354-.861-.006-1.482-.469-1.54-1.066H5.104c.047 1.177 1.05 2.144 2.754 2.144 1.653 0 2.954-.937 2.93-2.396-.023-1.278-1.031-1.846-1.734-1.916v-.07c.597-.1 1.505-.739 1.482-1.876-.03-1.177-1.043-2.074-2.637-2.062-1.675.006-2.59.984-2.625 2.12h1.248c.036-.556.557-1.054 1.348-1.054.785 0 1.348.486 1.348 1.195.006.715-.563 1.237-1.342 1.237h-.838v1.072h.879Z"/>
</svg>

After

Width:  |  Height:  |  Size: 607 B

@@ -0,0 +1,4 @@
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-3-circle" viewBox="0 0 16 16">
<path d="M7.918 8.414h-.879V7.342h.838c.78 0 1.348-.522 1.342-1.237 0-.709-.563-1.195-1.348-1.195-.79 0-1.312.498-1.348 1.055H5.275c.036-1.137.95-2.115 2.625-2.121 1.594-.012 2.608.885 2.637 2.062.023 1.137-.885 1.776-1.482 1.875v.07c.703.07 1.71.64 1.734 1.917.024 1.459-1.277 2.396-2.93 2.396-1.705 0-2.707-.967-2.754-2.144H6.33c.059.597.68 1.06 1.541 1.066.973.006 1.6-.563 1.588-1.354-.006-.779-.621-1.318-1.541-1.318"/>
<path d="M16 8A8 8 0 1 1 0 8a8 8 0 0 1 16 0M1 8a7 7 0 1 0 14 0A7 7 0 0 0 1 8"/>
</svg>

After

Width:  |  Height:  |  Size: 642 B

@@ -0,0 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-3-square-fill" viewBox="0 0 16 16">
<path d="M2 0a2 2 0 0 0-2 2v12a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V2a2 2 0 0 0-2-2zm5.918 8.414h-.879V7.342h.838c.78 0 1.348-.522 1.342-1.237 0-.709-.563-1.195-1.348-1.195-.79 0-1.312.498-1.348 1.055H5.275c.036-1.137.95-2.115 2.625-2.121 1.594-.012 2.608.885 2.637 2.062.023 1.137-.885 1.776-1.482 1.875v.07c.703.07 1.71.64 1.734 1.917.024 1.459-1.277 2.396-2.93 2.396-1.705 0-2.707-.967-2.754-2.144H6.33c.059.597.68 1.06 1.541 1.066.973.006 1.6-.563 1.588-1.354-.006-.779-.621-1.318-1.541-1.318"/>
</svg>

After

Width:  |  Height:  |  Size: 634 B

@@ -0,0 +1,4 @@
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-3-square" viewBox="0 0 16 16">
<path d="M7.918 8.414h-.879V7.342h.838c.78 0 1.348-.522 1.342-1.237 0-.709-.563-1.195-1.348-1.195-.79 0-1.312.498-1.348 1.055H5.275c.036-1.137.95-2.115 2.625-2.121 1.594-.012 2.608.885 2.637 2.062.023 1.137-.885 1.776-1.482 1.875v.07c.703.07 1.71.64 1.734 1.917.024 1.459-1.277 2.396-2.93 2.396-1.705 0-2.707-.967-2.754-2.144H6.33c.059.597.68 1.06 1.541 1.066.973.006 1.6-.563 1.588-1.354-.006-.779-.621-1.318-1.541-1.318"/>
<path d="M0 2a2 2 0 0 1 2-2h12a2 2 0 0 1 2 2v12a2 2 0 0 1-2 2H2a2 2 0 0 1-2-2zm15 0a1 1 0 0 0-1-1H2a1 1 0 0 0-1 1v12a1 1 0 0 0 1 1h12a1 1 0 0 0 1-1z"/>
</svg>

After

Width:  |  Height:  |  Size: 714 B

@@ -0,0 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-4-circle-fill" viewBox="0 0 16 16">
<path d="M16 8A8 8 0 1 1 0 8a8 8 0 0 1 16 0M7.519 5.057c-.886 1.418-1.772 2.838-2.542 4.265v1.12H8.85V12h1.26v-1.559h1.007V9.334H10.11V4.002H8.176zM6.225 9.281v.053H8.85V5.063h-.065c-.867 1.33-1.787 2.806-2.56 4.218"/>
</svg>

After

Width:  |  Height:  |  Size: 359 B

@@ -0,0 +1,4 @@
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-4-circle" viewBox="0 0 16 16">
<path d="M7.519 5.057q.33-.527.657-1.055h1.933v5.332h1.008v1.107H10.11V12H8.85v-1.559H4.978V9.322c.77-1.427 1.656-2.847 2.542-4.265ZM6.225 9.281v.053H8.85V5.063h-.065c-.867 1.33-1.787 2.806-2.56 4.218"/>
<path d="M16 8A8 8 0 1 1 0 8a8 8 0 0 1 16 0M1 8a7 7 0 1 0 14 0A7 7 0 0 0 1 8"/>
</svg>

After

Width:  |  Height:  |  Size: 421 B

@@ -0,0 +1,4 @@
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-4-square-fill" viewBox="0 0 16 16">
<path d="M6.225 9.281v.053H8.85V5.063h-.065c-.867 1.33-1.787 2.806-2.56 4.218"/>
<path d="M2 0a2 2 0 0 0-2 2v12a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V2a2 2 0 0 0-2-2zm5.519 5.057q.33-.527.657-1.055h1.933v5.332h1.008v1.107H10.11V12H8.85v-1.559H4.978V9.322c.77-1.427 1.656-2.847 2.542-4.265Z"/>
</svg>

After

Width:  |  Height:  |  Size: 428 B

@@ -0,0 +1,4 @@
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-4-square" viewBox="0 0 16 16">
<path d="M7.519 5.057q.33-.527.657-1.055h1.933v5.332h1.008v1.107H10.11V12H8.85v-1.559H4.978V9.322c.77-1.427 1.656-2.847 2.542-4.265ZM6.225 9.281v.053H8.85V5.063h-.065c-.867 1.33-1.787 2.806-2.56 4.218"/>
<path d="M0 2a2 2 0 0 1 2-2h12a2 2 0 0 1 2 2v12a2 2 0 0 1-2 2H2a2 2 0 0 1-2-2zm15 0a1 1 0 0 0-1-1H2a1 1 0 0 0-1 1v12a1 1 0 0 0 1 1h12a1 1 0 0 0 1-1z"/>
</svg>

After

Width:  |  Height:  |  Size: 493 B

@@ -0,0 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-5-circle-fill" viewBox="0 0 16 16">
<path d="M16 8A8 8 0 1 1 0 8a8 8 0 0 1 16 0m-8.006 4.158c1.74 0 2.924-1.119 2.924-2.806 0-1.641-1.178-2.584-2.56-2.584-.897 0-1.442.421-1.612.68h-.064l.193-2.344h3.621V4.002H5.791L5.445 8.63h1.149c.193-.358.668-.809 1.435-.809.85 0 1.582.604 1.582 1.57 0 1.085-.779 1.682-1.57 1.682-.697 0-1.389-.31-1.53-1.031H5.276c.065 1.213 1.149 2.115 2.72 2.115Z"/>
</svg>

After

Width:  |  Height:  |  Size: 495 B

@@ -0,0 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-5-circle" viewBox="0 0 16 16">
<path d="M1 8a7 7 0 1 1 14 0A7 7 0 0 1 1 8m15 0A8 8 0 1 0 0 8a8 8 0 0 0 16 0m-8.006 4.158c-1.57 0-2.654-.902-2.719-2.115h1.237c.14.72.832 1.031 1.529 1.031.791 0 1.57-.597 1.57-1.681 0-.967-.732-1.57-1.582-1.57-.767 0-1.242.45-1.435.808H5.445L5.791 4h4.705v1.103H6.875l-.193 2.343h.064c.17-.258.715-.68 1.611-.68 1.383 0 2.561.944 2.561 2.585 0 1.687-1.184 2.806-2.924 2.806Z"/>
</svg>

After

Width:  |  Height:  |  Size: 514 B

@@ -0,0 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-5-square-fill" viewBox="0 0 16 16">
<path d="M2 0a2 2 0 0 0-2 2v12a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V2a2 2 0 0 0-2-2zm5.994 12.158c-1.57 0-2.654-.902-2.719-2.115h1.237c.14.72.832 1.031 1.529 1.031.791 0 1.57-.597 1.57-1.681 0-.967-.732-1.57-1.582-1.57-.767 0-1.242.45-1.435.808H5.445L5.791 4h4.705v1.103H6.875l-.193 2.343h.064c.17-.258.715-.68 1.611-.68 1.383 0 2.561.944 2.561 2.585 0 1.687-1.184 2.806-2.924 2.806Z"/>
</svg>

After

Width:  |  Height:  |  Size: 521 B

@@ -0,0 +1,4 @@
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-5-square" viewBox="0 0 16 16">
<path d="M7.994 12.158c-1.57 0-2.654-.902-2.719-2.115h1.237c.14.72.832 1.031 1.529 1.031.791 0 1.57-.597 1.57-1.681 0-.967-.732-1.57-1.582-1.57-.767 0-1.242.45-1.435.808H5.445L5.791 4h4.705v1.103H6.875l-.193 2.343h.064c.17-.258.715-.68 1.611-.68 1.383 0 2.561.944 2.561 2.585 0 1.687-1.184 2.806-2.924 2.806Z"/>
<path d="M0 2a2 2 0 0 1 2-2h12a2 2 0 0 1 2 2v12a2 2 0 0 1-2 2H2a2 2 0 0 1-2-2zm15 0a1 1 0 0 0-1-1H2a1 1 0 0 0-1 1v12a1 1 0 0 0 1 1h12a1 1 0 0 0 1-1z"/>
</svg>

After

Width:  |  Height:  |  Size: 601 B

@@ -0,0 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-6-circle-fill" viewBox="0 0 16 16">
<path d="M16 8A8 8 0 1 1 0 8a8 8 0 0 1 16 0M8.21 3.855c-1.868 0-3.116 1.395-3.116 4.407 0 1.183.228 2.039.597 2.642.569.926 1.477 1.254 2.409 1.254 1.629 0 2.847-1.013 2.847-2.783 0-1.676-1.254-2.555-2.508-2.555-1.125 0-1.752.61-1.98 1.155h-.082c-.012-1.946.727-3.036 1.805-3.036.802 0 1.213.457 1.312.815h1.29c-.06-.908-.962-1.899-2.573-1.899Zm-.099 4.008c-.92 0-1.564.65-1.564 1.576 0 1.032.703 1.635 1.558 1.635.868 0 1.553-.533 1.553-1.629 0-1.06-.744-1.582-1.547-1.582"/>
</svg>

After

Width:  |  Height:  |  Size: 617 B

@@ -0,0 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-6-circle" viewBox="0 0 16 16">
<path d="M1 8a7 7 0 1 0 14 0A7 7 0 0 0 1 8m15 0A8 8 0 1 1 0 8a8 8 0 0 1 16 0M8.21 3.855c1.612 0 2.515.99 2.573 1.899H9.494c-.1-.358-.51-.815-1.312-.815-1.078 0-1.817 1.09-1.805 3.036h.082c.229-.545.855-1.155 1.98-1.155 1.254 0 2.508.88 2.508 2.555 0 1.77-1.218 2.783-2.847 2.783-.932 0-1.84-.328-2.409-1.254-.369-.603-.597-1.459-.597-2.642 0-3.012 1.248-4.407 3.117-4.407Zm-.099 4.008c-.92 0-1.564.65-1.564 1.576 0 1.032.703 1.635 1.558 1.635.868 0 1.553-.533 1.553-1.629 0-1.06-.744-1.582-1.547-1.582"/>
</svg>

After

Width:  |  Height:  |  Size: 640 B

@@ -0,0 +1,4 @@
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-6-square-fill" viewBox="0 0 16 16">
<path d="M8.111 7.863c-.92 0-1.564.65-1.564 1.576 0 1.032.703 1.635 1.558 1.635.868 0 1.553-.533 1.553-1.629 0-1.06-.744-1.582-1.547-1.582"/>
<path d="M2 0a2 2 0 0 0-2 2v12a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V2a2 2 0 0 0-2-2zm6.21 3.855c1.612 0 2.515.99 2.573 1.899H9.494c-.1-.358-.51-.815-1.312-.815-1.078 0-1.817 1.09-1.805 3.036h.082c.229-.545.855-1.155 1.98-1.155 1.254 0 2.508.88 2.508 2.555 0 1.77-1.218 2.783-2.847 2.783-.932 0-1.84-.328-2.409-1.254-.369-.603-.597-1.459-.597-2.642 0-3.012 1.248-4.407 3.117-4.407Z"/>
</svg>

After

Width:  |  Height:  |  Size: 662 B

@@ -0,0 +1,4 @@
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-6-square" viewBox="0 0 16 16">
<path d="M8.21 3.855c1.612 0 2.515.99 2.573 1.899H9.494c-.1-.358-.51-.815-1.312-.815-1.078 0-1.817 1.09-1.805 3.036h.082c.229-.545.855-1.155 1.98-1.155 1.254 0 2.508.88 2.508 2.555 0 1.77-1.218 2.783-2.847 2.783-.932 0-1.84-.328-2.409-1.254-.369-.603-.597-1.459-.597-2.642 0-3.012 1.248-4.407 3.117-4.407Zm-.099 4.008c-.92 0-1.564.65-1.564 1.576 0 1.032.703 1.635 1.558 1.635.868 0 1.553-.533 1.553-1.629 0-1.06-.744-1.582-1.547-1.582"/>
<path d="M0 2a2 2 0 0 1 2-2h12a2 2 0 0 1 2 2v12a2 2 0 0 1-2 2H2a2 2 0 0 1-2-2zm15 0a1 1 0 0 0-1-1H2a1 1 0 0 0-1 1v12a1 1 0 0 0 1 1h12a1 1 0 0 0 1-1z"/>
</svg>

After

Width:  |  Height:  |  Size: 727 B

@@ -0,0 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-7-circle-fill" viewBox="0 0 16 16">
<path d="M16 8A8 8 0 1 1 0 8a8 8 0 0 1 16 0M5.37 5.11h3.972v.07L6.025 12H7.42l3.258-6.85V4.002H5.369v1.107Z"/>
</svg>

After

Width:  |  Height:  |  Size: 251 B

@@ -0,0 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-7-circle" viewBox="0 0 16 16">
<path d="M1 8a7 7 0 1 0 14 0A7 7 0 0 0 1 8m15 0A8 8 0 1 1 0 8a8 8 0 0 1 16 0M5.37 5.11V4.001h5.308V5.15L7.42 12H6.025l3.317-6.82v-.07H5.369Z"/>
</svg>

After

Width:  |  Height:  |  Size: 279 B

@@ -0,0 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-7-square-fill" viewBox="0 0 16 16">
<path d="M2 0a2 2 0 0 0-2 2v12a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V2a2 2 0 0 0-2-2zm3.37 5.11V4.001h5.308V5.15L7.42 12H6.025l3.317-6.82v-.07H5.369Z"/>
</svg>

After

Width:  |  Height:  |  Size: 286 B

@@ -0,0 +1,4 @@
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-7-square" viewBox="0 0 16 16">
<path d="M5.37 5.11V4.001h5.308V5.15L7.42 12H6.025l3.317-6.82v-.07H5.369Z"/>
<path d="M0 2a2 2 0 0 1 2-2h12a2 2 0 0 1 2 2v12a2 2 0 0 1-2 2H2a2 2 0 0 1-2-2zm15 0a1 1 0 0 0-1-1H2a1 1 0 0 0-1 1v12a1 1 0 0 0 1 1h12a1 1 0 0 0 1-1z"/>
</svg>

After

Width:  |  Height:  |  Size: 366 B

@@ -0,0 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-8-circle-fill" viewBox="0 0 16 16">
<path d="M16 8A8 8 0 1 1 0 8a8 8 0 0 1 16 0m-5.03 1.803c0-1.248-.943-1.84-1.646-1.992v-.065c.598-.187 1.336-.72 1.336-1.781 0-1.225-1.084-2.121-2.654-2.121s-2.66.896-2.66 2.12c0 1.044.709 1.589 1.33 1.782v.065c-.697.152-1.647.732-1.647 2.003 0 1.39 1.19 2.344 2.953 2.344 1.77 0 2.989-.96 2.989-2.355Zm-4.347-3.71c0 .739.586 1.255 1.383 1.255s1.377-.516 1.377-1.254c0-.733-.58-1.23-1.377-1.23s-1.383.497-1.383 1.23Zm-.281 3.645c0 .838.72 1.412 1.664 1.412.943 0 1.658-.574 1.658-1.412 0-.843-.715-1.424-1.658-1.424-.944 0-1.664.58-1.664 1.424"/>
</svg>

After

Width:  |  Height:  |  Size: 686 B

@@ -0,0 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-8-circle" viewBox="0 0 16 16">
<path d="M1 8a7 7 0 1 0 14 0A7 7 0 0 0 1 8m15 0A8 8 0 1 1 0 8a8 8 0 0 1 16 0m-5.03 1.803c0 1.394-1.218 2.355-2.988 2.355-1.763 0-2.953-.955-2.953-2.344 0-1.271.95-1.851 1.647-2.003v-.065c-.621-.193-1.33-.738-1.33-1.781 0-1.225 1.09-2.121 2.66-2.121s2.654.896 2.654 2.12c0 1.061-.738 1.595-1.336 1.782v.065c.703.152 1.647.744 1.647 1.992Zm-4.347-3.71c0 .739.586 1.255 1.383 1.255s1.377-.516 1.377-1.254c0-.733-.58-1.23-1.377-1.23s-1.383.497-1.383 1.23Zm-.281 3.645c0 .838.72 1.412 1.664 1.412.943 0 1.658-.574 1.658-1.412 0-.843-.715-1.424-1.658-1.424-.944 0-1.664.58-1.664 1.424"/>
</svg>

After

Width:  |  Height:  |  Size: 717 B

@@ -0,0 +1,4 @@
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-8-square-fill" viewBox="0 0 16 16">
<path d="M6.623 6.094c0 .738.586 1.254 1.383 1.254s1.377-.516 1.377-1.254c0-.733-.58-1.23-1.377-1.23s-1.383.497-1.383 1.23m-.281 3.644c0 .838.72 1.412 1.664 1.412.943 0 1.658-.574 1.658-1.412 0-.843-.715-1.424-1.658-1.424-.944 0-1.664.58-1.664 1.424"/>
<path d="M2 0a2 2 0 0 0-2 2v12a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V2a2 2 0 0 0-2-2zm8.97 9.803c0 1.394-1.218 2.355-2.988 2.355-1.763 0-2.953-.955-2.953-2.344 0-1.271.95-1.851 1.647-2.003v-.065c-.621-.193-1.33-.738-1.33-1.781 0-1.225 1.09-2.121 2.66-2.121s2.654.896 2.654 2.12c0 1.061-.738 1.595-1.336 1.782v.065c.703.152 1.647.744 1.647 1.992Z"/>
</svg>

After

Width:  |  Height:  |  Size: 737 B

@@ -0,0 +1,4 @@
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-8-square" viewBox="0 0 16 16">
<path d="M10.97 9.803c0 1.394-1.218 2.355-2.988 2.355-1.763 0-2.953-.955-2.953-2.344 0-1.271.95-1.851 1.647-2.003v-.065c-.621-.193-1.33-.738-1.33-1.781 0-1.225 1.09-2.121 2.66-2.121s2.654.896 2.654 2.12c0 1.061-.738 1.595-1.336 1.782v.065c.703.152 1.647.744 1.647 1.992Zm-4.347-3.71c0 .739.586 1.255 1.383 1.255s1.377-.516 1.377-1.254c0-.733-.58-1.23-1.377-1.23s-1.383.497-1.383 1.23Zm-.281 3.645c0 .838.72 1.412 1.664 1.412.943 0 1.658-.574 1.658-1.412 0-.843-.715-1.424-1.658-1.424-.944 0-1.664.58-1.664 1.424"/>
<path d="M0 2a2 2 0 0 1 2-2h12a2 2 0 0 1 2 2v12a2 2 0 0 1-2 2H2a2 2 0 0 1-2-2zm15 0a1 1 0 0 0-1-1H2a1 1 0 0 0-1 1v12a1 1 0 0 0 1 1h12a1 1 0 0 0 1-1z"/>
</svg>

After

Width:  |  Height:  |  Size: 804 B

@@ -0,0 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-9-circle-fill" viewBox="0 0 16 16">
<path d="M16 8A8 8 0 1 1 0 8a8 8 0 0 1 16 0m-8.223 4.146c2.104 0 3.123-1.464 3.123-4.3 0-3.147-1.459-4.014-2.97-4.014-1.63 0-2.871 1.02-2.871 2.73 0 1.706 1.171 2.667 2.566 2.667 1.06 0 1.7-.557 1.934-1.184h.076c.047 1.67-.475 3.023-1.834 3.023-.71 0-1.149-.363-1.248-.72H5.258c.094.908.926 1.798 2.52 1.798Zm.118-3.972c.808 0 1.535-.528 1.535-1.594s-.668-1.676-1.56-1.676c-.838 0-1.517.616-1.517 1.659 0 1.072.708 1.61 1.54 1.61Z"/>
</svg>

After

Width:  |  Height:  |  Size: 574 B

@@ -0,0 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-9-circle" viewBox="0 0 16 16">
<path d="M1 8a7 7 0 1 0 14 0A7 7 0 0 0 1 8m15 0A8 8 0 1 1 0 8a8 8 0 0 1 16 0m-8.223 4.146c-1.593 0-2.425-.89-2.52-1.798h1.296c.1.357.539.72 1.248.72 1.36 0 1.88-1.353 1.834-3.023h-.076c-.235.627-.873 1.184-1.934 1.184-1.395 0-2.566-.961-2.566-2.666 0-1.711 1.242-2.731 2.87-2.731 1.512 0 2.971.867 2.971 4.014 0 2.836-1.02 4.3-3.123 4.3m.118-3.972c.808 0 1.535-.528 1.535-1.594s-.668-1.676-1.56-1.676c-.838 0-1.517.616-1.517 1.659 0 1.072.708 1.61 1.54 1.61Z"/>
</svg>

After

Width:  |  Height:  |  Size: 597 B

@@ -0,0 +1,4 @@
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-9-square-fill" viewBox="0 0 16 16">
<path d="M7.895 8.174c.808 0 1.535-.528 1.535-1.594s-.668-1.676-1.56-1.676c-.838 0-1.517.616-1.517 1.659 0 1.072.708 1.61 1.54 1.61Z"/>
<path d="M2 0a2 2 0 0 0-2 2v12a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V2a2 2 0 0 0-2-2zm5.777 12.146c-1.593 0-2.425-.89-2.52-1.798h1.296c.1.357.539.72 1.248.72 1.36 0 1.88-1.353 1.834-3.023h-.076c-.235.627-.873 1.184-1.934 1.184-1.395 0-2.566-.961-2.566-2.666 0-1.711 1.242-2.731 2.87-2.731 1.512 0 2.971.867 2.971 4.014 0 2.836-1.02 4.3-3.123 4.3"/>
</svg>

After

Width:  |  Height:  |  Size: 620 B

@@ -0,0 +1,4 @@
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-9-square" viewBox="0 0 16 16">
<path d="M7.777 12.146c-1.593 0-2.425-.89-2.52-1.798h1.296c.1.357.539.72 1.248.72 1.36 0 1.88-1.353 1.834-3.023h-.076c-.235.627-.873 1.184-1.934 1.184-1.395 0-2.566-.961-2.566-2.666 0-1.711 1.242-2.731 2.87-2.731 1.512 0 2.971.867 2.971 4.014 0 2.836-1.02 4.3-3.123 4.3m.118-3.972c.808 0 1.535-.528 1.535-1.594s-.668-1.676-1.56-1.676c-.838 0-1.517.616-1.517 1.659 0 1.072.708 1.61 1.54 1.61Z"/>
<path d="M0 2a2 2 0 0 1 2-2h12a2 2 0 0 1 2 2v12a2 2 0 0 1-2 2H2a2 2 0 0 1-2-2zm15 0a1 1 0 0 0-1-1H2a1 1 0 0 0-1 1v12a1 1 0 0 0 1 1h12a1 1 0 0 0 1-1z"/>
</svg>

After

Width:  |  Height:  |  Size: 684 B

@@ -0,0 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-activity" viewBox="0 0 16 16">
<path fill-rule="evenodd" d="M6 2a.5.5 0 0 1 .47.33L10 12.036l1.53-4.208A.5.5 0 0 1 12 7.5h3.5a.5.5 0 0 1 0 1h-3.15l-1.88 5.17a.5.5 0 0 1-.94 0L6 3.964 4.47 8.171A.5.5 0 0 1 4 8.5H.5a.5.5 0 0 1 0-1h3.15l1.88-5.17A.5.5 0 0 1 6 2"/>
</svg>

After

Width:  |  Height:  |  Size: 366 B

@@ -0,0 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-airplane-engines-fill" viewBox="0 0 16 16">
<path d="M8 0c-.787 0-1.292.592-1.572 1.151A4.35 4.35 0 0 0 6 3v3.691l-2 1V7.5a.5.5 0 0 0-.5-.5h-1a.5.5 0 0 0-.5.5v1.191l-1.17.585A1.5 1.5 0 0 0 0 10.618V12a.5.5 0 0 0 .582.493l1.631-.272.313.937a.5.5 0 0 0 .948 0l.405-1.214 2.21-.369.375 2.253-1.318 1.318A.5.5 0 0 0 5.5 16h5a.5.5 0 0 0 .354-.854l-1.318-1.318.375-2.253 2.21.369.405 1.214a.5.5 0 0 0 .948 0l.313-.937 1.63.272A.5.5 0 0 0 16 12v-1.382a1.5 1.5 0 0 0-.83-1.342L14 8.691V7.5a.5.5 0 0 0-.5-.5h-1a.5.5 0 0 0-.5.5v.191l-2-1V3c0-.568-.14-1.271-.428-1.849C9.292.591 8.787 0 8 0"/>
</svg>

After

Width:  |  Height:  |  Size: 687 B

@@ -0,0 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-airplane-engines" viewBox="0 0 16 16">
<path d="M8 0c-.787 0-1.292.592-1.572 1.151A4.35 4.35 0 0 0 6 3v3.691l-2 1V7.5a.5.5 0 0 0-.5-.5h-1a.5.5 0 0 0-.5.5v1.191l-1.17.585A1.5 1.5 0 0 0 0 10.618V12a.5.5 0 0 0 .582.493l1.631-.272.313.937a.5.5 0 0 0 .948 0l.405-1.214 2.21-.369.375 2.253-1.318 1.318A.5.5 0 0 0 5.5 16h5a.5.5 0 0 0 .354-.854l-1.318-1.318.375-2.253 2.21.369.405 1.214a.5.5 0 0 0 .948 0l.313-.937 1.63.272A.5.5 0 0 0 16 12v-1.382a1.5 1.5 0 0 0-.83-1.342L14 8.691V7.5a.5.5 0 0 0-.5-.5h-1a.5.5 0 0 0-.5.5v.191l-2-1V3c0-.568-.14-1.271-.428-1.849C9.292.591 8.787 0 8 0M7 3c0-.432.11-.979.322-1.401C7.542 1.159 7.787 1 8 1s.458.158.678.599C8.889 2.02 9 2.569 9 3v4a.5.5 0 0 0 .276.447l5.448 2.724a.5.5 0 0 1 .276.447v.792l-5.418-.903a.5.5 0 0 0-.575.41l-.5 3a.5.5 0 0 0 .14.437l.646.646H6.707l.647-.646a.5.5 0 0 0 .14-.436l-.5-3a.5.5 0 0 0-.576-.411L1 11.41v-.792a.5.5 0 0 1 .276-.447l5.448-2.724A.5.5 0 0 0 7 7z"/>
</svg>

After

Width:  |  Height:  |  Size: 1.0 KiB

@@ -0,0 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-airplane-fill" viewBox="0 0 16 16">
<path d="M6.428 1.151C6.708.591 7.213 0 8 0s1.292.592 1.572 1.151C9.861 1.73 10 2.431 10 3v3.691l5.17 2.585a1.5 1.5 0 0 1 .83 1.342V12a.5.5 0 0 1-.582.493l-5.507-.918-.375 2.253 1.318 1.318A.5.5 0 0 1 10.5 16h-5a.5.5 0 0 1-.354-.854l1.319-1.318-.376-2.253-5.507.918A.5.5 0 0 1 0 12v-1.382a1.5 1.5 0 0 1 .83-1.342L6 6.691V3c0-.568.14-1.271.428-1.849"/>
</svg>

After

Width:  |  Height:  |  Size: 492 B

@@ -0,0 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-airplane" viewBox="0 0 16 16">
<path d="M6.428 1.151C6.708.591 7.213 0 8 0s1.292.592 1.572 1.151C9.861 1.73 10 2.431 10 3v3.691l5.17 2.585a1.5 1.5 0 0 1 .83 1.342V12a.5.5 0 0 1-.582.493l-5.507-.918-.375 2.253 1.318 1.318A.5.5 0 0 1 10.5 16h-5a.5.5 0 0 1-.354-.854l1.319-1.318-.376-2.253-5.507.918A.5.5 0 0 1 0 12v-1.382a1.5 1.5 0 0 1 .83-1.342L6 6.691V3c0-.568.14-1.271.428-1.849m.894.448C7.111 2.02 7 2.569 7 3v4a.5.5 0 0 1-.276.447l-5.448 2.724a.5.5 0 0 0-.276.447v.792l5.418-.903a.5.5 0 0 1 .575.41l.5 3a.5.5 0 0 1-.14.437L6.708 15h2.586l-.647-.646a.5.5 0 0 1-.14-.436l.5-3a.5.5 0 0 1 .576-.411L15 11.41v-.792a.5.5 0 0 0-.276-.447L9.276 7.447A.5.5 0 0 1 9 7V3c0-.432-.11-.979-.322-1.401C8.458 1.159 8.213 1 8 1s-.458.158-.678.599"/>
</svg>

After

Width:  |  Height:  |  Size: 840 B

@@ -0,0 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-alarm-fill" viewBox="0 0 16 16">
<path d="M6 .5a.5.5 0 0 1 .5-.5h3a.5.5 0 0 1 0 1H9v1.07a7.001 7.001 0 0 1 3.274 12.474l.601.602a.5.5 0 0 1-.707.708l-.746-.746A6.97 6.97 0 0 1 8 16a6.97 6.97 0 0 1-3.422-.892l-.746.746a.5.5 0 0 1-.707-.708l.602-.602A7.001 7.001 0 0 1 7 2.07V1h-.5A.5.5 0 0 1 6 .5m2.5 5a.5.5 0 0 0-1 0v3.362l-1.429 2.38a.5.5 0 1 0 .858.515l1.5-2.5A.5.5 0 0 0 8.5 9zM.86 5.387A2.5 2.5 0 1 1 4.387 1.86 8.04 8.04 0 0 0 .86 5.387M11.613 1.86a2.5 2.5 0 1 1 3.527 3.527 8.04 8.04 0 0 0-3.527-3.527"/>
</svg>

After

Width:  |  Height:  |  Size: 615 B

@@ -0,0 +1,4 @@
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-alarm" viewBox="0 0 16 16">
<path d="M8.5 5.5a.5.5 0 0 0-1 0v3.362l-1.429 2.38a.5.5 0 1 0 .858.515l1.5-2.5A.5.5 0 0 0 8.5 9z"/>
<path d="M6.5 0a.5.5 0 0 0 0 1H7v1.07a7.001 7.001 0 0 0-3.273 12.474l-.602.602a.5.5 0 0 0 .707.708l.746-.746A6.97 6.97 0 0 0 8 16a6.97 6.97 0 0 0 3.422-.892l.746.746a.5.5 0 0 0 .707-.708l-.601-.602A7.001 7.001 0 0 0 9 2.07V1h.5a.5.5 0 0 0 0-1zm1.038 3.018a6 6 0 0 1 .924 0 6 6 0 1 1-.924 0M0 3.5c0 .753.333 1.429.86 1.887A8.04 8.04 0 0 1 4.387 1.86 2.5 2.5 0 0 0 0 3.5M13.5 1c-.753 0-1.429.333-1.887.86a8.04 8.04 0 0 1 3.527 3.527A2.5 2.5 0 0 0 13.5 1"/>
</svg>

After

Width:  |  Height:  |  Size: 689 B

@@ -0,0 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-alexa" viewBox="0 0 16 16">
<path d="M7.996 0A8 8 0 0 0 0 8a8 8 0 0 0 6.93 7.93v-1.613a1.06 1.06 0 0 0-.717-1.008A5.6 5.6 0 0 1 2.4 7.865 5.58 5.58 0 0 1 8.054 2.4a5.6 5.6 0 0 1 5.535 5.81l-.002.046-.012.192-.005.061a5 5 0 0 1-.033.284l-.01.068c-.685 4.516-6.564 7.054-6.596 7.068A7.998 7.998 0 0 0 15.992 8 8 8 0 0 0 7.996.001Z"/>
</svg>

After

Width:  |  Height:  |  Size: 436 B

@@ -0,0 +1,4 @@
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-align-bottom" viewBox="0 0 16 16">
<rect width="4" height="12" x="6" y="1" rx="1"/>
<path d="M1.5 14a.5.5 0 0 0 0 1zm13 1a.5.5 0 0 0 0-1zm-13 0h13v-1h-13z"/>
</svg>

After

Width:  |  Height:  |  Size: 264 B

@@ -0,0 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-align-center" viewBox="0 0 16 16">
<path d="M8 1a.5.5 0 0 1 .5.5V6h-1V1.5A.5.5 0 0 1 8 1m0 14a.5.5 0 0 1-.5-.5V10h1v4.5a.5.5 0 0 1-.5.5M2 7a1 1 0 0 1 1-1h10a1 1 0 0 1 1 1v2a1 1 0 0 1-1 1H3a1 1 0 0 1-1-1z"/>
</svg>

After

Width:  |  Height:  |  Size: 311 B

@@ -0,0 +1,4 @@
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-align-end" viewBox="0 0 16 16">
<path fill-rule="evenodd" d="M14.5 1a.5.5 0 0 0-.5.5v13a.5.5 0 0 0 1 0v-13a.5.5 0 0 0-.5-.5"/>
<path d="M13 7a1 1 0 0 0-1-1H2a1 1 0 0 0-1 1v2a1 1 0 0 0 1 1h10a1 1 0 0 0 1-1z"/>
</svg>

After

Width:  |  Height:  |  Size: 315 B

@@ -0,0 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-align-middle" viewBox="0 0 16 16">
<path d="M6 13a1 1 0 0 0 1 1h2a1 1 0 0 0 1-1V3a1 1 0 0 0-1-1H7a1 1 0 0 0-1 1zM1 8a.5.5 0 0 0 .5.5H6v-1H1.5A.5.5 0 0 0 1 8m14 0a.5.5 0 0 1-.5.5H10v-1h4.5a.5.5 0 0 1 .5.5"/>
</svg>

After

Width:  |  Height:  |  Size: 311 B

@@ -0,0 +1,4 @@
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-align-start" viewBox="0 0 16 16">
<path fill-rule="evenodd" d="M1.5 1a.5.5 0 0 1 .5.5v13a.5.5 0 0 1-1 0v-13a.5.5 0 0 1 .5-.5"/>
<path d="M3 7a1 1 0 0 1 1-1h10a1 1 0 0 1 1 1v2a1 1 0 0 1-1 1H4a1 1 0 0 1-1-1z"/>
</svg>

After

Width:  |  Height:  |  Size: 315 B

@@ -0,0 +1,4 @@
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-align-top" viewBox="0 0 16 16">
<rect width="4" height="12" rx="1" transform="matrix(1 0 0 -1 6 15)"/>
<path d="M1.5 2a.5.5 0 0 1 0-1zm13-1a.5.5 0 0 1 0 1zm-13 0h13v1h-13z"/>
</svg>

After

Width:  |  Height:  |  Size: 281 B

@@ -0,0 +1,4 @@
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-alipay" viewBox="0 0 16 16">
<path d="M2.541 0H13.5a2.55 2.55 0 0 1 2.54 2.563v8.297c-.006 0-.531-.046-2.978-.813-.412-.14-.916-.327-1.479-.536q-.456-.17-.957-.353a13 13 0 0 0 1.325-3.373H8.822V4.649h3.831v-.634h-3.83V2.121H7.26c-.274 0-.274.273-.274.273v1.621H3.11v.634h3.875v1.136h-3.2v.634H9.99c-.227.789-.532 1.53-.894 2.202-2.013-.67-4.161-1.212-5.51-.878-.864.214-1.42.597-1.746.998-1.499 1.84-.424 4.633 2.741 4.633 1.872 0 3.675-1.053 5.072-2.787 2.08 1.008 6.37 2.738 6.387 2.745v.105A2.55 2.55 0 0 1 13.5 16H2.541A2.55 2.55 0 0 1 0 13.437V2.563A2.55 2.55 0 0 1 2.541 0"/>
<path d="M2.309 9.27c-1.22 1.073-.49 3.034 1.978 3.034 1.434 0 2.868-.925 3.994-2.406-1.602-.789-2.959-1.353-4.425-1.207-.397.04-1.14.217-1.547.58Z"/>
</svg>

After

Width:  |  Height:  |  Size: 839 B

@@ -0,0 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-alphabet-uppercase" viewBox="0 0 16 16">
<path d="M1.226 10.88H0l2.056-6.26h1.42l2.047 6.26h-1.29l-.48-1.61H1.707l-.48 1.61ZM2.76 5.818h-.054l-.75 2.532H3.51zm3.217 5.062V4.62h2.56c1.09 0 1.808.582 1.808 1.54 0 .762-.444 1.22-1.05 1.372v.055c.736.074 1.365.587 1.365 1.528 0 1.119-.89 1.766-2.133 1.766zM7.18 5.55v1.675h.8c.812 0 1.171-.308 1.171-.853 0-.51-.328-.822-.898-.822zm0 2.537V9.95h.903c.951 0 1.342-.312 1.342-.909 0-.591-.382-.954-1.095-.954zm5.089-.711v.775c0 1.156.49 1.803 1.347 1.803.705 0 1.163-.454 1.212-1.096H16v.12C15.942 10.173 14.95 11 13.607 11c-1.648 0-2.573-1.073-2.573-2.849v-.78c0-1.775.934-2.871 2.573-2.871 1.347 0 2.34.849 2.393 2.087v.115h-1.172c-.05-.665-.516-1.156-1.212-1.156-.849 0-1.347.67-1.347 1.83"/>
</svg>

After

Width:  |  Height:  |  Size: 845 B

@@ -0,0 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-alphabet" viewBox="0 0 16 16">
<path d="M2.204 11.078c.767 0 1.201-.356 1.406-.737h.059V11h1.216V7.519c0-1.314-.947-1.783-2.11-1.783C1.355 5.736.75 6.42.69 7.27h1.216c.064-.323.313-.552.84-.552s.864.249.864.771v.464H2.346C1.145 7.953.5 8.568.5 9.496c0 .977.693 1.582 1.704 1.582m.42-.947c-.44 0-.845-.235-.845-.718 0-.395.269-.684.84-.684h.991v.538c0 .503-.444.864-.986.864m5.593.937c1.216 0 1.948-.869 1.948-2.31v-.702c0-1.44-.727-2.305-1.929-2.305-.742 0-1.328.347-1.499.889h-.063V3.983h-1.29V11h1.27v-.791h.064c.21.532.776.86 1.499.86Zm-.43-1.025c-.66 0-1.113-.518-1.113-1.28V8.12c0-.825.42-1.343 1.098-1.343.684 0 1.075.518 1.075 1.416v.45c0 .888-.386 1.401-1.06 1.401Zm2.834-1.328c0 1.47.87 2.378 2.305 2.378 1.416 0 2.139-.777 2.158-1.763h-1.186c-.06.425-.313.732-.933.732-.66 0-1.05-.512-1.05-1.352v-.625c0-.81.371-1.328 1.045-1.328.635 0 .879.425.918.776h1.187c-.02-.986-.787-1.806-2.14-1.806-1.41 0-2.304.918-2.304 2.338z"/>
</svg>

After

Width:  |  Height:  |  Size: 1.0 KiB

@@ -0,0 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-alt" viewBox="0 0 16 16">
<path d="M1 13.5a.5.5 0 0 0 .5.5h3.797a.5.5 0 0 0 .439-.26L11 3h3.5a.5.5 0 0 0 0-1h-3.797a.5.5 0 0 0-.439.26L5 13H1.5a.5.5 0 0 0-.5.5m10 0a.5.5 0 0 0 .5.5h3a.5.5 0 0 0 0-1h-3a.5.5 0 0 0-.5.5"/>
</svg>

After

Width:  |  Height:  |  Size: 324 B

@@ -0,0 +1,4 @@
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-amazon" viewBox="0 0 16 16">
<path d="M10.813 11.968c.157.083.36.074.5-.05l.005.005a90 90 0 0 1 1.623-1.405c.173-.143.143-.372.006-.563l-.125-.17c-.345-.465-.673-.906-.673-1.791v-3.3l.001-.335c.008-1.265.014-2.421-.933-3.305C10.404.274 9.06 0 8.03 0 6.017 0 3.77.75 3.296 3.24c-.047.264.143.404.316.443l2.054.22c.19-.009.33-.196.366-.387.176-.857.896-1.271 1.703-1.271.435 0 .929.16 1.188.55.264.39.26.91.257 1.376v.432q-.3.033-.621.065c-1.113.114-2.397.246-3.36.67C3.873 5.91 2.94 7.08 2.94 8.798c0 2.2 1.387 3.298 3.168 3.298 1.506 0 2.328-.354 3.489-1.54l.167.246c.274.405.456.675 1.047 1.166ZM6.03 8.431C6.03 6.627 7.647 6.3 9.177 6.3v.57c.001.776.002 1.434-.396 2.133-.336.595-.87.961-1.465.961-.812 0-1.286-.619-1.286-1.533M.435 12.174c2.629 1.603 6.698 4.084 13.183.997.28-.116.475.078.199.431C13.538 13.96 11.312 16 7.57 16 3.832 16 .968 13.446.094 12.386c-.24-.275.036-.4.199-.299z"/>
<path d="M13.828 11.943c.567-.07 1.468-.027 1.645.204.135.176-.004.966-.233 1.533-.23.563-.572.961-.762 1.115s-.333.094-.23-.137c.105-.23.684-1.663.455-1.963-.213-.278-1.177-.177-1.625-.13l-.09.009q-.142.013-.233.024c-.193.021-.245.027-.274-.032-.074-.209.779-.556 1.347-.623"/>
</svg>

After

Width:  |  Height:  |  Size: 1.2 KiB

@@ -0,0 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-amd" viewBox="0 0 16 16">
<path d="m.334 0 4.358 4.359h7.15v7.15l4.358 4.358V0zM.2 9.72l4.487-4.488v6.281h6.28L6.48 16H.2z"/>
</svg>

After

Width:  |  Height:  |  Size: 230 B

@@ -0,0 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-android" viewBox="0 0 16 16">
<path d="M2.76 3.061a.5.5 0 0 1 .679.2l1.283 2.352A8.9 8.9 0 0 1 8 5a8.9 8.9 0 0 1 3.278.613l1.283-2.352a.5.5 0 1 1 .878.478l-1.252 2.295C14.475 7.266 16 9.477 16 12H0c0-2.523 1.525-4.734 3.813-5.966L2.56 3.74a.5.5 0 0 1 .2-.678ZM5 10a1 1 0 1 0 0-2 1 1 0 0 0 0 2m6 0a1 1 0 1 0 0-2 1 1 0 0 0 0 2"/>
</svg>

After

Width:  |  Height:  |  Size: 432 B

@@ -0,0 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-android2" viewBox="0 0 16 16">
<path d="m10.213 1.471.691-1.26q.069-.124-.048-.192-.128-.057-.195.058l-.7 1.27A4.8 4.8 0 0 0 8.005.941q-1.032 0-1.956.404l-.7-1.27Q5.281-.037 5.154.02q-.117.069-.049.193l.691 1.259a4.25 4.25 0 0 0-1.673 1.476A3.7 3.7 0 0 0 3.5 5.02h9q0-1.125-.623-2.072a4.27 4.27 0 0 0-1.664-1.476ZM6.22 3.303a.37.37 0 0 1-.267.11.35.35 0 0 1-.263-.11.37.37 0 0 1-.107-.264.37.37 0 0 1 .107-.265.35.35 0 0 1 .263-.11q.155 0 .267.11a.36.36 0 0 1 .112.265.36.36 0 0 1-.112.264m4.101 0a.35.35 0 0 1-.262.11.37.37 0 0 1-.268-.11.36.36 0 0 1-.112-.264q0-.154.112-.265a.37.37 0 0 1 .268-.11q.155 0 .262.11a.37.37 0 0 1 .107.265q0 .153-.107.264M3.5 11.77q0 .441.311.75.311.306.76.307h.758l.01 2.182q0 .414.292.703a.96.96 0 0 0 .7.288.97.97 0 0 0 .71-.288.95.95 0 0 0 .292-.703v-2.182h1.343v2.182q0 .414.292.703a.97.97 0 0 0 .71.288.97.97 0 0 0 .71-.288.95.95 0 0 0 .292-.703v-2.182h.76q.436 0 .749-.308.31-.307.311-.75V5.365h-9zm10.495-6.587a.98.98 0 0 0-.702.278.9.9 0 0 0-.293.685v4.063q0 .406.293.69a.97.97 0 0 0 .702.284q.42 0 .712-.284a.92.92 0 0 0 .293-.69V6.146a.9.9 0 0 0-.293-.685 1 1 0 0 0-.712-.278m-12.702.283a1 1 0 0 1 .712-.283q.41 0 .702.283a.9.9 0 0 1 .293.68v4.063a.93.93 0 0 1-.288.69.97.97 0 0 1-.707.284 1 1 0 0 1-.712-.284.92.92 0 0 1-.293-.69V6.146q0-.396.293-.68"/>
</svg>

After

Width:  |  Height:  |  Size: 1.4 KiB

Loaded 100 of 2099 files, more files were not shown because too many files have changed in this diff. Show more