mirror of
https://github.com/aljazceru/njump.git
synced 2025-12-17 14:24:27 +01:00
Support embedding profiles in external web pages
prifile design SQUASH
This commit is contained in:
1
data.go
1
data.go
@@ -241,6 +241,7 @@ func grabData(ctx context.Context, code string, isProfileSitemap bool) (*Data, e
|
|||||||
|
|
||||||
switch event.Kind {
|
switch event.Kind {
|
||||||
case 0:
|
case 0:
|
||||||
|
data.templateId = Profile
|
||||||
{
|
{
|
||||||
rawAuthorRelays := []string{}
|
rawAuthorRelays := []string{}
|
||||||
ctx, cancel := context.WithTimeout(ctx, time.Second*4)
|
ctx, cancel := context.WithTimeout(ctx, time.Second*4)
|
||||||
|
|||||||
24
pages.go
24
pages.go
@@ -16,6 +16,7 @@ type TemplateID int
|
|||||||
|
|
||||||
const (
|
const (
|
||||||
Note TemplateID = iota
|
Note TemplateID = iota
|
||||||
|
Profile
|
||||||
LongForm
|
LongForm
|
||||||
TelegramInstantView
|
TelegramInstantView
|
||||||
FileMetadata
|
FileMetadata
|
||||||
@@ -286,6 +287,29 @@ type ProfilePage struct {
|
|||||||
|
|
||||||
func (*ProfilePage) TemplateText() string { return tmplProfile }
|
func (*ProfilePage) TemplateText() string { return tmplProfile }
|
||||||
|
|
||||||
|
var (
|
||||||
|
//go:embed templates/embedded_profile.html
|
||||||
|
tmplEmbeddedProfile string
|
||||||
|
EmbeddedProfileTemplate = tmpl.MustCompile(&EmbeddedProfilePage{})
|
||||||
|
)
|
||||||
|
|
||||||
|
type EmbeddedProfilePage struct {
|
||||||
|
AuthorRelays []string
|
||||||
|
Content string
|
||||||
|
CreatedAt string
|
||||||
|
Domain string
|
||||||
|
Metadata sdk.ProfileMetadata
|
||||||
|
NormalizedAuthorWebsiteURL string
|
||||||
|
RenderedAuthorAboutText template.HTML
|
||||||
|
Nevent string
|
||||||
|
Npub string
|
||||||
|
Nprofile string
|
||||||
|
Proxy string
|
||||||
|
Title string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (*EmbeddedProfilePage) TemplateText() string { return tmplEmbeddedProfile }
|
||||||
|
|
||||||
var (
|
var (
|
||||||
//go:embed templates/file_metadata.html
|
//go:embed templates/file_metadata.html
|
||||||
tmplFileMetadata string
|
tmplFileMetadata string
|
||||||
|
|||||||
@@ -51,6 +51,15 @@ func renderEmbedded(w http.ResponseWriter, r *http.Request, code string) {
|
|||||||
Url: code,
|
Url: code,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
case Profile:
|
||||||
|
err = EmbeddedProfileTemplate.Render(w, &EmbeddedProfilePage{
|
||||||
|
Metadata: data.metadata,
|
||||||
|
NormalizedAuthorWebsiteURL: normalizeWebsiteURL(data.metadata.Website),
|
||||||
|
RenderedAuthorAboutText: template.HTML(basicFormatting(html.EscapeString(data.metadata.About), false, false, true)),
|
||||||
|
Npub: data.npub,
|
||||||
|
Nprofile: data.nprofile,
|
||||||
|
AuthorRelays: data.authorRelays,
|
||||||
|
})
|
||||||
default:
|
default:
|
||||||
log.Error().Int("templateId", int(data.templateId)).Msg("no way to render")
|
log.Error().Int("templateId", int(data.templateId)).Msg("no way to render")
|
||||||
http.Error(w, "tried to render an unsupported template at render_event.go", 500)
|
http.Error(w, "tried to render an unsupported template at render_event.go", 500)
|
||||||
|
|||||||
@@ -59,13 +59,6 @@ func renderEvent(w http.ResponseWriter, r *http.Request) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// render npub and nprofile using a separate function
|
|
||||||
if prefix == "npub" || prefix == "nprofile" {
|
|
||||||
// it's a profile
|
|
||||||
renderProfile(w, r, code)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check if the embed parameter is set to "yes"
|
// Check if the embed parameter is set to "yes"
|
||||||
embedParam := r.URL.Query().Get("embed")
|
embedParam := r.URL.Query().Get("embed")
|
||||||
if embedParam == "yes" {
|
if embedParam == "yes" {
|
||||||
@@ -73,6 +66,13 @@ func renderEvent(w http.ResponseWriter, r *http.Request) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// render npub and nprofile using a separate function
|
||||||
|
if prefix == "npub" || prefix == "nprofile" {
|
||||||
|
// it's a profile
|
||||||
|
renderProfile(w, r, code)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
// get data for this event
|
// get data for this event
|
||||||
data, err := grabData(r.Context(), code, false)
|
data, err := grabData(r.Context(), code, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
144
templates/embedded_profile.html
Normal file
144
templates/embedded_profile.html
Normal file
@@ -0,0 +1,144 @@
|
|||||||
|
<!doctype html>
|
||||||
|
<html class="theme--default text-lg font-light print:text-base sm:text-xl">
|
||||||
|
<meta charset="UTF-8" />
|
||||||
|
<head>
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
|
<link
|
||||||
|
rel="stylesheet"
|
||||||
|
type="text/css"
|
||||||
|
href="/njump/static/tailwind-bundle.min.css"
|
||||||
|
/>
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body
|
||||||
|
class="relative bg-white text-gray-600 dark:bg-neutral-900 dark:text-neutral-50 print:text-black"
|
||||||
|
>
|
||||||
|
<style>
|
||||||
|
::-webkit-scrollbar {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<div
|
||||||
|
class="mx-auto w-full max-w-screen-2xl justify-between gap-10 overflow-visible px-4 pb-4 pt-4 print:w-full sm:w-11/12 md:w-10/12 lg:w-9/12"
|
||||||
|
>
|
||||||
|
<a href="/{{.Npub}}" target="_new" class="no-underline">
|
||||||
|
<div class="w-full break-words">
|
||||||
|
<div class="w-full break-words print:w-full">
|
||||||
|
<header class="mb-4 max-w-full">
|
||||||
|
<div class="flex flex-wrap items-center">
|
||||||
|
<div
|
||||||
|
class="print:basis-1-12 imgclip mr-2 max-w-full basis-1/6 overflow-hidden sm:mr-4 sm:basis-[10%]"
|
||||||
|
>
|
||||||
|
<img
|
||||||
|
class="block h-auto w-full"
|
||||||
|
src="{{.Metadata.Picture}}"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div class="block print:text-base">
|
||||||
|
<div class="text-2xl">{{.Metadata.Name}}</div>
|
||||||
|
{{ if not (eq .Metadata.Name .Metadata.DisplayName) }}
|
||||||
|
<div class="leading-4 text-stone-400">
|
||||||
|
{{.Metadata.DisplayName}}
|
||||||
|
</div>
|
||||||
|
{{ end }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</header>
|
||||||
|
<div dir="auto">
|
||||||
|
{{ if or (not (eq "" .Metadata.Website)) (not (eq ""
|
||||||
|
.RenderedAuthorAboutText)) }}
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="-ml-4 mb-6 h-1.5 w-1/2 bg-zinc-100 dark:bg-zinc-700 sm:-ml-2.5"
|
||||||
|
></div>
|
||||||
|
<div class="mb-6 leading-5">{{.Metadata.Website}}</div>
|
||||||
|
<div
|
||||||
|
class="prose mb-6 leading-5 dark:prose-invert prose-headings:font-light sm:prose-a:text-justify"
|
||||||
|
>
|
||||||
|
{{.RenderedAuthorAboutText}}
|
||||||
|
</div>
|
||||||
|
{{ end }}
|
||||||
|
<div
|
||||||
|
class="-ml-4 mb-6 h-1.5 w-1/3 bg-zinc-100 dark:bg-zinc-700 sm:-ml-2.5"
|
||||||
|
></div>
|
||||||
|
<div class="mb-6 leading-5">
|
||||||
|
<div class="text-sm text-strongpink">Public Key</div>
|
||||||
|
{{.Npub}}
|
||||||
|
</div>
|
||||||
|
<div class="mb-6 leading-5">
|
||||||
|
{{ if not (eq "" .Metadata.NIP05) }}
|
||||||
|
<div class="text-sm text-strongpink">NIP-05 Address</div>
|
||||||
|
{{.Metadata.NIP05}} {{ end }}
|
||||||
|
</div>
|
||||||
|
<div class="mb-6 leading-5">
|
||||||
|
{{ if not (eq "" .Metadata.LUD16) }}
|
||||||
|
<div class="text-sm text-strongpink">NIP-57 Address</div>
|
||||||
|
{{.Metadata.LUD16}} {{ end }}
|
||||||
|
</div>
|
||||||
|
<!-- <div class="mb-6 leading-5">
|
||||||
|
<div class="text-sm text-strongpink">Profile Code</div>
|
||||||
|
{{.Nprofile}}
|
||||||
|
</div> -->
|
||||||
|
|
||||||
|
{{ if not (eq 0 (len .AuthorRelays)) }}
|
||||||
|
<div class="mb-6 leading-5">
|
||||||
|
<div class="text-sm text-strongpink">Publishing to</div>
|
||||||
|
{{range $index, $element := .AuthorRelays}}
|
||||||
|
<span
|
||||||
|
class="mr-1 mt-2 inline-block max-w-full rounded-lg border border-slate-300 px-2 py-0.5"
|
||||||
|
>{{$element}}</span
|
||||||
|
>
|
||||||
|
{{end}}
|
||||||
|
</div>
|
||||||
|
{{ end }}
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="-ml-4 mb-6 h-1.5 w-1/3 bg-zinc-100 dark:bg-zinc-700 sm:-ml-2.5"
|
||||||
|
></div>
|
||||||
|
</div>
|
||||||
|
</a>
|
||||||
|
<div class="text-sm leading-3 text-neutral-400">
|
||||||
|
This note has been published on Nostr and is embedded via Njump,
|
||||||
|
<a href="/" target="_new" class="underline">learn more</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<svg width="0" height="0" version="1.1" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<defs>
|
||||||
|
<clipPath id="svg-shape" clipPathUnits="objectBoundingBox">
|
||||||
|
<path
|
||||||
|
transform="scale(0.005, 0.005)"
|
||||||
|
d="M100,200c43.8,0,68.2,0,84.1-15.9C200,168.2,200,143.8,200,100s0-68.2-15.9-84.1C168.2,0,143.8,0,100,0S31.8,0,15.9,15.9C0,31.8,0,56.2,0,100s0,68.2,15.9,84.1C31.8,200,56.2,200,100,200z"
|
||||||
|
/>
|
||||||
|
</clipPath>
|
||||||
|
</defs>
|
||||||
|
</svg>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
window.addEventListener('load', function () {
|
||||||
|
var contentHeight = document.body.scrollHeight
|
||||||
|
window.parent.postMessage({height: contentHeight}, '*')
|
||||||
|
})
|
||||||
|
|
||||||
|
window.addEventListener('message', function (event) {
|
||||||
|
if (event.data.showGradient) {
|
||||||
|
var gradient = document.getElementById('bottom-gradient')
|
||||||
|
gradient.classList.remove('hidden')
|
||||||
|
}
|
||||||
|
if (event.data.setDarkMode) {
|
||||||
|
document.querySelector('html').classList.add('theme--dark')
|
||||||
|
}
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div
|
||||||
|
id="bottom-gradient"
|
||||||
|
class="pointer-events-none sticky bottom-0 left-0 hidden h-20 w-full bg-gradient-to-b from-transparent to-white dark:to-neutral-900"
|
||||||
|
></div>
|
||||||
|
|
||||||
|
<a href="/" target="_new" class="fixed bottom-2 right-2 w-[100px]"
|
||||||
|
><img src="/njump/static/logo.png"
|
||||||
|
/></a>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
Reference in New Issue
Block a user