Skip to content
Merged
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ public class NavigationStore
.Add( new( nameof( LumexDataGrid<T> ) ) )
.Add( new( nameof( LumexDivider ) ) )
.Add( new( nameof( LumexDropdown ) ) )
.Add( new( nameof( LumexKbd ), PageStatus.New ) )
.Add( new( nameof( LumexLink ) ) )
.Add( new( nameof( LumexListbox<T> ) ) )
.Add( new( nameof( LumexNavbar ) ) )
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<div class="flex items-center gap-2">
<LumexKbd Keys="@([KeyboardKey.Command])">K</LumexKbd>
<LumexKbd Keys="@([KeyboardKey.Command, KeyboardKey.Shift])">N</LumexKbd>
<LumexKbd Keys="@([KeyboardKey.Option, KeyboardKey.Command])">P</LumexKbd>
</div>
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
<LumexKbd Keys="@([KeyboardKey.Command])">K</LumexKbd>
61 changes: 61 additions & 0 deletions docs/LumexUI.Docs.Client/Pages/Components/Kbd/Kbd.razor
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
@page "/docs/components/kbd"
@layout DocsContentLayout

@using LumexUI.Docs.Client.Pages.Components.Kbd.PreviewCodes

<DocsSection Title="Usage">
<Usage />

<DocsSection Title="Keys">
<p>Use the <code>Keys</code> parameter to specify a single keyboard key or a combination of keys.</p>
<Keys />
</DocsSection>
</DocsSection>

<DocsSlotsSection Slots="@_slots">
<div>
<h4 class="font-semibold">Kbd</h4>
<ul>
<li><code>Class</code>: The basic CSS class name styles the wrapper of the kbd contents.</li>
<li><code>Classes</code>: The CSS class names for the kbd slots style the entire kbd at once.</li>
</ul>
</div>
</DocsSlotsSection>

<DocsApiSection Components="@_apiComponents" />

@code {
[CascadingParameter] private DocsContentLayout Layout { get; set; } = default!;

private readonly Heading[] _headings = new Heading[]
{
new("Usage", [
new("Keys")
]),
new("Custom Styles"),
new("API")
};

private readonly Slot[] _slots = new Slot[]
{
new(nameof( KbdSlots.Base ), "Kbd wrapper, it handles alignment, placement, and general appearance."),
new(nameof( KbdSlots.Abbr ), "The keys wrapper that handles the appearance of the keys."),
new(nameof( KbdSlots.Content ), "The children wrapper that handles the appearance of the content."),
};

private readonly string[] _apiComponents = new string[]
{
nameof( LumexKbd )
};

protected override void OnInitialized()
{
Layout.Initialize(
title: "Keyboard Key",
category: "Components",
description: "Keyboard key component for displaying keyboard shortcuts and input combinations.",
headings: _headings,
linksProps: new ComponentLinksProps( "Kbd", isServer: true )
);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
@rendermode InteractiveWebAssembly

<PreviewCode Code="@new(name: null, snippet: "Kbd.Code.Keys")">
<LumexUI.Docs.Client.Pages.Components.Kbd.Examples.Keys />
</PreviewCode>
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
@rendermode InteractiveWebAssembly

<PreviewCode Code="@new(name: null, snippet: "Kbd.Code.Usage")">
<LumexUI.Docs.Client.Pages.Components.Kbd.Examples.Usage />
</PreviewCode>
121 changes: 121 additions & 0 deletions src/LumexUI/Common/Enums/KeyboardKey.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
// Copyright (c) LumexUI 2024
// LumexUI licenses this file to you under the MIT license
// See the license here https://github.com/LumexUI/lumexui/blob/main/LICENSE

namespace LumexUI.Common;

/// <summary>
/// Represents common keyboard keys for UI interactions.
/// </summary>
public enum KeyboardKey
{
/// <summary>
/// The Command key (⌘), commonly found on Apple keyboards.
/// </summary>
Command,

/// <summary>
/// The Shift key.
/// </summary>
Shift,

/// <summary>
/// The Control key (Ctrl).
/// </summary>
Control,

/// <summary>
/// The Option key (⌥), commonly found on Apple keyboards.
/// </summary>
Option,

/// <summary>
/// The Alt key (⎇), commonly found on Windows and Linux keyboards.
/// </summary>
Alt,

/// <summary>
/// The Windows key (⊞).
/// </summary>
Win,

/// <summary>
/// The Function (fn) key, often found on laptops.
/// </summary>
Fn,

/// <summary>
/// The Enter key.
/// </summary>
Enter,

/// <summary>
/// The Delete key.
/// </summary>
Delete,

/// <summary>
/// The Escape key (Esc).
/// </summary>
Escape,

/// <summary>
/// The Tab key.
/// </summary>
Tab,

/// <summary>
/// The Caps Lock key.
/// </summary>
CapsLock,

/// <summary>
/// The Up Arrow key.
/// </summary>
Up,

/// <summary>
/// The Right Arrow key.
/// </summary>
Right,

/// <summary>
/// The Down Arrow key.
/// </summary>
Down,

/// <summary>
/// The Left Arrow key.
/// </summary>
Left,

/// <summary>
/// The Page Up key.
/// </summary>
PageUp,

/// <summary>
/// The Page Down key.
/// </summary>
PageDown,

/// <summary>
/// The Home key.
/// </summary>
Home,

/// <summary>
/// The End key.
/// </summary>
End,

/// <summary>
/// The Help key.
/// </summary>
Help,

/// <summary>
/// The Space key (Spacebar).
/// </summary>
Space,
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's also add Fn (fn), Win (Win) and Alt (⎇).

36 changes: 36 additions & 0 deletions src/LumexUI/Components/Kbd/KbdConstants.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
// Copyright (c) LumexUI 2024
// LumexUI licenses this file to you under the MIT license
// See the license here https://github.com/LumexUI/lumexui/blob/main/LICENSE

using LumexUI.Common;

namespace LumexUI;

internal static class KbdConstants
{
public static readonly Dictionary<KeyboardKey, string> KeyboardKeys = new()
{
[KeyboardKey.Command] = "⌘",
[KeyboardKey.Shift] = "⇧",
[KeyboardKey.Control] = "⌃",
[KeyboardKey.Option] = "⌥",
[KeyboardKey.Alt] = "⎇",
[KeyboardKey.Win] = "⊞",
[KeyboardKey.Fn] = "fn",
[KeyboardKey.Enter] = "↵",
[KeyboardKey.Delete] = "⌫",
[KeyboardKey.Escape] = "⎋",
[KeyboardKey.Tab] = "⇥",
[KeyboardKey.CapsLock] = "⇪",
[KeyboardKey.Up] = "↑",
[KeyboardKey.Right] = "→",
[KeyboardKey.Down] = "↓",
[KeyboardKey.Left] = "←",
[KeyboardKey.PageUp] = "⇞",
[KeyboardKey.PageDown] = "⇟",
[KeyboardKey.Home] = "↖",
[KeyboardKey.End] = "↘",
[KeyboardKey.Help] = "?",
[KeyboardKey.Space] = "␣",
};
}
26 changes: 26 additions & 0 deletions src/LumexUI/Components/Kbd/KbdSlots.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
// Copyright (c) LumexUI 2024
// LumexUI licenses this file to you under the MIT license
// See the license here https://github.com/LumexUI/lumexui/blob/main/LICENSE

using System.Diagnostics.CodeAnalysis;

using LumexUI.Common;

namespace LumexUI;

/// <summary>
/// Represents the set of customizable slots for the <see cref="LumexKbd"/> component.
/// </summary>
[ExcludeFromCodeCoverage]
public class KbdSlots : SlotBase
{
/// <summary>
/// Gets or sets the CSS class for the abbr slot.
/// </summary>
public string? Abbr { get; set; }

/// <summary>
/// Gets or sets the CSS class for the content slot.
/// </summary>
public string? Content { get; set; }
}
22 changes: 22 additions & 0 deletions src/LumexUI/Components/Kbd/LumexKbd.razor
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
@namespace LumexUI
@inherits LumexComponentBase

@using S = KbdSlots;
@using C = KbdConstants;

<LumexComponent As="@As"
Class="@GetStyles( nameof( S.Base ) )"
Style="@RootStyle"
data-slot="base"
@attributes="@AdditionalAttributes">
@foreach( var key in Keys )
{
<abbr class="@GetStyles( nameof( S.Abbr ) )" title="@key" data-slot="abbr">
@( C.KeyboardKeys.TryGetValue( key, out var symbol ) ? symbol : null )
</abbr>
}

<span class="@GetStyles( nameof( S.Content ) )" data-slot="content">
@ChildContent
</span>
</LumexComponent>
67 changes: 67 additions & 0 deletions src/LumexUI/Components/Kbd/LumexKbd.razor.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
// Copyright (c) LumexUI 2024
// LumexUI licenses this file to you under the MIT license
// See the license here https://github.com/LumexUI/lumexui/blob/main/LICENSE

using System.Diagnostics.CodeAnalysis;

using LumexUI.Common;
using LumexUI.Utilities;

using Microsoft.AspNetCore.Components;

namespace LumexUI;

/// <summary>
/// A component that represents a keyboard key or combination of keys used to perform a specific action.
/// </summary>
public partial class LumexKbd : LumexComponentBase, ISlotComponent<KbdSlots>
{
/// <summary>
/// Gets or sets the content to be rendered inside the component.
/// </summary>
[Parameter] public RenderFragment? ChildContent { get; set; }

/// <summary>
/// Gets or sets the collection of keys to be used as input for the component.
/// </summary>
[Parameter] public IEnumerable<KeyboardKey> Keys { get; set; } = [];

/// <summary>
/// Gets or sets the CSS class names for the kbd slots.
/// </summary>
[Parameter] public KbdSlots? Classes { get; set; }

private Dictionary<string, ComponentSlot> _slots = [];

/// <summary>
/// Initializes a new instance of the <see cref="LumexKbd"/>.
/// </summary>
public LumexKbd()
{
As = "kbd";
}

/// <inheritdoc/>
protected override void OnParametersSet()
{
var kbd = Styles.Kbd.Style( TwMerge );
_slots = kbd();
}

[ExcludeFromCodeCoverage]
private string? GetStyles( string slot )
{
if( !_slots.TryGetValue( slot, out var styles ) )
{
throw new NotImplementedException();
}

return slot switch
{
nameof( KbdSlots.Base ) => styles( Classes?.Base, Class ),
nameof( KbdSlots.Abbr ) => styles( Classes?.Abbr ),
nameof( KbdSlots.Content ) => styles( Classes?.Content ),
_ => throw new NotImplementedException()
};
}
}
Loading
Loading