feat: finalize provider parity and SEO/frontend route coverage

This commit is contained in:
Dwindi Ramadhana
2026-02-04 09:32:25 +07:00
parent a4d2031117
commit 0c45435db9
14 changed files with 550 additions and 57 deletions

View File

@@ -97,6 +97,11 @@ class SiteController extends Controller
return view('site.pricing');
}
public function support(): View
{
return view('site.support');
}
public function privacy(): View
{
return view('site.privacy');
@@ -143,6 +148,59 @@ class SiteController extends Controller
]);
}
public function robotsTxt(): Response
{
$base = rtrim(config('app.url', request()->getSchemeAndHttpHost()), '/');
$body = "User-agent: *\nAllow: /\n\nSitemap: ".$base."/sitemap.xml\n";
return response($body, 200)->header('Content-Type', 'text/plain; charset=UTF-8');
}
public function sitemapXml(): Response
{
$data = $this->loadDataset();
$items = is_array($data['emojis'] ?? null) ? $data['emojis'] : [];
$base = rtrim(config('app.url', request()->getSchemeAndHttpHost()), '/');
$lastUpdatedTs = isset($data['last_updated_ts']) ? (int) $data['last_updated_ts'] : time();
$lastUpdated = gmdate('Y-m-d\TH:i:s\Z', $lastUpdatedTs);
$urls = [
['loc' => $base.'/', 'priority' => '0.8', 'changefreq' => 'daily'],
['loc' => $base.'/api-docs', 'priority' => '0.5', 'changefreq' => 'weekly'],
['loc' => $base.'/pricing', 'priority' => '0.7', 'changefreq' => 'weekly'],
['loc' => $base.'/privacy', 'priority' => '0.3', 'changefreq' => 'monthly'],
['loc' => $base.'/terms', 'priority' => '0.3', 'changefreq' => 'monthly'],
['loc' => $base.'/support', 'priority' => '0.4', 'changefreq' => 'weekly'],
];
foreach ($items as $item) {
$slug = trim((string) ($item['slug'] ?? ''));
if ($slug === '' || $this->shouldHideForSitemap($item)) {
continue;
}
$urls[] = [
'loc' => $base.'/emoji/'.$slug,
'priority' => '0.6',
'changefreq' => 'weekly',
];
}
$xml = '<?xml version="1.0" encoding="UTF-8"?>'."\n";
$xml .= '<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">'."\n";
foreach ($urls as $url) {
$xml .= " <url>\n";
$xml .= ' <loc>'.htmlspecialchars((string) $url['loc'], ENT_XML1)."</loc>\n";
$xml .= ' <lastmod>'.$lastUpdated."</lastmod>\n";
$xml .= ' <changefreq>'.$url['changefreq']."</changefreq>\n";
$xml .= ' <priority>'.$url['priority']."</priority>\n";
$xml .= " </url>\n";
}
$xml .= '</urlset>'."\n";
return response($xml, 200)->header('Content-Type', 'application/xml; charset=UTF-8');
}
/**
* @return array<string,string>
*/
@@ -155,4 +213,72 @@ class SiteController extends Controller
return $out;
}
/**
* @return array<string,mixed>
*/
private function loadDataset(): array
{
$dataPath = (string) config('dewemoji.data_path');
if (!is_file($dataPath)) {
return ['emojis' => []];
}
$raw = file_get_contents($dataPath);
if ($raw === false) {
return ['emojis' => []];
}
$decoded = json_decode($raw, true);
if (!is_array($decoded)) {
return ['emojis' => []];
}
return $decoded;
}
/**
* @param array<string,mixed> $emoji
*/
private function shouldHideForSitemap(array $emoji): bool
{
$name = strtolower(trim((string) ($emoji['name'] ?? '')));
$category = strtolower(trim((string) ($emoji['category'] ?? '')));
$subcategory = strtolower(trim((string) ($emoji['subcategory'] ?? '')));
if ($subcategory === 'family' || str_starts_with($name, 'family:')) {
return true;
}
if (preg_match('~\bwoman: beard\b~i', $name)) {
return true;
}
if (preg_match('~\bmen with bunny ears\b~i', $name)) {
return true;
}
if (preg_match('~\bpregnant man\b~i', $name)) {
return true;
}
if ($category === 'people & body') {
if (preg_match('~\bmen holding hands\b~i', $name)) {
return true;
}
if (preg_match('~\bwomen holding hands\b~i', $name)) {
return true;
}
if (preg_match('~kiss:.*\bman,\s*man\b~i', $name)) {
return true;
}
if (preg_match('~kiss:.*\bwoman,\s*woman\b~i', $name)) {
return true;
}
if (preg_match('~couple.*\bman,\s*man\b~i', $name)) {
return true;
}
if (preg_match('~couple.*\bwoman,\s*woman\b~i', $name)) {
return true;
}
}
return false;
}
}