Skip to content

Commit 8d45d9d

Browse files
committed
Dynamic JsonLD+
1 parent 971c1e4 commit 8d45d9d

17 files changed

+871
-128
lines changed

TextHub/Models/PageMetadata.cs

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
namespace TextHub.Models;
2+
3+
public record PageMetadata(
4+
string Title,
5+
string Description,
6+
string Url,
7+
string Type = "WebPage",
8+
string? ImageUrl = null,
9+
string? Author = null,
10+
DateTime? PublishedDate = null,
11+
DateTime? ModifiedDate = null,
12+
List<string>? Keywords = null,
13+
Dictionary<string, object>? AdditionalProperties = null
14+
);
15+
16+
public record ToolPageMetadata(
17+
string Title,
18+
string Description,
19+
string Url,
20+
string ToolName,
21+
string Category,
22+
string? Instructions = null,
23+
List<string>? Features = null,
24+
Dictionary<string, object>? AdditionalProperties = null
25+
) : PageMetadata(Title, Description, Url, "WebApplication", AdditionalProperties: AdditionalProperties);

TextHub/Pages/Home.razor

Lines changed: 10 additions & 119 deletions
Original file line numberDiff line numberDiff line change
@@ -1,96 +1,26 @@
11
@page "/"
2-
@using TextHub.Models
32
@using TextHub.UIComponent
4-
@using System.Linq
3+
@using TextHub.Services
4+
@inject JsonLdService JsonLdService
55

66
<PageTitle>Text Hub - Quick & Simple Text Utilities</PageTitle>
77

8+
<DynamicJsonLd JsonLdContent="@_jsonLdContent" Id="home-jsonld" />
9+
810
<div class="min-h-screen flex flex-col">
911
<main class="flex-1">
1012
<div>
1113
@* --- Hero Section --- *@
1214
<HomeHeroSection/>
1315

1416
@* --- Text Case Tools Section --- *@
15-
<section class="pb-12 md:pb-20 px-4">
16-
<div class="container mx-auto max-w-7xl">
17-
<div class="mb-12 md:mb-16 animate-fade-in" style="animation-delay: 0ms;">
18-
<div class="flex items-center gap-3 mb-2">
19-
<div class="p-2 bg-primary/10 rounded-lg">
20-
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-case-sensitive w-5 h-5 md:w-6 md:h-6 text-primary">
21-
<path d="m3 15 4-8 4 8"></path>
22-
<path d="M4 13h6"></path>
23-
<circle cx="18" cy="12" r="3"></circle>
24-
<path d="M21 9v6"></path>
25-
</svg>
26-
</div>
27-
<h2 class="text-2xl md:text-3xl font-bold text-foreground">Text Case Tools</h2>
28-
</div>
29-
<p class="text-muted-foreground mb-6 md:mb-8 ml-12 md:ml-14">Convert text between different cases</p>
30-
<div class="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-4 md:gap-6">
31-
@foreach (var (tool, index) in _textCaseTools.Select((t, i) => (t, i)))
32-
{
33-
<ToolCardComponent Tool="tool" AnimationDelay="@(index * 50)" />
34-
}
35-
</div>
36-
</div>
37-
</div>
38-
</section>
17+
<TextCaseToolsSection/>
3918

4019
@* --- Text Analysis Section --- *@
41-
<section class="py-16 md:py-24 px-4 bg-muted/5">
42-
<div class="container mx-auto max-w-7xl">
43-
<div class="mb-16 md:mb-20 animate-fade-in" style="animation-delay: 150ms;">
44-
<div class="flex items-center gap-4 mb-4">
45-
<div class="p-3 bg-primary/10 rounded-xl border border-primary/20">
46-
<svg xmlns="http://www.w3.org/2000/svg" width="28" height="28" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="text-primary">
47-
<path d="M15 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V7Z"></path>
48-
<path d="M14 2v4a2 2 0 0 0 2 2h4"></path>
49-
<path d="M10 9H8"></path>
50-
<path d="M16 13H8"></path>
51-
<path d="M16 17H8"></path>
52-
</svg>
53-
</div>
54-
<h2 class="text-3xl md:text-4xl font-bold text-foreground">Text Analysis</h2>
55-
</div>
56-
<p class="text-lg text-muted-foreground mb-12 ml-16">Analyze and count text properties</p>
57-
<div class="grid grid-cols-1 md:grid-cols-2 xl:grid-cols-3 gap-6">
58-
@foreach (var (tool, index) in _textAnalysisTools.Select((t, i) => (t, i)))
59-
{
60-
<ToolCardComponent Tool="tool" AnimationDelay="@(150 + index * 100)" />
61-
}
62-
</div>
63-
</div>
64-
</div>
65-
</section>
20+
<TextAnalysisToolsSection/>
6621

6722
@* --- Text Formatting Section --- *@
68-
<section class="py-16 md:py-24 px-4">
69-
<div class="container mx-auto max-w-7xl">
70-
<div class="mb-16 md:mb-20 animate-fade-in" style="animation-delay: 300ms;">
71-
<div class="flex items-center gap-4 mb-4">
72-
<div class="p-3 bg-primary/10 rounded-xl border border-primary/20">
73-
<svg xmlns="http://www.w3.org/2000/svg" width="28" height="28" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="text-primary">
74-
<circle cx="6" cy="6" r="3"></circle>
75-
<path d="M8.12 8.12 12 12"></path>
76-
<path d="M20 4 8.12 15.88"></path>
77-
<circle cx="6" cy="18" r="3"></circle>
78-
<path d="M14.8 14.8 20 20"></path>
79-
</svg>
80-
</div>
81-
<h2 class="text-3xl md:text-4xl font-bold text-foreground">Text Formatting</h2>
82-
</div>
83-
<p class="text-lg text-muted-foreground mb-12 ml-16">Clean and format your text</p>
84-
<div class="grid grid-cols-1 md:grid-cols-2 xl:grid-cols-3 gap-6">
85-
@foreach (var (tool, index) in _textFormattingTools.Select((t, i) => (t, i)))
86-
{
87-
<ToolCardComponent Tool="tool" AnimationDelay="@(300 + index * 100)" />
88-
}
89-
</div>
90-
</div>
91-
</div>
92-
</section>
93-
23+
<TextFormattingToolsSection/>
9424

9525
@* --- Why Choose Us Section --- *@
9626
<WhyChooseUs/>
@@ -99,49 +29,10 @@
9929
</div>
10030

10131
@code {
102-
private List<Tool> _featuredTools = new();
103-
private List<Tool> _textCaseTools = new();
104-
private List<Tool> _textAnalysisTools = new();
105-
private List<Tool> _textFormattingTools = new();
32+
private string _jsonLdContent = string.Empty;
10633

10734
protected override void OnInitialized()
10835
{
109-
// Initialize featured tools (most popular ones)
110-
_featuredTools = new List<Tool>
111-
{
112-
new Tool("Uppercase Converter", "Convert any text to UPPERCASE instantly", "/uppercase", "<svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" class=\"w-6 h-6 text-primary\"><polyline points=\"4 7 4 4 20 4 20 7\"></polyline><line x1=\"9\" x2=\"15\" y1=\"20\" y2=\"20\"></line><line x1=\"12\" x2=\"12\" y1=\"4\" y2=\"20\"></line></svg>"),
113-
new Tool("Word Counter", "Count words and characters in your text", "/word-counter", "<svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" class=\"w-6 h-6 text-primary\"><line x1=\"4\" x2=\"20\" y1=\"9\" y2=\"9\"></line><line x1=\"4\" x2=\"20\" y1=\"15\" y2=\"15\"></line><line x1=\"10\" x2=\"8\" y1=\"3\" y2=\"21\"></line><line x1=\"16\" x2=\"14\" y1=\"3\" y2=\"21\"></line></svg>"),
114-
new Tool("Title Case", "Capitalize First Letter Of Each Word", "/title-case", "<svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" class=\"w-6 h-6 text-primary\"><path d=\"m3 15 4-8 4 8\"></path><path d=\"M4 13h6\"></path><circle cx=\"18\" cy=\"12\" r=\"3\"></circle><path d=\"M21 9v6\"></path></svg>"),
115-
new Tool("Remove Extra Spaces", "Clean up unnecessary spaces from text", "/remove-spaces", "<svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" class=\"w-6 h-6 text-primary\"><path d=\"M22 17v1c0 .5-.5 1-1 1H3c-.5 0-1-.5-1-1v-1\"></path></svg>")
116-
};
117-
118-
// Initialize text case tools
119-
_textCaseTools = new List<Tool>
120-
{
121-
new Tool("Uppercase Converter", "Convert any text to UPPERCASE instantly", "/uppercase", "<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" class=\"lucide lucide-type w-5 h-5 sm:w-6 sm:h-6 text-primary\"><polyline points=\"4 7 4 4 20 4 20 7\"></polyline><line x1=\"9\" x2=\"15\" y1=\"20\" y2=\"20\"></line><line x1=\"12\" x2=\"12\" y1=\"4\" y2=\"20\"></line></svg>"),
122-
new Tool("Lowercase Converter", "Transform text to lowercase with one click", "/lowercase", "<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" class=\"lucide lucide-letter-text w-5 h-5 sm:w-6 sm:h-6 text-primary\"><path d=\"M15 12h6\"></path><path d=\"M15 6h6\"></path><path d=\"m3 13 3.553-7.724a.5.5 0 0 1 .894 0L11 13\"></path><path d=\"M3 18h18\"></path><path d=\"M4 11h6\"></path></svg>"),
123-
new Tool("Title Case", "Capitalize First Letter Of Each Word", "/title-case", "<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" class=\"lucide lucide-case-sensitive w-5 h-5 sm:w-6 sm:h-6 text-primary\"><path d=\"m3 15 4-8 4 8\"></path><path d=\"M4 13h6\"></path><circle cx=\"18\" cy=\"12\" r=\"3\"></circle><path d=\"M21 9v6\"></path></svg>"),
124-
new Tool("Sentence Case", "Capitalize first letter of sentences", "/sentence-case", "<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" class=\"lucide lucide-case-sensitive w-5 h-5 sm:w-6 sm:h-6 text-primary\"><path d=\"m3 15 4-8 4 8\"></path><path d=\"M4 13h6\"></path><circle cx=\"18\" cy=\"12\" r=\"3\"></circle><path d=\"M21 9v6\"></path></svg>"),
125-
new Tool("camelCase", "Convert to camelCase for coding", "/camel-case", "<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" class=\"lucide lucide-code w-5 h-5 sm:w-6 sm:h-6 text-primary\"><polyline points=\"16 18 22 12 16 6\"></polyline><polyline points=\"8 6 2 12 8 18\"></polyline></svg>"),
126-
new Tool("PascalCase", "Convert to PascalCase for classes", "/pascal-case", "<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" class=\"lucide lucide-code w-5 h-5 sm:w-6 sm:h-6 text-primary\"><polyline points=\"16 18 22 12 16 6\"></polyline><polyline points=\"8 6 2 12 8 18\"></polyline></svg>"),
127-
new Tool("snake_case", "Convert to snake_case format", "/snake-case", "<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" class=\"lucide lucide-code w-5 h-5 sm:w-6 sm:h-6 text-primary\"><polyline points=\"16 18 22 12 16 6\"></polyline><polyline points=\"8 6 2 12 8 18\"></polyline></svg>"),
128-
new Tool("kebab-case", "Convert to kebab-case for URLs", "/kebab-case", "<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" class=\"lucide lucide-code w-5 h-5 sm:w-6 sm:h-6 text-primary\"><polyline points=\"16 18 22 12 16 6\"></polyline><polyline points=\"8 6 2 12 8 18\"></polyline></svg>")
129-
};
130-
131-
// Initialize text analysis tools for the dedicated section
132-
_textAnalysisTools = new List<Tool>
133-
{
134-
new Tool("Word Counter", "Count words and characters in your text", "/word-counter", "<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" class=\"lucide lucide-hash w-6 h-6 text-primary\"><line x1=\"4\" x2=\"20\" y1=\"9\" y2=\"9\"></line><line x1=\"4\" x2=\"20\" y1=\"15\" y2=\"15\"></line><line x1=\"10\" x2=\"8\" y1=\"3\" y2=\"21\"></line><line x1=\"16\" x2=\"14\" y1=\"3\" y2=\"21\"></line></svg>"),
135-
new Tool("Character Counter", "Count total characters including spaces", "", "<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" class=\"lucide lucide-file-text w-6 h-6 text-muted-foreground\"><path d=\"M15 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V7Z\"></path><path d=\"M14 2v4a2 2 0 0 0 2 2h4\"></path><path d=\"M10 9H8\"></path><path d=\"M16 13H8\"></path><path d=\"M16 17H8\"></path></svg>", IsComingSoon: true),
136-
new Tool("Line Counter", "Count lines and paragraphs in text", "", "<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" class=\"lucide lucide-file-text w-6 h-6 text-muted-foreground\"><path d=\"M15 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V7Z\"></path><path d=\"M14 2v4a2 2 0 0 0 2 2h4\"></path><path d=\"M10 9H8\"></path><path d=\"M16 13H8\"></path><path d=\"M16 17H8\"></path></svg>", IsComingSoon: true)
137-
};
138-
139-
// Initialize text formatting tools for the dedicated section
140-
_textFormattingTools = new List<Tool>
141-
{
142-
new Tool("Remove Extra Spaces", "Clean up unnecessary spaces from text", "/remove-spaces", "<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" class=\"lucide lucide-space w-6 h-6 text-primary\"><path d=\"M22 17v1c0 .5-.5 1-1 1H3c-.5 0-1-.5-1-1v-1\"></path></svg>"),
143-
new Tool("Remove Line Breaks", "Convert multi-line text to single line", "", "<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" class=\"lucide lucide-scissors w-6 h-6 text-muted-foreground\"><circle cx=\"6\" cy=\"6\" r=\"3\"></circle><path d=\"M8.12 8.12 12 12\"></path><path d=\"M20 4 8.12 15.88\"></path><circle cx=\"6\" cy=\"18\" r=\"3\"></circle><path d=\"M14.8 14.8 20 20\"></path></svg>", IsComingSoon: true),
144-
new Tool("Find & Replace", "Search and replace text patterns", "", "<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" class=\"lucide lucide-replace w-6 h-6 text-muted-foreground\"><path d=\"M14 4a2 2 0 0 1 2-2\"></path><path d=\"M16 10a2 2 0 0 1-2-2\"></path><path d=\"M20 2a2 2 0 0 1 2 2\"></path><path d=\"M22 8a2 2 0 0 1-2 2\"></path><path d=\"m3 7 3 3 3-3\"></path><path d=\"M6 10V5a3 3 0 0 1 3-3h1\"></path><rect x=\"2\" y=\"14\" width=\"8\" height=\"8\" rx=\"2\"></rect></svg>", IsComingSoon: true)
145-
};
36+
_jsonLdContent = JsonLdService.GenerateHomePageJsonLd();
14637
}
147-
}
38+
}

TextHub/Pages/TestJsonLd.razor

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
@page "/test-jsonld"
2+
@using TextHub.Services
3+
@using TextHub.UIComponent
4+
@inject JsonLdService JsonLdService
5+
6+
<PageTitle>Test JSON-LD - Text Hub</PageTitle>
7+
8+
<DynamicJsonLd JsonLdContent="@_jsonLdContent" Id="test-jsonld" />
9+
10+
<div class="min-h-screen flex flex-col">
11+
<main class="flex-1 py-8 px-4">
12+
<div class="container mx-auto max-w-4xl">
13+
<h1 class="text-4xl font-bold mb-4">JSON-LD Test Page</h1>
14+
<p class="text-xl text-muted-foreground mb-8">This page tests the dynamic JSON-LD generation system.</p>
15+
16+
<div class="bg-card rounded-lg border p-6">
17+
<h2 class="text-2xl font-semibold mb-4">Generated JSON-LD:</h2>
18+
<pre class="bg-muted p-4 rounded text-sm overflow-auto">@_jsonLdContent</pre>
19+
</div>
20+
</div>
21+
</main>
22+
</div>
23+
24+
@code {
25+
private string _jsonLdContent = string.Empty;
26+
27+
protected override void OnInitialized()
28+
{
29+
_jsonLdContent = JsonLdService.GenerateHomePageJsonLd();
30+
}
31+
}

0 commit comments

Comments
 (0)