appview/pages: seo improvements, sitemap, schemae and more #676

open
opened by anirudh.fi targeting master from push-wmkmzrsvlkmk
Changed files
+340 -43
appview
pages
repoinfo
templates
fragments
goodfirstissues
layouts
repo
issues
fragments
pulls
fragments
timeline
state
+46
appview/pages/repoinfo/repoinfo.go
···
package repoinfo
import (
+
"encoding/json"
"fmt"
"path"
"slices"
···
func (r RolesInRepo) IsPushAllowed() bool {
return slices.Contains(r.Roles, "repo:push")
}
+
+
// PrimaryLanguage returns the first (most used) language from a list, or empty string if none
+
func PrimaryLanguage(languages []interface{}) string {
+
if len(languages) == 0 {
+
return ""
+
}
+
+
// Languages are already sorted by percentage in descending order
+
// Just get the first one
+
if firstLang, ok := languages[0].(map[string]interface{}); ok {
+
if name, ok := firstLang["Name"].(string); ok {
+
return name
+
}
+
}
+
+
return ""
+
}
+
+
// StructuredData generates Schema.org JSON-LD structured data for the repository
+
func (r RepoInfo) StructuredData(primaryLanguage string) string {
+
data := map[string]interface{}{
+
"@context": "https://schema.org",
+
"@type": "SoftwareSourceCode",
+
"name": r.Name,
+
"description": r.Description,
+
"codeRepository": "https://tangled.org/" + r.FullName(),
+
"url": "https://tangled.org/" + r.FullName(),
+
"author": map[string]interface{}{
+
"@type": "Person",
+
"name": r.owner(),
+
"url": "https://tangled.org/" + r.owner(),
+
},
+
}
+
+
// Add programming language if available
+
if primaryLanguage != "" {
+
data["programmingLanguage"] = primaryLanguage
+
}
+
+
jsonBytes, err := json.Marshal(data)
+
if err != nil {
+
return "{}"
+
}
+
return string(jsonBytes)
+
}
+22
appview/pages/templates/fragments/breadcrumb.html
···
+
{{ define "fragments/breadcrumb" }}
+
{{ $items := . }}
+
{{ if gt (len $items) 0 }}
+
<script type="application/ld+json">
+
{
+
"@context": "https://schema.org",
+
"@type": "BreadcrumbList",
+
"itemListElement": [
+
{{ range $idx, $item := $items }}
+
{{ if gt $idx 0 }},{{ end }}
+
{
+
"@type": "ListItem",
+
"position": {{ add $idx 1 }},
+
"name": "{{ index $item 0 }}",
+
"item": "{{ index $item 1 }}"
+
}
+
{{ end }}
+
]
+
}
+
</script>
+
{{ end }}
+
{{ end }}
+44
appview/pages/templates/fragments/dolly/logo.svg
···
+
<svg
+
version="1.1"
+
id="svg1"
+
width="25"
+
height="25"
+
viewBox="0 0 25 25"
+
sodipodi:docname="tangled_dolly_face_only.png"
+
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+
xmlns:xlink="http://www.w3.org/1999/xlink"
+
xmlns="http://www.w3.org/2000/svg"
+
xmlns:svg="http://www.w3.org/2000/svg">
+
<title>Dolly</title>
+
<defs
+
id="defs1" />
+
<sodipodi:namedview
+
id="namedview1"
+
pagecolor="#ffffff"
+
bordercolor="#000000"
+
borderopacity="0.25"
+
inkscape:showpageshadow="2"
+
inkscape:pageopacity="0.0"
+
inkscape:pagecheckerboard="true"
+
inkscape:deskcolor="#d5d5d5">
+
<inkscape:page
+
x="0"
+
y="0"
+
width="25"
+
height="25"
+
id="page2"
+
margin="0"
+
bleed="0" />
+
</sodipodi:namedview>
+
<g
+
inkscape:groupmode="layer"
+
inkscape:label="Image"
+
id="g1">
+
<path
+
fill="currentColor"
+
style="stroke-width:0.111183"
+
d="m 16.348974,24.09935 -0.06485,-0.03766 -0.202005,-0.0106 -0.202008,-0.01048 -0.275736,-0.02601 -0.275734,-0.02602 v -0.02649 -0.02648 l -0.204577,-0.04019 -0.204578,-0.04019 -0.167616,-0.08035 -0.167617,-0.08035 -0.0014,-0.04137 -0.0014,-0.04137 -0.266473,-0.143735 -0.266475,-0.143735 -0.276098,-0.20335 -0.2761,-0.203347 -0.262064,-0.251949 -0.262064,-0.25195 -0.22095,-0.284628 -0.220948,-0.284629 -0.170253,-0.284631 -0.170252,-0.284628 -0.01341,-0.0144 -0.0134,-0.0144 -0.141982,0.161297 -0.14198,0.1613 -0.22313,0.21426 -0.223132,0.214264 -0.186025,0.146053 -0.186023,0.14605 -0.252501,0.163342 -0.252502,0.163342 -0.249014,0.115348 -0.249013,0.115336 0.0053,0.03241 0.0053,0.03241 -0.1716725,0.04599 -0.171669,0.046 -0.3379966,0.101058 -0.3379972,0.101058 -0.1778925,0.04506 -0.1778935,0.04508 -0.3913655,0.02601 -0.3913643,0.02603 -0.3557868,-0.03514 -0.3557863,-0.03514 -0.037426,-0.03029 -0.037427,-0.03029 -0.076924,0.02011 -0.076924,0.02011 -0.050508,-0.05051 -0.050405,-0.05056 L 6.6604532,23.110188 6.451745,23.063961 6.1546135,22.960559 5.8574835,22.857156 5.5319879,22.694039 5.2064938,22.530922 4.8793922,22.302961 4.5522905,22.075005 4.247598,21.786585 3.9429055,21.49817 3.7185335,21.208777 3.4941628,20.919385 3.3669822,20.705914 3.239803,20.492443 3.1335213,20.278969 3.0272397,20.065499 2.9015252,19.7275 2.7758105,19.389504 2.6925225,18.998139 2.6092345,18.606774 2.6096814,17.91299 2.6101284,17.219208 2.6744634,16.90029 2.7387984,16.581374 2.8474286,16.242088 2.9560588,15.9028 3.1137374,15.583492 3.2714148,15.264182 3.3415068,15.150766 3.4115988,15.03735 3.3127798,14.96945 3.2139618,14.90157 3.0360685,14.800239 2.8581753,14.698908 2.5913347,14.503228 2.3244955,14.307547 2.0621238,14.055599 1.7997507,13.803651 1.6111953,13.56878 1.4226411,13.333906 1.2632237,13.087474 1.1038089,12.841042 0.97442,12.575195 0.8450307,12.30935 0.724603,11.971351 0.6041766,11.633356 0.52150365,11.241991 0.4388285,10.850626 0.44091592,10.156842 0.44300333,9.4630594 0.54235911,9.0369608 0.6417149,8.6108622 0.7741173,8.2694368 0.9065196,7.9280115 1.0736303,7.6214262 1.2407515,7.3148397 1.45931,7.0191718 1.6778685,6.7235039 1.9300326,6.4611321 2.1821966,6.1987592 2.4134579,6.0137228 2.6447193,5.8286865 2.8759792,5.6776409 3.1072406,5.526594 3.4282004,5.3713977 3.7491603,5.2162016 3.9263009,5.1508695 4.1034416,5.0855373 4.2813348,4.7481598 4.4592292,4.4107823 4.6718,4.108422 4.8843733,3.8060618 5.198353,3.4805372 5.5123313,3.155014 5.7685095,2.9596425 6.0246877,2.7642722 6.329187,2.5851365 6.6336863,2.406002 6.9497657,2.2751596 7.2658453,2.1443184 7.4756394,2.0772947 7.6854348,2.01027 8.0825241,1.931086 8.4796139,1.851902 l 0.5870477,0.00291 0.5870469,0.00291 0.4447315,0.092455 0.444734,0.092455 0.302419,0.1105495 0.302417,0.1105495 0.329929,0.1646046 0.32993,0.1646033 0.239329,-0.2316919 0.239329,-0.2316919 0.160103,-0.1256767 0.160105,-0.1256767 0.160102,-0.1021909 0.160105,-0.1021899 0.142315,-0.082328 0.142314,-0.082328 0.231262,-0.1090091 0.231259,-0.1090091 0.26684,-0.098743 0.266839,-0.098743 0.320208,-0.073514 0.320209,-0.073527 0.355787,-0.041833 0.355785,-0.041834 0.426942,0.023827 0.426945,0.023828 0.355785,0.071179 0.355788,0.0711791 0.284627,0.09267 0.284629,0.09267 0.28514,0.1310267 0.28514,0.1310255 0.238179,0.1446969 0.238174,0.1446979 0.259413,0.1955332 0.259413,0.1955319 0.290757,0.296774 0.290758,0.2967753 0.151736,0.1941581 0.151734,0.1941594 0.135326,0.2149951 0.135327,0.2149952 0.154755,0.3202073 0.154758,0.3202085 0.09409,0.2677358 0.09409,0.267737 0.06948,0.3319087 0.06948,0.3319099 0.01111,0.00808 0.01111,0.00808 0.444734,0.2173653 0.444734,0.2173665 0.309499,0.2161102 0.309497,0.2161101 0.309694,0.2930023 0.309694,0.2930037 0.18752,0.2348726 0.187524,0.2348727 0.166516,0.2574092 0.166519,0.2574108 0.15273,0.3260252 0.152734,0.3260262 0.08972,0.2668403 0.08971,0.2668391 0.08295,0.3913655 0.08295,0.3913652 -6.21e-4,0.6582049 -6.21e-4,0.658204 -0.06362,0.315725 -0.06362,0.315725 -0.09046,0.289112 -0.09046,0.289112 -0.122759,0.281358 -0.12276,0.281356 -0.146626,0.252323 -0.146629,0.252322 -0.190443,0.258668 -0.190448,0.258671 -0.254911,0.268356 -0.254911,0.268355 -0.286872,0.223127 -0.286874,0.223127 -0.320203,0.187693 -0.320209,0.187693 -0.04347,0.03519 -0.04347,0.03521 0.0564,0.12989 0.0564,0.129892 0.08728,0.213472 0.08728,0.213471 0.189755,0.729363 0.189753,0.729362 0.0652,0.302417 0.0652,0.302419 -0.0018,0.675994 -0.0018,0.675995 -0.0801,0.373573 -0.08009,0.373577 -0.09,0.266839 -0.09,0.26684 -0.190389,0.391364 -0.19039,0.391366 -0.223169,0.320207 -0.223167,0.320209 -0.303585,0.315294 -0.303584,0.315291 -0.284631,0.220665 -0.284629,0.220663 -0.220128,0.132359 -0.220127,0.132358 -0.242395,0.106698 -0.242394,0.106699 -0.08895,0.04734 -0.08895,0.04733 -0.249052,0.07247 -0.24905,0.07247 -0.322042,0.0574 -0.322044,0.0574 -0.282794,-0.003 -0.282795,-0.003 -0.07115,-0.0031 -0.07115,-0.0031 -0.177894,-0.0033 -0.177893,-0.0033 -0.124528,0.02555 -0.124528,0.02555 z m -4.470079,-5.349839 0.214838,-0.01739 0.206601,-0.06782 0.206602,-0.06782 0.244389,-0.117874 0.244393,-0.11786 0.274473,-0.206822 0.27447,-0.20682 0.229308,-0.257201 0.229306,-0.2572 0.219161,-0.28463 0.219159,-0.284629 0.188541,-0.284628 0.188543,-0.28463 0.214594,-0.373574 0.214593,-0.373577 0.133861,-0.312006 0.133865,-0.312007 0.02861,-0.01769 0.02861,-0.01769 0.197275,0.26212 0.197278,0.262119 0.163613,0.150814 0.163614,0.150814 0.201914,0.09276 0.201914,0.09276 0.302417,0.01421 0.302418,0.01421 0.213472,-0.08025 0.213471,-0.08025 0.200606,-0.204641 0.200606,-0.204642 0.09242,-0.278887 0.09241,-0.278888 0.05765,-0.302418 0.05764,-0.302416 L 18.41327,13.768114 18.39502,13.34117 18.31849,12.915185 18.24196,12.4892 18.15595,12.168033 18.06994,11.846867 17.928869,11.444534 17.787801,11.042201 17.621278,10.73296 17.454757,10.423723 17.337388,10.263619 17.220021,10.103516 17.095645,9.9837986 16.971268,9.8640816 16.990048,9.6813736 17.008828,9.4986654 16.947568,9.249616 16.886308,9.0005655 16.752419,8.7159355 16.618521,8.4313217 16.435707,8.2294676 16.252892,8.0276114 16.079629,7.9004245 15.906366,7.773238 l -0.20429,0.1230127 -0.204289,0.1230121 -0.26702,0.059413 -0.267022,0.059413 -0.205761,-0.021508 -0.205766,-0.021508 -0.23495,-0.08844 -0.234953,-0.08844 -0.118429,-0.090334 -0.118428,-0.090333 h -0.03944 -0.03944 L 13.711268,7.8540732 13.655958,7.9706205 13.497227,8.1520709 13.338499,8.3335203 13.168394,8.4419112 12.998289,8.550301 12.777045,8.624223 12.5558,8.698155 H 12.275611 11.995429 L 11.799973,8.6309015 11.604513,8.5636472 11.491311,8.5051061 11.37811,8.446565 11.138172,8.2254579 10.898231,8.0043497 l -0.09565,-0.084618 -0.09565,-0.084613 -0.218822,0.198024 -0.218822,0.1980231 -0.165392,0.078387 -0.1653925,0.078387 -0.177894,0.047948 -0.177892,0.047948 L 9.3635263,8.4842631 9.144328,8.4846889 8.9195029,8.4147138 8.6946778,8.3447386 8.5931214,8.4414036 8.491565,8.5380686 8.3707618,8.7019598 8.2499597,8.8658478 8.0802403,8.9290726 7.9105231,8.9922974 7.7952769,9.0780061 7.6800299,9.1637148 7.5706169,9.2778257 7.4612038,9.3919481 7.1059768,9.9205267 6.7507497,10.449105 l -0.2159851,0.449834 -0.2159839,0.449834 -0.2216572,0.462522 -0.2216559,0.462523 -0.1459343,0.337996 -0.1459342,0.337998 -0.055483,0.220042 -0.055483,0.220041 -0.015885,0.206903 -0.015872,0.206901 0.034307,0.242939 0.034307,0.24294 0.096281,0.196632 0.096281,0.196634 0.143607,0.125222 0.1436071,0.125222 0.1873143,0.08737 0.1873141,0.08737 0.2752084,0.002 0.2752084,0.002 0.2312297,-0.09773 0.231231,-0.09772 0.1067615,-0.07603 0.1067614,-0.07603 0.3679062,-0.29377 0.3679065,-0.293771 0.026804,0.01656 0.026804,0.01656 0.023626,0.466819 0.023626,0.466815 0.088326,0.513195 0.088326,0.513193 0.08897,0.364413 0.08897,0.364411 0.1315362,0.302418 0.1315352,0.302418 0.1051964,0.160105 0.1051954,0.160103 0.1104741,0.11877 0.1104731,0.118769 0.2846284,0.205644 0.2846305,0.205642 0.144448,0.07312 0.144448,0.07312 0.214787,0.05566 0.214787,0.05566 0.245601,0.03075 0.245602,0.03075 0.204577,-0.0125 0.204578,-0.0125 z m 0.686342,-3.497495 -0.11281,-0.06077 -0.106155,-0.134033 -0.106155,-0.134031 -0.04406,-0.18371 -0.04406,-0.183707 0.02417,-0.553937 0.02417,-0.553936 0.03513,-0.426945 0.03513,-0.426942 0.07225,-0.373576 0.07225,-0.373575 0.05417,-0.211338 0.05417,-0.211339 0.0674,-0.132112 0.0674,-0.132112 0.132437,-0.10916 0.132437,-0.109161 0.187436,-0.04195 0.187438,-0.04195 0.170366,0.06469 0.170364,0.06469 0.114312,0.124073 0.114313,0.124086 0.04139,0.18495 0.04139,0.184951 -0.111218,0.459845 -0.111219,0.459844 -0.03383,0.26584 -0.03382,0.265841 -0.03986,0.818307 -0.03986,0.818309 -0.0378,0.15162 -0.03779,0.151621 -0.11089,0.110562 -0.110891,0.110561 -0.114489,0.04913 -0.114489,0.04913 -0.187932,-0.0016 -0.187929,-0.0016 z m -2.8087655,-0.358124 -0.146445,-0.06848 -0.088025,-0.119502 -0.088024,-0.119502 -0.038581,-0.106736 -0.038581,-0.106736 -0.02237,-0.134956 -0.02239,-0.134957 -0.031955,-0.46988 -0.031955,-0.469881 0.036203,-0.444733 0.036203,-0.444731 0.048862,-0.215257 0.048862,-0.215255 0.076082,-0.203349 0.076081,-0.203348 0.0936,-0.111244 0.0936,-0.111245 0.143787,-0.06531 0.1437865,-0.06532 h 0.142315 0.142314 l 0.142314,0.06588 0.142316,0.06588 0.093,0.102325 0.093,0.102325 0.04042,0.120942 0.04042,0.120942 v 0.152479 0.152477 l -0.03347,0.08804 -0.03347,0.08805 -0.05693,0.275653 -0.05693,0.275651 2.11e-4,0.430246 2.12e-4,0.430243 0.04294,0.392646 0.04295,0.392647 -0.09189,0.200702 -0.09189,0.200702 -0.148688,0.0984 -0.148687,0.0984 -0.20136,0.01212 -0.2013595,0.01212 z"
+
id="path4" />
+
</g>
+
</svg>
+27 -2
appview/pages/templates/goodfirstissues/index.html
···
{{ define "title" }}good first issues{{ end }}
{{ define "extrameta" }}
+
<meta name="description" content="Discover beginner-friendly good first issues across open source projects on Tangled. Perfect for new contributors looking to get started with open source development." />
+
<meta name="keywords" content="good first issues, beginner issues, open source contribution, first time contributor, beginner friendly, open source projects" />
+
<meta property="og:title" content="good first issues · tangled" />
-
<meta property="og:type" content="object" />
+
<meta property="og:type" content="website" />
<meta property="og:url" content="https://tangled.org/goodfirstissues" />
-
<meta property="og:description" content="Find good first issues to contribute to open source projects" />
+
<meta property="og:description" content="Find beginner-friendly issues across all repositories to get started with open source contributions on Tangled." />
+
+
<meta name="twitter:card" content="summary" />
+
<meta name="twitter:title" content="good first issues · tangled" />
+
<meta name="twitter:description" content="Find beginner-friendly issues to get started with open source contributions." />
+
+
<!-- structured data for good first issues page -->
+
<script type="application/ld+json">
+
{
+
"@context": "https://schema.org",
+
"@type": "CollectionPage",
+
"name": "Good First Issues",
+
"description": "A curated collection of beginner-friendly issues across open source projects",
+
"url": "https://tangled.org/goodfirstissues",
+
"isPartOf": {
+
"@type": "WebSite",
+
"name": "Tangled",
+
"url": "https://tangled.org"
+
}
+
}
+
</script>
{{ end }}
+
{{ define "canonical" }}https://tangled.org/goodfirstissues{{ end }}
+
{{ define "content" }}
<div class="grid grid-cols-10">
<header class="col-span-full md:col-span-10 px-6 py-2 text-center flex flex-col items-center justify-center py-8">
+26 -2
appview/pages/templates/layouts/base.html
···
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
-
<meta name="description" content="Social coding, but for real this time!"/>
+
<meta name="description" content="tightly-knit social coding"/>
+
<meta name="keywords" content="git hosting, social coding, version control, pull requests, CI/CD, code collaboration, open source, decentralized"/>
<meta name="htmx-config" content='{"includeIndicatorStyles": false}'>
+
<meta name="author" content="Tangled"/>
+
+
<!-- Canonical URL -->
+
<link rel="canonical" href="{{ block "canonical" . }}https://tangled.org{{ .Request.URL.Path }}{{ end }}" />
<script defer src="/static/htmx.min.js"></script>
<script defer src="/static/htmx-ext-ws.min.js"></script>
···
<link rel="preconnect" href="https://avatar.tangled.sh" />
<link rel="preconnect" href="https://camo.tangled.sh" />
+
<!-- RSS Feed Discovery -->
+
{{ block "rss" . }}{{ end }}
+
<!-- pwa manifest -->
<link rel="manifest" href="/pwa-manifest.json" />
···
<link rel="preload" href="/static/fonts/InterVariable.woff2" as="font" type="font/woff2" crossorigin />
<link rel="stylesheet" href="/static/tw.css?{{ cssContentHash }}" type="text/css" />
-
<title>{{ block "title" . }}{{ end }} · tangled</title>
+
<title>{{ block "title" . }}{{ end }}</title>
+
+
<!-- Structured Data -->
+
{{ block "structuredData" . }}
+
<script type="application/ld+json">
+
{
+
"@context": "https://schema.org",
+
"@type": "Organization",
+
"name": "Tangled",
+
"url": "https://tangled.org",
+
"logo": "https://tangled.org/favicon.svg",
+
"description": "tightly-knit social coding",
+
"sameAs": []
+
}
+
</script>
+
{{ end }}
+
{{ block "extrameta" . }}{{ end }}
</head>
<body class="min-h-screen flex flex-col gap-4 bg-slate-100 dark:bg-gray-900 dark:text-white transition-colors duration-200">
+20 -1
appview/pages/templates/layouts/profilebase.html
···
<meta property="og:image" content="{{ $avatarUrl }}" />
<meta property="og:image:width" content="512" />
<meta property="og:image:height" content="512" />
-
+
<meta name="twitter:card" content="summary" />
<meta name="twitter:title" content="{{ $handle }}" />
<meta name="twitter:description" content="{{ or .Card.Profile.Description $handle }}" />
<meta name="twitter:image" content="{{ $avatarUrl }}" />
+
+
<!-- structured data for user profile -->
+
<script type="application/ld+json">
+
{
+
"@context": "https://schema.org",
+
"@type": "Person",
+
"name": "{{ or .Card.Profile.DisplayName .Card.UserHandle .Card.UserDid }}",
+
"url": "https://tangled.org/{{ or .Card.UserHandle .Card.UserDid }}",
+
"image": "{{ $avatarUrl }}",
+
"description": "{{ .Card.Profile.Description }}"{{ if .Card.UserHandle }},
+
"identifier": "{{ .Card.UserHandle }}"{{ end }}
+
}
+
</script>
+
{{ end }}
+
+
{{ define "canonical" }}https://tangled.org/{{ or .Card.UserHandle .Card.UserDid }}{{ end }}
+
+
{{ define "rss" }}
+
<link rel="alternate" type="application/atom+xml" title="{{ or .Card.UserHandle .Card.UserDid }} Activity Feed" href="https://tangled.org/{{ or .Card.UserHandle .Card.UserDid }}/feed.atom" />
{{ end }}
{{ define "content" }}
+36
appview/pages/templates/repo/index.html
···
{{ template "repo/fragments/meta" . }}
{{ template "repo/fragments/og" (dict "RepoInfo" .RepoInfo) }}
+
+
<!-- Structured Data for Repository -->
+
<script type="application/ld+json">
+
{
+
"@context": "https://schema.org",
+
"@type": "SoftwareSourceCode",
+
"name": "{{ .RepoInfo.Name }}",
+
"description": "{{ .RepoInfo.Description }}",
+
"codeRepository": "https://tangled.org/{{ .RepoInfo.FullName }}",
+
"programmingLanguage": {{ if .Languages }}{{ range $idx, $lang := .Languages }}{{ if eq $idx 0 }}"{{ $lang.Name }}"{{ end }}{{ end }}{{ else }}"Unknown"{{ end }},
+
"url": "https://tangled.org/{{ .RepoInfo.FullName }}",
+
"author": {
+
"@type": "Person",
+
"name": "{{ .RepoInfo.OwnerWithAt }}",
+
"url": "https://tangled.org/{{ .RepoInfo.OwnerWithAt }}"
+
}{{ if .RepoInfo.Source }},
+
"isBasedOn": {
+
"@type": "SoftwareSourceCode",
+
"name": "{{ .RepoInfo.Source.Name }}",
+
"url": "https://tangled.org/{{ didOrHandle .RepoInfo.Source.Did .RepoInfo.SourceHandle }}/{{ .RepoInfo.Source.Name }}"
+
}{{ end }}
+
}
+
</script>
+
+
<!-- Breadcrumb Navigation -->
+
{{ template "fragments/breadcrumb" (list
+
(list "Home" "https://tangled.org")
+
(list .RepoInfo.OwnerWithAt (printf "https://tangled.org/%s" .RepoInfo.OwnerWithAt))
+
(list .RepoInfo.Name (printf "https://tangled.org/%s" .RepoInfo.FullName))
+
) }}
+
{{ end }}
+
+
{{ define "canonical" }}https://tangled.org/{{ .RepoInfo.FullName }}{{ end }}
+
+
{{ define "rss" }}
+
<link rel="alternate" type="application/atom+xml" title="{{ .RepoInfo.FullName }} Activity Feed" href="https://tangled.org/{{ .RepoInfo.FullName }}/feed.atom" />
{{ end }}
{{ define "repoContent" }}
-19
appview/pages/templates/repo/issues/fragments/og.html
···
-
{{ define "repo/issues/fragments/og" }}
-
{{ $title := printf "%s #%d" .Issue.Title .Issue.IssueId }}
-
{{ $description := or .Issue.Body .RepoInfo.Description }}
-
{{ $url := printf "https://tangled.org/%s/issues/%d" .RepoInfo.FullName .Issue.IssueId }}
-
{{ $imageUrl := printf "https://tangled.org/%s/issues/%d/opengraph" .RepoInfo.FullName .Issue.IssueId }}
-
-
<meta property="og:title" content="{{ unescapeHtml $title }}" />
-
<meta property="og:type" content="object" />
-
<meta property="og:url" content="{{ $url }}" />
-
<meta property="og:description" content="{{ $description }}" />
-
<meta property="og:image" content="{{ $imageUrl }}" />
-
<meta property="og:image:width" content="1200" />
-
<meta property="og:image:height" content="600" />
-
-
<meta name="twitter:card" content="summary_large_image" />
-
<meta name="twitter:title" content="{{ unescapeHtml $title }}" />
-
<meta name="twitter:description" content="{{ $description }}" />
-
<meta name="twitter:image" content="{{ $imageUrl }}" />
-
{{ end }}
+16 -16
appview/pages/templates/repo/pulls/fragments/og.html
···
-
{{ define "repo/pulls/fragments/og" }}
-
{{ $title := printf "%s #%d" .Pull.Title .Pull.PullId }}
-
{{ $description := or .Pull.Body .RepoInfo.Description }}
-
{{ $url := printf "https://tangled.org/%s/pulls/%d" .RepoInfo.FullName .Pull.PullId }}
-
{{ $imageUrl := printf "https://tangled.org/%s/pulls/%d/opengraph" .RepoInfo.FullName .Pull.PullId }}
+
{{ define "pulls/fragments/og" }}
+
{{ $title := printf "%s #%d" .Pull.Title .Pull.PullId }}
+
{{ $description := or .Pull.Body .RepoInfo.Description }}
+
{{ $url := printf "https://tangled.org/%s/pulls/%d" .RepoInfo.FullName .Pull.PullId }}
+
{{ $imageUrl := printf "https://tangled.org/%s/pulls/%d/opengraph" .RepoInfo.FullName .Pull.PullId }}
-
<meta property="og:title" content="{{ unescapeHtml $title }}" />
-
<meta property="og:type" content="object" />
-
<meta property="og:url" content="{{ $url }}" />
-
<meta property="og:description" content="{{ $description }}" />
-
<meta property="og:image" content="{{ $imageUrl }}" />
-
<meta property="og:image:width" content="1200" />
-
<meta property="og:image:height" content="600" />
+
<meta property="og:title" content="{{ unescapeHtml $title }}" />
+
<meta property="og:type" content="object" />
+
<meta property="og:url" content="{{ $url }}" />
+
<meta property="og:description" content="{{ $description }}" />
+
<meta property="og:image" content="{{ $imageUrl }}" />
+
<meta property="og:image:width" content="1200" />
+
<meta property="og:image:height" content="600" />
-
<meta name="twitter:card" content="summary_large_image" />
-
<meta name="twitter:title" content="{{ unescapeHtml $title }}" />
-
<meta name="twitter:description" content="{{ $description }}" />
-
<meta name="twitter:image" content="{{ $imageUrl }}" />
+
<meta name="twitter:card" content="summary_large_image" />
+
<meta name="twitter:title" content="{{ unescapeHtml $title }}" />
+
<meta name="twitter:description" content="{{ $description }}" />
+
<meta name="twitter:image" content="{{ $imageUrl }}" />
{{ end }}
+49 -3
appview/pages/templates/timeline/home.html
···
{{ define "title" }}tangled &middot; tightly-knit social coding{{ end }}
{{ define "extrameta" }}
-
<meta property="og:title" content="timeline · tangled" />
-
<meta property="og:type" content="object" />
+
{{ $desc := "Collaborate on code with decentralized git hosting, modern contribution and review workflows, and lightweight CI/CD pipelines." }}
+
{{ $title = "tangled · tightly-knit social coding" }}
+
+
<meta name="description" content="{{ $desc }}" />
+
<meta property="og:title" content="{{ $title }}" />
+
<meta property="og:type" content="website" />
<meta property="og:url" content="https://tangled.org" />
-
<meta property="og:description" content="tightly-knit social coding" />
+
<meta property="og:description" content="Decentralized git hosting with improved pull requests and lightweight CI/CD. Host repositories on your own infrastructure." />
+
<meta property="og:image" content="https://assets.tangled.network/tangled_og.png" />
+
<meta property="og:image:width" content="1200" />
+
<meta property="og:image:height" content="630" />
+
+
<meta name="twitter:card" content="summary_large_image" />
+
<meta name="twitter:title" content="{{ $title }}" />
+
<meta name="twitter:description" content="{{ $desc }}" />
+
<meta name="twitter:image" content="https://assets.tangled.network/tangled_og.png" />
+
+
<!-- Enhanced Structured Data for Homepage -->
+
<script type="application/ld+json">
+
{
+
"@context": "https://schema.org",
+
"@type": "WebSite",
+
"name": "Tangled",
+
"alternateName": "Tangled",
+
"url": "https://tangled.org",
+
"description": "{{ $desc }}",
+
"potentialAction": {
+
"@type": "SearchAction",
+
"target": "https://tangled.org/?q={search_term_string}",
+
"query-input": "required name=search_term_string"
+
}
+
}
+
</script>
+
<script type="application/ld+json">
+
{
+
"@context": "https://schema.org",
+
"@type": "SoftwareApplication",
+
"name": "Tangled",
+
"applicationCategory": "DeveloperTool",
+
"offers": {
+
"@type": "Offer",
+
"price": "0",
+
"priceCurrency": "USD"
+
},
+
"operatingSystem": "Web",
+
"description": "{{ $desc }}"
+
}
+
</script>
{{ end }}
+
{{ define "canonical" }}https://tangled.org{{ end }}
+
{{ define "content" }}
<div class="flex flex-col gap-4">
+1
appview/state/router.go
···
router.Get("/favicon.ico", s.Favicon)
router.Get("/pwa-manifest.json", s.PWAManifest)
router.Get("/robots.txt", s.RobotsTxt)
+
router.Get("/sitemap.xml", s.Sitemap)
userRouter := s.UserRouter(&middleware)
standardRouter := s.StandardRouter(&middleware)
+53
appview/state/state.go
···
robotsTxt := `User-agent: *
Allow: /
+
Disallow: /settings
+
Disallow: /notifications
+
Disallow: /login
+
Disallow: /logout
+
Disallow: /signup
+
Disallow: /oauth
+
Disallow: */settings$
+
Disallow: */settings/*
+
+
Crawl-delay: 1
+
+
Sitemap: https://tangled.org/sitemap.xml
`
w.Write([]byte(robotsTxt))
}
+
func (s *State) Sitemap(w http.ResponseWriter, r *http.Request) {
+
w.Header().Set("Content-Type", "application/xml; charset=utf-8")
+
w.Header().Set("Cache-Control", "public, max-age=3600")
+
+
// basic sitemap with static pages
+
sitemap := `<?xml version="1.0" encoding="UTF-8"?>
+
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
+
<url>
+
<loc>https://tangled.org</loc>
+
<changefreq>daily</changefreq>
+
<priority>1.0</priority>
+
</url>
+
<url>
+
<loc>https://tangled.org/timeline</loc>
+
<changefreq>hourly</changefreq>
+
<priority>0.9</priority>
+
</url>
+
<url>
+
<loc>https://tangled.org/goodfirstissues</loc>
+
<changefreq>daily</changefreq>
+
<priority>0.8</priority>
+
</url>
+
<url>
+
<loc>https://tangled.org/terms</loc>
+
<changefreq>monthly</changefreq>
+
<priority>0.3</priority>
+
</url>
+
<url>
+
<loc>https://tangled.org/privacy</loc>
+
<changefreq>monthly</changefreq>
+
<priority>0.3</priority>
+
</url>
+
<url>
+
<loc>https://tangled.org/brand</loc>
+
<changefreq>monthly</changefreq>
+
<priority>0.5</priority>
+
</url>
+
</urlset>`
+
w.Write([]byte(sitemap))
+
}
+
// https://developer.mozilla.org/en-US/docs/Web/Progressive_web_apps/Manifest
const manifestJson = `{
"name": "tangled",