diff --git a/apps/server/AliasVault.Client/Main/Pages/Items/View.razor b/apps/server/AliasVault.Client/Main/Pages/Items/View.razor
index 62d8366e4..8ed636b6f 100644
--- a/apps/server/AliasVault.Client/Main/Pages/Items/View.razor
+++ b/apps/server/AliasVault.Client/Main/Pages/Items/View.razor
@@ -171,14 +171,9 @@ else
@@ -206,7 +201,7 @@ else
}
@foreach (var field in aliasFields)
{
-
+
}
@@ -223,9 +218,7 @@ else
@foreach (var field in cardFields)
{
- @* Cardholder name should be full width *@
- var isFullWidthCardField = field.FieldKey == FieldKey.CardCardholderName;
-
+
}
diff --git a/apps/server/AliasVault.Client/Main/Utilities/LayoutUtils.cs b/apps/server/AliasVault.Client/Main/Utilities/LayoutUtils.cs
new file mode 100644
index 000000000..9f7feeba1
--- /dev/null
+++ b/apps/server/AliasVault.Client/Main/Utilities/LayoutUtils.cs
@@ -0,0 +1,95 @@
+// -----------------------------------------------------------------------
+//
+// Copyright (c) aliasvault. All rights reserved.
+// Licensed under the AGPLv3 license. See LICENSE.md file in the project root for full license information.
+//
+// -----------------------------------------------------------------------
+
+namespace AliasVault.Client.Main.Utilities;
+
+using AliasClientDb.Models;
+using AliasVault.Client.Main.Models;
+
+///
+/// Utility for calculating field layout widths dynamically.
+///
+public static class LayoutUtils
+{
+ ///
+ /// Determines which fields should be displayed at full width based on the field list.
+ /// Rules:
+ /// - Fields that are inherently full width (Password, TextArea, URL) always stay full width.
+ /// - If there's only one half-width-capable field, it should be full width.
+ /// - If there's an odd number of half-width-capable fields, the last one should be full width.
+ /// - Password fields are placed at the end and always full width.
+ ///
+ /// The list of fields to analyze.
+ /// A set of field keys that should be displayed at full width.
+ public static HashSet GetFullWidthFields(IReadOnlyList fields)
+ {
+ var fullWidthFields = new HashSet();
+
+ if (fields == null || fields.Count == 0)
+ {
+ return fullWidthFields;
+ }
+
+ // First, identify fields that are always full width by their type
+ var alwaysFullWidthTypes = new HashSet(StringComparer.OrdinalIgnoreCase)
+ {
+ FieldType.Password,
+ FieldType.Hidden,
+ FieldType.TextArea,
+ FieldType.URL,
+ };
+
+ // Separate fields into always-full-width and half-width-capable
+ var halfWidthCapableFields = new List();
+
+ foreach (var field in fields)
+ {
+ if (alwaysFullWidthTypes.Contains(field.FieldType))
+ {
+ fullWidthFields.Add(GetFieldIdentifier(field));
+ }
+ else
+ {
+ halfWidthCapableFields.Add(field);
+ }
+ }
+
+ // If there's only one half-width-capable field, make it full width
+ if (halfWidthCapableFields.Count == 1)
+ {
+ fullWidthFields.Add(GetFieldIdentifier(halfWidthCapableFields[0]));
+ }
+ else if (halfWidthCapableFields.Count > 1 && halfWidthCapableFields.Count % 2 == 1)
+ {
+ fullWidthFields.Add(GetFieldIdentifier(halfWidthCapableFields[^1]));
+ }
+
+ return fullWidthFields;
+ }
+
+ ///
+ /// Determines if a specific field should be displayed at full width based on the field list.
+ ///
+ /// The field to check.
+ /// The list of all fields in the section.
+ /// True if the field should be full width, false otherwise.
+ public static bool ShouldBeFullWidth(DisplayField field, IReadOnlyList fields)
+ {
+ var fullWidthFields = GetFullWidthFields(fields);
+ return fullWidthFields.Contains(GetFieldIdentifier(field));
+ }
+
+ ///
+ /// Gets a unique identifier for a field (uses FieldKey for system fields, FieldDefinitionId for custom).
+ ///
+ private static string GetFieldIdentifier(DisplayField field)
+ {
+ return !string.IsNullOrEmpty(field.FieldKey)
+ ? field.FieldKey
+ : field.FieldDefinitionId ?? string.Empty;
+ }
+}