diff --git a/README.md b/README.md index 76aa0a22..5fb63758 100644 --- a/README.md +++ b/README.md @@ -696,6 +696,44 @@ How do we solve this ? Developers love having framework overview by examples. It +
+ + + Blazor + + + +- [x] Reactivity + - [x] Declare state + - [x] Update state + - [x] Computed state +- [x] Templating + - [x] Minimal template + - [x] Styling + - [x] Loop + - [x] Event click + - [x] Dom ref + - [x] Conditional +- [x] Lifecycle + - [x] On mount + - [x] On unmount +- [x] Component composition + - [x] Props + - [x] Emit to parent + - [x] Slot + - [x] Slot fallback + - [x] Context +- [x] Form input + - [x] Input text + - [x] Checkbox + - [x] Radio + - [x] Select +- [ ] Webapp features + - [ ] Render app + - [ ] Fetch data + +
+ ## 🤝 Contributing diff --git a/build/lib/highlighter.ts b/build/lib/highlighter.ts index 5b66fca9..6816362b 100644 --- a/build/lib/highlighter.ts +++ b/build/lib/highlighter.ts @@ -32,9 +32,12 @@ async function getHighlighter(): Promise< "jsx", "vue", "marko", + "csharp", ], langAlias: { - ripple: "jsx", // until ripple is supported by shiki + ripple: "jsx", + razor: "csharp", // Csharp might not be ideal, but better? than nothing + cs: "csharp", }, }); } diff --git a/content/1-reactivity/1-declare-state/blazor/Name.razor b/content/1-reactivity/1-declare-state/blazor/Name.razor new file mode 100644 index 00000000..76383b90 --- /dev/null +++ b/content/1-reactivity/1-declare-state/blazor/Name.razor @@ -0,0 +1,5 @@ +

Hello @name

+ +@code { + private string name = "John"; +} diff --git a/content/1-reactivity/2-update-state/blazor/Name.razor b/content/1-reactivity/2-update-state/blazor/Name.razor new file mode 100644 index 00000000..1d9d5fa0 --- /dev/null +++ b/content/1-reactivity/2-update-state/blazor/Name.razor @@ -0,0 +1,10 @@ +

Hello @name

+ +@code { + private string name = "John"; + + protected override void OnInitialized() + { + name = "Jane"; + } +} diff --git a/content/1-reactivity/3-computed-state/blazor/DoubleCount.razor b/content/1-reactivity/3-computed-state/blazor/DoubleCount.razor new file mode 100644 index 00000000..f33f7a87 --- /dev/null +++ b/content/1-reactivity/3-computed-state/blazor/DoubleCount.razor @@ -0,0 +1,6 @@ +
@doubleCount
+ +@code { + private int count = 10; + private int doubleCount => count * 2; +} diff --git a/content/2-templating/1-minimal-template/blazor/HelloWorld.razor b/content/2-templating/1-minimal-template/blazor/HelloWorld.razor new file mode 100644 index 00000000..159202e8 --- /dev/null +++ b/content/2-templating/1-minimal-template/blazor/HelloWorld.razor @@ -0,0 +1 @@ +

Hello world

diff --git a/content/2-templating/2-styling/blazor/CssStyle.razor b/content/2-templating/2-styling/blazor/CssStyle.razor new file mode 100644 index 00000000..e41c14d0 --- /dev/null +++ b/content/2-templating/2-styling/blazor/CssStyle.razor @@ -0,0 +1,8 @@ +

I am red

+ + + diff --git a/content/2-templating/3-loop/blazor/Colors.razor b/content/2-templating/3-loop/blazor/Colors.razor new file mode 100644 index 00000000..a3032f15 --- /dev/null +++ b/content/2-templating/3-loop/blazor/Colors.razor @@ -0,0 +1,10 @@ + + +@code { + private string[] colors = { "red", "green", "blue" }; +} diff --git a/content/2-templating/4-event-click/blazor/Counter.razor b/content/2-templating/4-event-click/blazor/Counter.razor new file mode 100644 index 00000000..ff37548a --- /dev/null +++ b/content/2-templating/4-event-click/blazor/Counter.razor @@ -0,0 +1,11 @@ +

Counter: @count

+ + +@code { + private int count = 0; + + private void IncrementCount() + { + count++; + } +} diff --git a/content/2-templating/5-dom-ref/blazor/InputFocused.razor b/content/2-templating/5-dom-ref/blazor/InputFocused.razor new file mode 100644 index 00000000..f389bbf4 --- /dev/null +++ b/content/2-templating/5-dom-ref/blazor/InputFocused.razor @@ -0,0 +1,13 @@ + + +@code { + private ElementReference inputElement; + + protected override async Task OnAfterRenderAsync(bool firstRender) + { + if (firstRender) + { + await inputElement.FocusAsync(); + } + } +} diff --git a/content/2-templating/6-conditional/blazor/TrafficLight.razor b/content/2-templating/6-conditional/blazor/TrafficLight.razor new file mode 100644 index 00000000..a52beb03 --- /dev/null +++ b/content/2-templating/6-conditional/blazor/TrafficLight.razor @@ -0,0 +1,28 @@ + +

Light is: @light

+

+ You must + @if (light == "red") + { + STOP + } + else if (light == "orange") + { + SLOW DOWN + } + else if (light == "green") + { + GO + } +

+ +@code { + private readonly string[] trafficLights = { "red", "orange", "green" }; + private int lightIndex = 0; + private string light => trafficLights[lightIndex]; + + private void NextLight() + { + lightIndex = (lightIndex + 1) % trafficLights.Length; + } +} diff --git a/content/3-lifecycle/1-on-mount/blazor/PageTitle.razor b/content/3-lifecycle/1-on-mount/blazor/PageTitle.razor new file mode 100644 index 00000000..0d25c19d --- /dev/null +++ b/content/3-lifecycle/1-on-mount/blazor/PageTitle.razor @@ -0,0 +1,12 @@ +

Page title: @pageTitle

+ +@inject IJSRuntime JSRuntime + +@code { + private string pageTitle = string.Empty; + + protected override async Task OnInitializedAsync() + { + pageTitle = await JSRuntime.InvokeAsync("eval", "document.title"); + } +} diff --git a/content/3-lifecycle/2-on-unmount/blazor/Time.razor b/content/3-lifecycle/2-on-unmount/blazor/Time.razor new file mode 100644 index 00000000..1b2c2403 --- /dev/null +++ b/content/3-lifecycle/2-on-unmount/blazor/Time.razor @@ -0,0 +1,31 @@ +@implements IDisposable + +

Current time: @currentTime

+ +@code { + private string currentTime = string.Empty; + private Timer? timer; + + protected override void OnInitialized() + { + currentTime = DateTime.Now.ToLongTimeString(); + + timer = new Timer( + callback: _ => UpdateTime(), + state: null, + dueTime: TimeSpan.Zero, + period: TimeSpan.FromSeconds(1) + ); + } + + private void UpdateTime() + { + currentTime = DateTime.Now.ToLongTimeString(); + StateHasChanged(); + } + + public void Dispose() + { + timer?.Dispose(); + } +} \ No newline at end of file diff --git a/content/4-component-composition/1-props/blazor/App.razor b/content/4-component-composition/1-props/blazor/App.razor new file mode 100644 index 00000000..bf92f4a8 --- /dev/null +++ b/content/4-component-composition/1-props/blazor/App.razor @@ -0,0 +1,6 @@ + + diff --git a/content/4-component-composition/1-props/blazor/UserProfile.razor b/content/4-component-composition/1-props/blazor/UserProfile.razor new file mode 100644 index 00000000..9733c90c --- /dev/null +++ b/content/4-component-composition/1-props/blazor/UserProfile.razor @@ -0,0 +1,18 @@ +

My name is @Name!

+

My age is @Age!

+

My favourite colors are @string.Join(", ", FavouriteColors)!

+

I am @(IsAvailable ? "available" : "not available")

+ +@code { + [Parameter] + public string Name { get; set; } = ""; + + [Parameter] + public int Age { get; set; } + + [Parameter] + public string[] FavouriteColors { get; set; } = Array.Empty(); + + [Parameter] + public bool IsAvailable { get; set; } +} diff --git a/content/4-component-composition/2-emit-to-parent/blazor/AnswerButton.razor b/content/4-component-composition/2-emit-to-parent/blazor/AnswerButton.razor new file mode 100644 index 00000000..8d6ef9ff --- /dev/null +++ b/content/4-component-composition/2-emit-to-parent/blazor/AnswerButton.razor @@ -0,0 +1,8 @@ + + +@code { + [Parameter] + public EventCallback OnYes { get; set; } + [Parameter] + public EventCallback OnNo { get; set; } +} \ No newline at end of file diff --git a/content/4-component-composition/2-emit-to-parent/blazor/App.razor b/content/4-component-composition/2-emit-to-parent/blazor/App.razor new file mode 100644 index 00000000..03599a71 --- /dev/null +++ b/content/4-component-composition/2-emit-to-parent/blazor/App.razor @@ -0,0 +1,17 @@ +

Are you happy?

+ +

@(isHappy ? "😀" : "😥")

+ +@code { + private bool isHappy = true; + + private void OnAnswerNo() + { + isHappy = false; + } + + private void OnAnswerYes() + { + isHappy = true; + } +} diff --git a/content/4-component-composition/3-slot/blazor/App.razor b/content/4-component-composition/3-slot/blazor/App.razor new file mode 100644 index 00000000..63cea083 --- /dev/null +++ b/content/4-component-composition/3-slot/blazor/App.razor @@ -0,0 +1 @@ +Click me! diff --git a/content/4-component-composition/3-slot/blazor/FunnyButton.razor b/content/4-component-composition/3-slot/blazor/FunnyButton.razor new file mode 100644 index 00000000..61662e44 --- /dev/null +++ b/content/4-component-composition/3-slot/blazor/FunnyButton.razor @@ -0,0 +1,8 @@ + + +@code { + [Parameter] + public RenderFragment? ChildContent { get; set; } +} diff --git a/content/4-component-composition/4-slot-fallback/blazor/App.razor b/content/4-component-composition/4-slot-fallback/blazor/App.razor new file mode 100644 index 00000000..385cd230 --- /dev/null +++ b/content/4-component-composition/4-slot-fallback/blazor/App.razor @@ -0,0 +1,2 @@ + +I got content! diff --git a/content/4-component-composition/4-slot-fallback/blazor/FunnyButton.razor b/content/4-component-composition/4-slot-fallback/blazor/FunnyButton.razor new file mode 100644 index 00000000..844101d0 --- /dev/null +++ b/content/4-component-composition/4-slot-fallback/blazor/FunnyButton.razor @@ -0,0 +1,15 @@ + + +@code { + [Parameter] + public RenderFragment? ChildContent { get; set; } +} diff --git a/content/4-component-composition/5-context/blazor/App.razor b/content/4-component-composition/5-context/blazor/App.razor new file mode 100644 index 00000000..13ddc755 --- /dev/null +++ b/content/4-component-composition/5-context/blazor/App.razor @@ -0,0 +1,25 @@ +

Welcome back, @user.Username

+ + + + +@code { + private UserInfo user = new() + { + Id = 1, + Username = "unicorn42", + Email = "unicorn42@example.com" + }; + + public class UserInfo + { + public int Id { get; set; } + public string Username { get; set; } = ""; + public string Email { get; set; } = ""; + + public void UpdateUsername(string newUsername) + { + Username = newUsername; + } + } +} diff --git a/content/4-component-composition/5-context/blazor/UserProfile.razor b/content/4-component-composition/5-context/blazor/UserProfile.razor new file mode 100644 index 00000000..0fcf43e5 --- /dev/null +++ b/content/4-component-composition/5-context/blazor/UserProfile.razor @@ -0,0 +1,16 @@ +
+

My Profile

+

Username: @user?.Username

+

Email: @user?.Email

+ +
+ +@code { + [CascadingParameter] + private App.UserInfo? user { get; set; } + + private void UpdateUsername() + { + user?.UpdateUsername("Jane"); + } +} diff --git a/content/6-form-input/1-input-text/blazor/InputHello.razor b/content/6-form-input/1-input-text/blazor/InputHello.razor new file mode 100644 index 00000000..607b1ca0 --- /dev/null +++ b/content/6-form-input/1-input-text/blazor/InputHello.razor @@ -0,0 +1,6 @@ +

@text

+ + +@code { + private string text = "Hello world"; +} diff --git a/content/6-form-input/2-checkbox/blazor/IsAvailable.razor b/content/6-form-input/2-checkbox/blazor/IsAvailable.razor new file mode 100644 index 00000000..9e923fd8 --- /dev/null +++ b/content/6-form-input/2-checkbox/blazor/IsAvailable.razor @@ -0,0 +1,6 @@ + + + +@code { + private bool isAvailable = false; +} diff --git a/content/6-form-input/3-radio/blazor/PickPill.razor b/content/6-form-input/3-radio/blazor/PickPill.razor new file mode 100644 index 00000000..75f2278e --- /dev/null +++ b/content/6-form-input/3-radio/blazor/PickPill.razor @@ -0,0 +1,19 @@ +
Picked: @picked
+ + + + + + + +@code { + private string picked = "red"; +} diff --git a/content/6-form-input/4-select/blazor/ColorSelect.razor b/content/6-form-input/4-select/blazor/ColorSelect.razor new file mode 100644 index 00000000..250d7c07 --- /dev/null +++ b/content/6-form-input/4-select/blazor/ColorSelect.razor @@ -0,0 +1,25 @@ + + +@code { + private class ColorOption + { + public int Id { get; set; } + public string Text { get; set; } = ""; + public bool IsDisabled { get; set; } + } + + private readonly ColorOption[] colors = new[] + { + new ColorOption { Id = 1, Text = "red" }, + new ColorOption { Id = 2, Text = "blue" }, + new ColorOption { Id = 3, Text = "green" }, + new ColorOption { Id = 4, Text = "gray", IsDisabled = true } + }; + + private int selectedColorId = 2; +} diff --git a/frameworks.ts b/frameworks.ts index e1389ac1..ee244bd5 100644 --- a/frameworks.ts +++ b/frameworks.ts @@ -338,6 +338,23 @@ export const frameworks: Framework[] = [ mainPackageName: "ripple", releaseDate: "2023-01-01", }, + { + id: "blazor", + title: "Blazor", + frameworkName: "Blazor", + frameworkNameId: "blazor", + isLatestStable: true, + img: "framework/blazor.svg", + playgroundURL: "https://try.dot.net/", + documentationURL: + "https://dotnet.microsoft.com/apps/aspnet/web-apps/blazor", + filesSorter(files) { + return sortAllFilenames(files, ["App.razor", "App.razor.cs"]); + }, + repositoryLink: "https://github.com/dotnet/aspnetcore", + mainPackageName: "Microsoft.AspNetCore.Components.Web", + releaseDate: "2018-09-01", + }, ]; export function matchFrameworkId(id: string): Framework | undefined { diff --git a/public/framework/blazor.svg b/public/framework/blazor.svg new file mode 100644 index 00000000..2f5a30cf --- /dev/null +++ b/public/framework/blazor.svg @@ -0,0 +1 @@ + \ No newline at end of file