Add basic SEO for the public landing page.
Index the homepage with meta description, Open Graph tags, robots.txt and sitemap; keep private viewer URLs out of search indexes. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -9,7 +9,7 @@ import sys
|
||||
import webbrowser
|
||||
from pathlib import Path
|
||||
|
||||
from flask import Blueprint, Flask, abort, jsonify, render_template, request, send_file, send_from_directory
|
||||
from flask import Blueprint, Flask, Response, abort, jsonify, render_template, request, send_file, send_from_directory
|
||||
from werkzeug.utils import secure_filename
|
||||
|
||||
from advisor import advise_skill
|
||||
@@ -121,6 +121,20 @@ def sw_viewer(viewer_id: str):
|
||||
return _serve_sw()
|
||||
|
||||
|
||||
def _landing_seo() -> dict[str, str]:
|
||||
base = external_base_url()
|
||||
return {
|
||||
"seo_title": "Idle Fantasy Save Viewer",
|
||||
"seo_description": (
|
||||
"Free web viewer for Idle Fantasy game saves. "
|
||||
"Track skills, inventory, quests, goals and snapshot history – no account, private link only."
|
||||
),
|
||||
"seo_url": f"{base}/",
|
||||
"seo_image": f"{base}/static/icon-512.png",
|
||||
"seo_robots": "index, follow",
|
||||
}
|
||||
|
||||
|
||||
@viewer_bp.route("/")
|
||||
def viewer_index(viewer_id: str):
|
||||
_resolve_viewer_db(viewer_id)
|
||||
@@ -128,6 +142,7 @@ def viewer_index(viewer_id: str):
|
||||
"index.html",
|
||||
viewer_id=viewer_id,
|
||||
manifest_href=f"/v/{viewer_id}/manifest.webmanifest",
|
||||
seo_robots="noindex, nofollow",
|
||||
)
|
||||
|
||||
|
||||
@@ -401,9 +416,31 @@ def sw_root():
|
||||
return _serve_sw()
|
||||
|
||||
|
||||
@app.route("/robots.txt")
|
||||
def robots_txt():
|
||||
base = external_base_url()
|
||||
body = f"User-agent: *\nAllow: /\nDisallow: /v/\n\nSitemap: {base}/sitemap.xml\n"
|
||||
return Response(body, mimetype="text/plain")
|
||||
|
||||
|
||||
@app.route("/sitemap.xml")
|
||||
def sitemap_xml():
|
||||
base = external_base_url()
|
||||
xml = f"""<?xml version="1.0" encoding="UTF-8"?>
|
||||
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
|
||||
<url>
|
||||
<loc>{base}/</loc>
|
||||
<changefreq>monthly</changefreq>
|
||||
<priority>1.0</priority>
|
||||
</url>
|
||||
</urlset>
|
||||
"""
|
||||
return Response(xml, mimetype="application/xml")
|
||||
|
||||
|
||||
@app.route("/")
|
||||
def landing():
|
||||
return render_template("landing.html", manifest_href="/manifest.webmanifest")
|
||||
return render_template("landing.html", manifest_href="/manifest.webmanifest", **_landing_seo())
|
||||
|
||||
|
||||
@app.post("/api/viewers")
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
{% if seo_robots %}<meta name="robots" content="{{ seo_robots }}">{% endif %}
|
||||
{% if seo_description %}
|
||||
<meta name="description" content="{{ seo_description }}">
|
||||
<meta property="og:description" content="{{ seo_description }}">
|
||||
<meta name="twitter:description" content="{{ seo_description }}">
|
||||
{% endif %}
|
||||
{% if seo_url %}
|
||||
<link rel="canonical" href="{{ seo_url }}">
|
||||
<meta property="og:url" content="{{ seo_url }}">
|
||||
{% endif %}
|
||||
{% if seo_title %}
|
||||
<meta property="og:title" content="{{ seo_title }}">
|
||||
<meta name="twitter:title" content="{{ seo_title }}">
|
||||
{% endif %}
|
||||
<meta property="og:type" content="website">
|
||||
<meta name="twitter:card" content="summary">
|
||||
{% if seo_image %}<meta property="og:image" content="{{ seo_image }}">{% endif %}
|
||||
@@ -5,6 +5,7 @@
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Idle Fantasy Viewer</title>
|
||||
<link rel="icon" href="/static/favicon.svg" type="image/svg+xml">
|
||||
{% include '_seo_head.html' %}
|
||||
{% include '_pwa_head.html' %}
|
||||
<link rel="stylesheet" href="/static/style.css">
|
||||
{% include '_analytics.html' %}
|
||||
|
||||
@@ -3,8 +3,9 @@
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Idle Fantasy Viewer</title>
|
||||
<title>{{ seo_title | default("Idle Fantasy Save Viewer", true) }} – Skills, Inventory & History</title>
|
||||
<link rel="icon" href="/static/favicon.svg" type="image/svg+xml">
|
||||
{% include '_seo_head.html' %}
|
||||
{% include '_pwa_head.html' %}
|
||||
<link rel="stylesheet" href="/static/style.css">
|
||||
{% include '_analytics.html' %}
|
||||
|
||||
Reference in New Issue
Block a user