diff --git a/app/Http/Controllers/ToolController.php b/app/Http/Controllers/ToolController.php
index d0a6454..682b4c9 100644
--- a/app/Http/Controllers/ToolController.php
+++ b/app/Http/Controllers/ToolController.php
@@ -147,6 +147,12 @@ public function index(): View
'route' => 'tools.diff',
'icon' => 'diff',
],
+ [
+ 'name' => 'Sort Lines',
+ 'description' => 'Sort, deduplicate, reverse, and shuffle lines',
+ 'route' => 'tools.sort-lines',
+ 'icon' => 'sort',
+ ],
];
return view('home', compact('tools'));
@@ -266,4 +272,9 @@ public function diff(): View
{
return view('tools.diff');
}
+
+ public function sortLines(): View
+ {
+ return view('tools.sort-lines');
+ }
}
diff --git a/resources/views/home.blade.php b/resources/views/home.blade.php
index 4e1851a..972ddb3 100644
--- a/resources/views/home.blade.php
+++ b/resources/views/home.blade.php
@@ -151,6 +151,11 @@
@break
+ @case('sort')
+
+ @break
@endswitch
diff --git a/resources/views/tools/sort-lines.blade.php b/resources/views/tools/sort-lines.blade.php
new file mode 100644
index 0000000..ba2cd1d
--- /dev/null
+++ b/resources/views/tools/sort-lines.blade.php
@@ -0,0 +1,351 @@
+@extends('layouts.app')
+
+@section('title', 'Sort Lines - Sort, Dedupe, Reverse, Shuffle Text | Dev Tools')
+@section('meta_description', 'Free online line sorter. Sort lines alphabetically, numerically, remove duplicates, reverse order, or shuffle randomly. Fast and private - no data stored.')
+@section('meta_keywords', 'sort lines, line sorter, sort text, remove duplicates, dedupe lines, reverse lines, shuffle lines, alphabetical sort, natural sort')
+
+@push('schema')
+
+@endpush
+
+@section('content')
+
+
+
+
Sort Lines
+
Sort, deduplicate, reverse, and shuffle text lines
+
+
← Back
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ lines
+ unique
+ duplicates
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Quick Actions
+
+
+
+
+
+
+
+
+
+
+@endsection
+
+@push('scripts')
+
+@endpush
diff --git a/routes/web.php b/routes/web.php
index 63e04f2..de71750 100644
--- a/routes/web.php
+++ b/routes/web.php
@@ -29,6 +29,7 @@
Route::get('/jwt', [ToolController::class, 'jwt'])->name('jwt');
Route::get('/timestamp', [ToolController::class, 'timestamp'])->name('timestamp');
Route::get('/diff', [ToolController::class, 'diff'])->name('diff');
+ Route::get('/sort-lines', [ToolController::class, 'sortLines'])->name('sort-lines');
});
// Static Pages
@@ -62,6 +63,7 @@
['loc' => route('tools.jwt'), 'priority' => '0.8', 'changefreq' => 'monthly'],
['loc' => route('tools.timestamp'), 'priority' => '0.8', 'changefreq' => 'monthly'],
['loc' => route('tools.diff'), 'priority' => '0.8', 'changefreq' => 'monthly'],
+ ['loc' => route('tools.sort-lines'), 'priority' => '0.8', 'changefreq' => 'monthly'],
['loc' => route('about'), 'priority' => '0.5', 'changefreq' => 'monthly'],
['loc' => route('privacy'), 'priority' => '0.3', 'changefreq' => 'yearly'],
];
diff --git a/tests/Feature/WebRoutesTest.php b/tests/Feature/WebRoutesTest.php
index d99e52e..b4c1203 100644
--- a/tests/Feature/WebRoutesTest.php
+++ b/tests/Feature/WebRoutesTest.php
@@ -41,6 +41,7 @@ public function test_home_page_displays_all_tools(): void
$response->assertSee('JWT Decoder');
$response->assertSee('Timestamp Converter');
$response->assertSee('Diff Checker');
+ $response->assertSee('Sort Lines');
}
public function test_home_page_has_tool_links(): void
@@ -70,6 +71,7 @@ public function test_home_page_has_tool_links(): void
$response->assertSee('href="' . route('tools.jwt') . '"', false);
$response->assertSee('href="' . route('tools.timestamp') . '"', false);
$response->assertSee('href="' . route('tools.diff') . '"', false);
+ $response->assertSee('href="' . route('tools.sort-lines') . '"', false);
}
public function test_csv_tool_page_loads(): void
@@ -516,9 +518,30 @@ public function test_diff_tool_has_required_elements(): void
$response->assertSee('Compare');
}
+ public function test_sort_lines_page_loads(): void
+ {
+ $response = $this->get('/tools/sort-lines');
+
+ $response->assertStatus(200);
+ $response->assertSee('Sort Lines');
+ $response->assertSee('Sort, deduplicate, reverse, and shuffle text lines');
+ }
+
+ public function test_sort_lines_has_required_elements(): void
+ {
+ $response = $this->get('/tools/sort-lines');
+
+ $response->assertStatus(200);
+ $response->assertSee('Input Text');
+ $response->assertSee('Sort Options');
+ $response->assertSee('Sort A-Z');
+ $response->assertSee('Remove Duplicates');
+ $response->assertSee('Shuffle');
+ }
+
public function test_all_pages_have_navigation(): void
{
- $pages = ['/', '/tools/csv', '/tools/yaml', '/tools/markdown', '/tools/sql', '/tools/base64', '/tools/uuid', '/tools/hash', '/tools/url', '/tools/code-editor', '/tools/regex', '/tools/base-converter', '/tools/slug-generator', '/tools/color-picker', '/tools/qr-code', '/tools/html-entity', '/tools/text-case', '/tools/password', '/tools/lorem', '/tools/cron', '/tools/jwt', '/tools/timestamp', '/tools/diff'];
+ $pages = ['/', '/tools/csv', '/tools/yaml', '/tools/markdown', '/tools/sql', '/tools/base64', '/tools/uuid', '/tools/hash', '/tools/url', '/tools/code-editor', '/tools/regex', '/tools/base-converter', '/tools/slug-generator', '/tools/color-picker', '/tools/qr-code', '/tools/html-entity', '/tools/text-case', '/tools/password', '/tools/lorem', '/tools/cron', '/tools/jwt', '/tools/timestamp', '/tools/diff', '/tools/sort-lines'];
foreach ($pages as $page) {
$response = $this->get($page);
@@ -530,7 +553,7 @@ public function test_all_pages_have_navigation(): void
public function test_all_pages_have_theme_toggle(): void
{
- $pages = ['/', '/tools/csv', '/tools/yaml', '/tools/markdown', '/tools/sql', '/tools/base64', '/tools/uuid', '/tools/hash', '/tools/url', '/tools/code-editor', '/tools/regex', '/tools/base-converter', '/tools/slug-generator', '/tools/color-picker', '/tools/qr-code', '/tools/html-entity', '/tools/text-case', '/tools/password', '/tools/lorem', '/tools/cron', '/tools/jwt', '/tools/timestamp', '/tools/diff'];
+ $pages = ['/', '/tools/csv', '/tools/yaml', '/tools/markdown', '/tools/sql', '/tools/base64', '/tools/uuid', '/tools/hash', '/tools/url', '/tools/code-editor', '/tools/regex', '/tools/base-converter', '/tools/slug-generator', '/tools/color-picker', '/tools/qr-code', '/tools/html-entity', '/tools/text-case', '/tools/password', '/tools/lorem', '/tools/cron', '/tools/jwt', '/tools/timestamp', '/tools/diff', '/tools/sort-lines'];
foreach ($pages as $page) {
$response = $this->get($page);
@@ -543,7 +566,7 @@ public function test_all_pages_have_theme_toggle(): void
public function test_all_pages_load_vite_assets(): void
{
// Code editor uses standalone template without Vite
- $pages = ['/', '/tools/csv', '/tools/yaml', '/tools/markdown', '/tools/sql', '/tools/base64', '/tools/uuid', '/tools/hash', '/tools/url', '/tools/regex', '/tools/base-converter', '/tools/slug-generator', '/tools/color-picker', '/tools/qr-code', '/tools/html-entity', '/tools/text-case', '/tools/password', '/tools/lorem', '/tools/cron', '/tools/jwt', '/tools/timestamp', '/tools/diff'];
+ $pages = ['/', '/tools/csv', '/tools/yaml', '/tools/markdown', '/tools/sql', '/tools/base64', '/tools/uuid', '/tools/hash', '/tools/url', '/tools/regex', '/tools/base-converter', '/tools/slug-generator', '/tools/color-picker', '/tools/qr-code', '/tools/html-entity', '/tools/text-case', '/tools/password', '/tools/lorem', '/tools/cron', '/tools/jwt', '/tools/timestamp', '/tools/diff', '/tools/sort-lines'];
foreach ($pages as $page) {
$response = $this->get($page);
@@ -556,7 +579,7 @@ public function test_all_pages_load_vite_assets(): void
public function test_all_tool_pages_have_back_link(): void
{
// Code editor uses standalone template with home link instead of back
- $toolPages = ['/tools/csv', '/tools/yaml', '/tools/markdown', '/tools/sql', '/tools/base64', '/tools/uuid', '/tools/hash', '/tools/url', '/tools/regex', '/tools/base-converter', '/tools/slug-generator', '/tools/color-picker', '/tools/qr-code', '/tools/html-entity', '/tools/text-case', '/tools/password', '/tools/lorem', '/tools/cron', '/tools/jwt', '/tools/timestamp', '/tools/diff'];
+ $toolPages = ['/tools/csv', '/tools/yaml', '/tools/markdown', '/tools/sql', '/tools/base64', '/tools/uuid', '/tools/hash', '/tools/url', '/tools/regex', '/tools/base-converter', '/tools/slug-generator', '/tools/color-picker', '/tools/qr-code', '/tools/html-entity', '/tools/text-case', '/tools/password', '/tools/lorem', '/tools/cron', '/tools/jwt', '/tools/timestamp', '/tools/diff', '/tools/sort-lines'];
foreach ($toolPages as $page) {
$response = $this->get($page);
@@ -609,7 +632,7 @@ public function test_api_routes_reject_get_requests(): void
public function test_pages_have_csrf_token(): void
{
- $pages = ['/tools/csv', '/tools/yaml', '/tools/markdown', '/tools/sql', '/tools/base64', '/tools/uuid', '/tools/hash', '/tools/url', '/tools/code-editor', '/tools/regex', '/tools/base-converter', '/tools/slug-generator', '/tools/color-picker', '/tools/qr-code', '/tools/html-entity', '/tools/text-case', '/tools/password', '/tools/lorem', '/tools/cron', '/tools/jwt', '/tools/timestamp', '/tools/diff'];
+ $pages = ['/tools/csv', '/tools/yaml', '/tools/markdown', '/tools/sql', '/tools/base64', '/tools/uuid', '/tools/hash', '/tools/url', '/tools/code-editor', '/tools/regex', '/tools/base-converter', '/tools/slug-generator', '/tools/color-picker', '/tools/qr-code', '/tools/html-entity', '/tools/text-case', '/tools/password', '/tools/lorem', '/tools/cron', '/tools/jwt', '/tools/timestamp', '/tools/diff', '/tools/sort-lines'];
foreach ($pages as $page) {
$response = $this->get($page);