From 1d6babdab592639e0bc371b6722e17895e44bd05 Mon Sep 17 00:00:00 2001 From: Beau Findlay Date: Wed, 6 Mar 2024 21:37:45 +0000 Subject: [PATCH] Add typewriter component --- BeauFindlay/BeauFindlay/App.razor | 1 - .../Components/Typewriter/Typewriter.razor | 104 ++++++++++++++++++ BeauFindlay/BeauFindlay/Pages/Home.razor | 11 +- BeauFindlay/BeauFindlay/_Imports.razor | 1 + BeauFindlay/BeauFindlay/wwwroot/css/app.css | 11 +- .../BeauFindlay/wwwroot/css/app.min.css | 75 +++++++++++++ BeauFindlay/BeauFindlay/wwwroot/index.html | 5 +- 7 files changed, 204 insertions(+), 4 deletions(-) create mode 100644 BeauFindlay/BeauFindlay/Components/Typewriter/Typewriter.razor diff --git a/BeauFindlay/BeauFindlay/App.razor b/BeauFindlay/BeauFindlay/App.razor index 6fd3ed1..d414dad 100644 --- a/BeauFindlay/BeauFindlay/App.razor +++ b/BeauFindlay/BeauFindlay/App.razor @@ -1,7 +1,6 @@  - Not found diff --git a/BeauFindlay/BeauFindlay/Components/Typewriter/Typewriter.razor b/BeauFindlay/BeauFindlay/Components/Typewriter/Typewriter.razor new file mode 100644 index 0000000..38ffb4f --- /dev/null +++ b/BeauFindlay/BeauFindlay/Components/Typewriter/Typewriter.razor @@ -0,0 +1,104 @@ +@using System.Timers + +@if (DisplayCursor) +{ + @currentText| +} +else +{ + @currentText +} + +@code { + private const int typingDelayMilliseconds = 100; + private const int lineEndDelayMilliseconds = 1000; + + private static List instances = []; + private static Typewriter? lastTypingInstance = null; + private string currentText = ""; + private bool isTyping = false; + + private bool DisplayCursor => lastTypingInstance == this; + + [Parameter] + public string Text { get; set; } = ""; + + protected override void OnInitialized() + { + Text = Text.Trim(); + instances.Add(this); + StartTypingIfFirst(); + } + + private void StartTypingIfFirst() + { + if (instances.FirstOrDefault() == this && !isTyping) + { + StartTyping(); + } + } + + private void StartTyping() + { + isTyping = true; + lastTypingInstance = this; + var timer = new Timer(typingDelayMilliseconds); + var index = 0; + + timer.Elapsed += (_, __) => + { + if (index < Text.Length) + { + currentText += Text[index++]; + InvokeAsync(StateHasChanged); + } + else + { + CompleteTyping(timer); + } + }; + timer.Start(); + } + + private void CompleteTyping(Timer typingTimer) + { + typingTimer.Stop(); + + isTyping = false; + + var delayTimer = new Timer(lineEndDelayMilliseconds); + delayTimer.Elapsed += (sender, e) => + { + delayTimer.Stop(); + delayTimer.Dispose(); + UpdateCursorVisibility(); + StartNextInstanceTyping(); + InvokeAsync(StateHasChanged); + }; + + delayTimer.Start(); + } + + private void UpdateCursorVisibility() + { + lastTypingInstance = instances.LastOrDefault(i => !i.isTyping); + + InvokeAsync(StateHasChanged); + } + + private void StartNextInstanceTyping() + { + instances.Remove(this); + + var nextInstance = instances.FirstOrDefault(); + + nextInstance?.StartTyping(); + } + + public static void Reset() + { + instances.Clear(); + + lastTypingInstance = null; + } +} diff --git a/BeauFindlay/BeauFindlay/Pages/Home.razor b/BeauFindlay/BeauFindlay/Pages/Home.razor index d01a7f0..451dabf 100644 --- a/BeauFindlay/BeauFindlay/Pages/Home.razor +++ b/BeauFindlay/BeauFindlay/Pages/Home.razor @@ -1,3 +1,12 @@ @page "/" -Home \ No newline at end of file +Home - Beau Findlay + +
+

+ +

+

+ +

+
\ No newline at end of file diff --git a/BeauFindlay/BeauFindlay/_Imports.razor b/BeauFindlay/BeauFindlay/_Imports.razor index 4a99c9f..6c21cbd 100644 --- a/BeauFindlay/BeauFindlay/_Imports.razor +++ b/BeauFindlay/BeauFindlay/_Imports.razor @@ -8,3 +8,4 @@ @using Microsoft.JSInterop @using BeauFindlay @using BeauFindlay.Layout +@using BeauFindlay.Components.Typewriter \ No newline at end of file diff --git a/BeauFindlay/BeauFindlay/wwwroot/css/app.css b/BeauFindlay/BeauFindlay/wwwroot/css/app.css index bd6213e..1475925 100644 --- a/BeauFindlay/BeauFindlay/wwwroot/css/app.css +++ b/BeauFindlay/BeauFindlay/wwwroot/css/app.css @@ -1,3 +1,12 @@ @tailwind base; @tailwind components; -@tailwind utilities; \ No newline at end of file +@tailwind utilities; + +@keyframes blink { + from, to { opacity: 1 } + 50% { opacity: 0 } +} + +.blinking-cursor { + animation: blink 1s step-end infinite; +} \ No newline at end of file diff --git a/BeauFindlay/BeauFindlay/wwwroot/css/app.min.css b/BeauFindlay/BeauFindlay/wwwroot/css/app.min.css index f885dab..6ae6288 100644 --- a/BeauFindlay/BeauFindlay/wwwroot/css/app.min.css +++ b/BeauFindlay/BeauFindlay/wwwroot/css/app.min.css @@ -544,19 +544,80 @@ video { --tw-backdrop-sepia: ; } +.static { + position: static; +} + +.mt-4 { + margin-top: 1rem; +} + +.mt-3 { + margin-top: 0.75rem; +} + +.flex { + display: flex; +} + +.h-full { + height: 100%; +} + .min-h-screen { min-height: 100vh; } +.items-center { + align-items: center; +} + +.justify-center { + justify-content: center; +} + .bg-black { --tw-bg-opacity: 1; background-color: rgb(0 0 0 / var(--tw-bg-opacity)); } +.p-4 { + padding: 1rem; +} + +.p-8 { + padding: 2rem; +} + +.py-4 { + padding-top: 1rem; + padding-bottom: 1rem; +} + +.py-8 { + padding-top: 2rem; + padding-bottom: 2rem; +} + +.px-4 { + padding-left: 1rem; + padding-right: 1rem; +} + .font-mono { font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace; } +.text-lg { + font-size: 1.125rem; + line-height: 1.75rem; +} + +.text-3xl { + font-size: 1.875rem; + line-height: 2.25rem; +} + .text-slate-50 { --tw-text-opacity: 1; color: rgb(248 250 252 / var(--tw-text-opacity)); @@ -565,4 +626,18 @@ video { .subpixel-antialiased { -webkit-font-smoothing: auto; -moz-osx-font-smoothing: auto; +} + +@keyframes blink { + from, to { + opacity: 1 + } + + 50% { + opacity: 0 + } +} + +.blinking-cursor { + animation: blink 1s step-end infinite; } \ No newline at end of file diff --git a/BeauFindlay/BeauFindlay/wwwroot/index.html b/BeauFindlay/BeauFindlay/wwwroot/index.html index fabce85..54f4f1f 100644 --- a/BeauFindlay/BeauFindlay/wwwroot/index.html +++ b/BeauFindlay/BeauFindlay/wwwroot/index.html @@ -12,7 +12,10 @@ -
+
+
+

Loading beaufindlay.com|

+