init
This commit is contained in:
14
.gitignore
vendored
Normal file
14
.gitignore
vendored
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
/tmp
|
||||||
|
/claude.md
|
||||||
|
/CLAUDE.md
|
||||||
|
.claude
|
||||||
|
.DS_Store
|
||||||
|
.env
|
||||||
|
/envs/knot
|
||||||
|
/envs/appview
|
||||||
|
/deploy.yml
|
||||||
|
/install.zsh
|
||||||
|
/keys
|
||||||
|
/data
|
||||||
|
/repositories
|
||||||
|
/server
|
||||||
44
compose.yml
Normal file
44
compose.yml
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
services:
|
||||||
|
redis:
|
||||||
|
image: redis:alpine
|
||||||
|
restart: always
|
||||||
|
volumes:
|
||||||
|
- ./data/redis:/data
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD", "redis-cli", "ping", "|", "grep", "PONG"]
|
||||||
|
interval: 1s
|
||||||
|
timeout: 5s
|
||||||
|
retries: 5
|
||||||
|
|
||||||
|
knot:
|
||||||
|
build:
|
||||||
|
context: ./repos/knot-docker/
|
||||||
|
args:
|
||||||
|
UID: 1000
|
||||||
|
GID: 1000
|
||||||
|
restart: always
|
||||||
|
ports:
|
||||||
|
- "2588:5555"
|
||||||
|
- "2222:22"
|
||||||
|
volumes:
|
||||||
|
- ./keys:/etc/ssh/keys
|
||||||
|
- ./repositories:/home/git/repositories
|
||||||
|
- ./server:/app
|
||||||
|
env_file:
|
||||||
|
- ./envs/knot
|
||||||
|
|
||||||
|
appview:
|
||||||
|
build:
|
||||||
|
context: .
|
||||||
|
dockerfile: docker/appview/Dockerfile
|
||||||
|
target: appview
|
||||||
|
restart: always
|
||||||
|
ports:
|
||||||
|
- "2589:3000"
|
||||||
|
volumes:
|
||||||
|
- ./data/appview:/data
|
||||||
|
env_file:
|
||||||
|
- ./envs/appview
|
||||||
|
depends_on:
|
||||||
|
redis:
|
||||||
|
condition: service_healthy
|
||||||
49
docker/appview/Dockerfile
Normal file
49
docker/appview/Dockerfile
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
FROM golang:1.25-bookworm AS builder
|
||||||
|
RUN apt-get update && apt-get install -y git gcc libc6-dev nodejs npm curl unzip && rm -rf /var/lib/apt/lists/*
|
||||||
|
WORKDIR /build
|
||||||
|
COPY repos/core/ .
|
||||||
|
|
||||||
|
# static assets required for go:embed
|
||||||
|
RUN mkdir -p appview/pages/static/fonts appview/pages/static/icons appview/pages/static/logos
|
||||||
|
|
||||||
|
# JS
|
||||||
|
RUN curl -sLo appview/pages/static/htmx.min.js https://unpkg.com/htmx.org@2.0.4/dist/htmx.min.js && \
|
||||||
|
curl -sLo appview/pages/static/htmx-ext-ws.min.js https://unpkg.com/htmx-ext-ws@2.0.2/ws.js && \
|
||||||
|
curl -sLo appview/pages/static/mermaid.min.js https://cdn.jsdelivr.net/npm/mermaid@11/dist/mermaid.min.js && \
|
||||||
|
touch appview/pages/static/actor-typeahead.js
|
||||||
|
|
||||||
|
# Fonts
|
||||||
|
RUN curl -sLo /tmp/inter.zip https://github.com/rsms/inter/releases/download/v4.1/Inter-4.1.zip && \
|
||||||
|
cd /tmp && unzip -q inter.zip -d inter && \
|
||||||
|
find /tmp/inter -name 'InterVariable*.woff2' -exec cp {} /build/appview/pages/static/fonts/ \; && \
|
||||||
|
find /tmp/inter -name 'InterDisplay*.woff2' -exec cp {} /build/appview/pages/static/fonts/ \; || true
|
||||||
|
|
||||||
|
RUN curl -sLo /tmp/plex.zip https://github.com/IBM/plex/releases/download/v6.4.0/IBM-Plex-Mono.zip && \
|
||||||
|
cd /tmp && unzip -q plex.zip -d plex && \
|
||||||
|
find /tmp/plex -name 'IBMPlexMono*.woff2' -exec cp {} /build/appview/pages/static/fonts/ \; || true
|
||||||
|
|
||||||
|
# Lucide icons
|
||||||
|
RUN curl -sLo /tmp/lucide.zip https://github.com/lucide-icons/lucide/releases/download/0.344.0/lucide-icons-0.344.0.zip && \
|
||||||
|
cd /tmp && unzip -q lucide.zip -d lucide && \
|
||||||
|
find /tmp/lucide -name '*.svg' -exec cp {} /build/appview/pages/static/icons/ \; || true
|
||||||
|
|
||||||
|
# Placeholder logos
|
||||||
|
RUN touch appview/pages/static/logos/dolly.png appview/pages/static/logos/dolly.ico appview/pages/static/logos/dolly.svg
|
||||||
|
|
||||||
|
# Custom logos (place files in docker/appview/logos/)
|
||||||
|
COPY docker/appview/logos/ appview/pages/static/logos/
|
||||||
|
|
||||||
|
# Tailwind CSS (v3 - matches tailwind.config.js)
|
||||||
|
RUN cd /build && npm install tailwindcss@3 @tailwindcss/typography && \
|
||||||
|
npx tailwindcss -c tailwind.config.js -i input.css -o appview/pages/static/tw.css --minify 2>&1 && \
|
||||||
|
echo "tw.css size: $(wc -c < appview/pages/static/tw.css) bytes"
|
||||||
|
|
||||||
|
# Build
|
||||||
|
RUN CGO_ENABLED=1 go build -o appview-bin ./cmd/appview/
|
||||||
|
|
||||||
|
# --- AppView ---
|
||||||
|
FROM debian:bookworm-slim AS appview
|
||||||
|
RUN apt-get update && apt-get install -y ca-certificates && rm -rf /var/lib/apt/lists/*
|
||||||
|
COPY --from=builder /build/appview-bin /usr/local/bin/appview
|
||||||
|
EXPOSE 3000
|
||||||
|
CMD ["appview"]
|
||||||
19
docker/appview/logos/ai.svg
Normal file
19
docker/appview/logos/ai.svg
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1024 1024" width="1024" height="1024">
|
||||||
|
<path fill-rule="evenodd" fill="#F6E717" d="
|
||||||
|
M 619,232
|
||||||
|
L 512,7
|
||||||
|
L 405,232
|
||||||
|
A 300,300 0 0,0 216,559
|
||||||
|
L 75,765
|
||||||
|
L 323,745
|
||||||
|
A 300,300 0 0,0 701,745
|
||||||
|
L 949,765
|
||||||
|
L 808,559
|
||||||
|
A 300,300 0 0,0 619,232
|
||||||
|
Z
|
||||||
|
M 512,337
|
||||||
|
A 175,175 0 0,0 512,687
|
||||||
|
A 175,175 0 0,0 512,337
|
||||||
|
Z
|
||||||
|
"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 413 B |
41
envs/appview.example
Normal file
41
envs/appview.example
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
# core
|
||||||
|
TANGLED_APPVIEW_HOST=git.example.com
|
||||||
|
TANGLED_APPVIEW_NAME=Example Git
|
||||||
|
TANGLED_DB_PATH=/data/appview.db
|
||||||
|
TANGLED_LISTEN_ADDR=0.0.0.0:3000
|
||||||
|
TANGLED_DEV=false
|
||||||
|
TANGLED_COOKIE_SECRET=change-me-32-char-random-string!
|
||||||
|
|
||||||
|
# at protocol
|
||||||
|
TANGLED_PLC_URL=https://plc.directory
|
||||||
|
TANGLED_JETSTREAM_ENDPOINT=wss://jetstream1.us-east.bsky.network/subscribe
|
||||||
|
|
||||||
|
# oauth (generate with: goat key generate -t P-256)
|
||||||
|
TANGLED_OAUTH_CLIENT_SECRET=z-multibase-p256-secret-key
|
||||||
|
TANGLED_OAUTH_CLIENT_KID=1234567890
|
||||||
|
|
||||||
|
# redis
|
||||||
|
TANGLED_REDIS_ADDR=tangled-redis:6379
|
||||||
|
# TANGLED_REDIS_PASS=
|
||||||
|
# TANGLED_REDIS_DB=0
|
||||||
|
|
||||||
|
# labels (empty for self-host, default requires tangled.sh DID)
|
||||||
|
TANGLED_LABEL_DEFAULTS=
|
||||||
|
TANGLED_LABEL_GFI=
|
||||||
|
|
||||||
|
# email (optional, uses resend.com)
|
||||||
|
# TANGLED_RESEND_API_KEY=re_xxxxx
|
||||||
|
# TANGLED_RESEND_SENT_FROM=noreply@example.com
|
||||||
|
|
||||||
|
# optional services
|
||||||
|
# TANGLED_CAMO_HOST=https://camo.example.com
|
||||||
|
# TANGLED_CAMO_SHARED_SECRET=
|
||||||
|
# TANGLED_AVATAR_HOST=https://avatar.example.com
|
||||||
|
# TANGLED_AVATAR_SHARED_SECRET=
|
||||||
|
# TANGLED_PDS_HOST=https://pds.example.com
|
||||||
|
# TANGLED_PDS_ADMIN_SECRET=
|
||||||
|
# TANGLED_CLOUDFLARE_API_TOKEN=
|
||||||
|
# TANGLED_CLOUDFLARE_ZONE_ID=
|
||||||
|
# TANGLED_CLOUDFLARE_TURNSTILE_SITE_KEY=
|
||||||
|
# TANGLED_CLOUDFLARE_TURNSTILE_SECRET_KEY=
|
||||||
|
# TANGLED_POSTHOG_API_KEY=
|
||||||
16
envs/knot.example
Normal file
16
envs/knot.example
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
# required
|
||||||
|
KNOT_SERVER_HOSTNAME=knot.example.com
|
||||||
|
KNOT_SERVER_OWNER=did:plc:xxxxx
|
||||||
|
|
||||||
|
# network
|
||||||
|
KNOT_SERVER_JETSTREAM_ENDPOINT=wss://jetstream.example.com/subscribe
|
||||||
|
APPVIEW_ENDPOINT=http://appview:3000
|
||||||
|
|
||||||
|
# optional (defaults shown)
|
||||||
|
# KNOT_SERVER_LISTEN_ADDR=0.0.0.0:5555
|
||||||
|
# KNOT_SERVER_INTERNAL_LISTEN_ADDR=0.0.0.0:5444
|
||||||
|
# KNOT_SERVER_DB_PATH=/app/knotserver.db
|
||||||
|
# KNOT_REPO_SCAN_PATH=/home/git/repositories
|
||||||
|
# KNOT_REPO_MAIN_BRANCH=main
|
||||||
|
# KNOT_SERVER_DEV=false
|
||||||
|
# KNOT_SERVER_LOG_DIDS=true
|
||||||
52
patching/100-appview-avatar-pds-blob.patch
Normal file
52
patching/100-appview-avatar-pds-blob.patch
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
--- a/appview/pages/funcmap.go
|
||||||
|
+++ b/appview/pages/funcmap.go
|
||||||
|
@@ -505,34 +505,26 @@
|
||||||
|
did = identity.DID.String()
|
||||||
|
}
|
||||||
|
|
||||||
|
- secret := p.avatar.SharedSecret
|
||||||
|
- h := hmac.New(sha256.New, []byte(secret))
|
||||||
|
- h.Write([]byte(did))
|
||||||
|
- signature := hex.EncodeToString(h.Sum(nil))
|
||||||
|
-
|
||||||
|
- // Get avatar CID for cache busting
|
||||||
|
+ // Get avatar CID from profile DB
|
||||||
|
profile, err := db.GetProfile(p.db, did)
|
||||||
|
- version := ""
|
||||||
|
- if err == nil && profile != nil && profile.Avatar != "" {
|
||||||
|
- // Use first 8 chars of avatar CID as version
|
||||||
|
- if len(profile.Avatar) > 8 {
|
||||||
|
- version = profile.Avatar[:8]
|
||||||
|
- } else {
|
||||||
|
- version = profile.Avatar
|
||||||
|
+ if err == nil && profile != nil && profile.Avatar != "" && identity != nil {
|
||||||
|
+ // Get PDS endpoint from DID document
|
||||||
|
+ if svc, ok := identity.Services["atproto_pds"]; ok {
|
||||||
|
+ pdsUrl := strings.TrimRight(svc.URL, "/")
|
||||||
|
+ return fmt.Sprintf("%s/xrpc/com.atproto.sync.getBlob?did=%s&cid=%s", pdsUrl, did, profile.Avatar)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- baseUrl := fmt.Sprintf("%s/%s/%s", p.avatar.Host, signature, did)
|
||||||
|
- if size != "" {
|
||||||
|
- if version != "" {
|
||||||
|
- return fmt.Sprintf("%s?size=%s&v=%s", baseUrl, size, version)
|
||||||
|
- }
|
||||||
|
- return fmt.Sprintf("%s?size=%s", baseUrl, size)
|
||||||
|
+ // Fallback to avatar proxy if configured
|
||||||
|
+ if p.avatar.Host != "" && p.avatar.SharedSecret != "" {
|
||||||
|
+ secret := p.avatar.SharedSecret
|
||||||
|
+ h := hmac.New(sha256.New, []byte(secret))
|
||||||
|
+ h.Write([]byte(did))
|
||||||
|
+ signature := hex.EncodeToString(h.Sum(nil))
|
||||||
|
+ return fmt.Sprintf("%s/%s/%s", p.avatar.Host, signature, did)
|
||||||
|
}
|
||||||
|
- if version != "" {
|
||||||
|
- return fmt.Sprintf("%s?v=%s", baseUrl, version)
|
||||||
|
- }
|
||||||
|
- return baseUrl
|
||||||
|
+
|
||||||
|
+ return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *Pages) icon(name string, classes []string) (template.HTML, error) {
|
||||||
114
patching/110-appview-custom-footer.patch
Normal file
114
patching/110-appview-custom-footer.patch
Normal file
@@ -0,0 +1,114 @@
|
|||||||
|
--- a/appview/pages/templates/layouts/fragments/footer.html 2026-03-10 19:59:35
|
||||||
|
+++ b/appview/pages/templates/layouts/fragments/footer.html 2026-03-10 20:00:03
|
||||||
|
@@ -1,102 +1,13 @@
|
||||||
|
{{ define "layouts/fragments/footer" }}
|
||||||
|
-<div class="w-full p-8 bg-white dark:bg-gray-800">
|
||||||
|
- <div class="mx-auto px-4">
|
||||||
|
- <div class="flex flex-col text-gray-600 dark:text-gray-400 gap-8">
|
||||||
|
- <!-- Desktop layout: grid with 3 columns -->
|
||||||
|
- <div class="hidden lg:grid lg:grid-cols-[1fr_minmax(0,1024px)_1fr] lg:gap-8 lg:items-start">
|
||||||
|
- <!-- Left section -->
|
||||||
|
- <div>
|
||||||
|
- <a href="/" hx-boost="true" class="flex gap-2 font-semibold italic no-underline hover:no-underline">
|
||||||
|
- {{ template "fragments/logotypeSmall" }}
|
||||||
|
- </a>
|
||||||
|
- </div>
|
||||||
|
-
|
||||||
|
- {{ $headerStyle := "text-gray-900 dark:text-gray-200 font-bold text-sm uppercase tracking-wide mb-1" }}
|
||||||
|
- {{ $linkStyle := "text-gray-500 dark:text-gray-400 hover:text-gray-900 dark:hover:text-gray-200 hover:underline inline-flex gap-1 items-center" }}
|
||||||
|
- {{ $iconStyle := "w-4 h-4 flex-shrink-0" }}
|
||||||
|
-
|
||||||
|
- <!-- Center section with max-width -->
|
||||||
|
- <div class="grid grid-cols-4 gap-2">
|
||||||
|
- <div class="flex flex-col gap-1">
|
||||||
|
- <div class="{{ $headerStyle }}">legal</div>
|
||||||
|
- <a href="/terms" class="{{ $linkStyle }}">{{ i "file-text" $iconStyle }} terms of service</a>
|
||||||
|
- <a href="/privacy" class="{{ $linkStyle }}">{{ i "shield" $iconStyle }} privacy policy</a>
|
||||||
|
- </div>
|
||||||
|
-
|
||||||
|
- <div class="flex flex-col gap-1">
|
||||||
|
- <div class="{{ $headerStyle }}">resources</div>
|
||||||
|
- <a href="https://blog.tangled.org" class="{{ $linkStyle }}" target="_blank" rel="noopener noreferrer">{{ i "book-open" $iconStyle }} blog</a>
|
||||||
|
- <a href="https://docs.tangled.org" class="{{ $linkStyle }}">{{ i "book" $iconStyle }} docs</a>
|
||||||
|
- <a href="https://tangled.org/@tangled.org/core" class="{{ $linkStyle }}">{{ i "code" $iconStyle }} source</a>
|
||||||
|
- <a href="https://tangled.org/brand" class="{{ $linkStyle }}">{{ i "paintbrush" $iconStyle }} brand</a>
|
||||||
|
- </div>
|
||||||
|
-
|
||||||
|
- <div class="flex flex-col gap-1">
|
||||||
|
- <div class="{{ $headerStyle }}">social</div>
|
||||||
|
- <a href="https://chat.tangled.org" class="{{ $linkStyle }}" target="_blank" rel="noopener noreferrer">{{ i "message-circle" $iconStyle }} discord</a>
|
||||||
|
- <a href="https://web.libera.chat/#tangled" class="{{ $linkStyle }}" target="_blank" rel="noopener noreferrer">{{ i "hash" $iconStyle }} irc</a>
|
||||||
|
- <a href="https://bsky.app/profile/tangled.org" class="{{ $linkStyle }}" target="_blank" rel="noopener noreferrer">{{ template "user/fragments/bluesky" $iconStyle }} bluesky</a>
|
||||||
|
- </div>
|
||||||
|
-
|
||||||
|
- <div class="flex flex-col gap-1">
|
||||||
|
- <div class="{{ $headerStyle }}">contact</div>
|
||||||
|
- <a href="mailto:team@tangled.org" class="{{ $linkStyle }}">{{ i "mail" "w-4 h-4 flex-shrink-0" }} team@tangled.org</a>
|
||||||
|
- <a href="mailto:security@tangled.org" class="{{ $linkStyle }}">{{ i "shield-check" "w-4 h-4 flex-shrink-0" }} security@tangled.org</a>
|
||||||
|
- </div>
|
||||||
|
- </div>
|
||||||
|
-
|
||||||
|
- <!-- Right section -->
|
||||||
|
- <div class="text-right">
|
||||||
|
- <div class="text-xs">© 2026 Tangled Labs Oy. All rights reserved.</div>
|
||||||
|
- </div>
|
||||||
|
- </div>
|
||||||
|
-
|
||||||
|
- <!-- Mobile layout: stacked -->
|
||||||
|
- <div class="lg:hidden flex flex-col gap-8">
|
||||||
|
- {{ $headerStyle := "text-gray-900 dark:text-gray-200 font-bold text-xs uppercase tracking-wide mb-1" }}
|
||||||
|
- {{ $linkStyle := "text-gray-500 dark:text-gray-400 hover:text-gray-900 dark:hover:text-gray-200 hover:underline inline-flex gap-1 items-center" }}
|
||||||
|
- {{ $iconStyle := "w-4 h-4 flex-shrink-0" }}
|
||||||
|
-
|
||||||
|
- <div class="mb-4 md:mb-0">
|
||||||
|
- <a href="/" hx-boost="true" class="flex gap-2 font-semibold italic no-underline hover:no-underline">
|
||||||
|
- {{ template "fragments/logotypeSmall" }}
|
||||||
|
- </a>
|
||||||
|
- </div>
|
||||||
|
-
|
||||||
|
- <div class="grid grid-cols-1 sm:grid-cols-1 md:grid-cols-4 sm:gap-6 md:gap-2 gap-6">
|
||||||
|
- <div class="flex flex-col gap-1">
|
||||||
|
- <div class="{{ $headerStyle }}">legal</div>
|
||||||
|
- <a href="/terms" class="{{ $linkStyle }}">{{ i "file-text" $iconStyle }} terms of service</a>
|
||||||
|
- <a href="/privacy" class="{{ $linkStyle }}">{{ i "shield" $iconStyle }} privacy policy</a>
|
||||||
|
- </div>
|
||||||
|
-
|
||||||
|
- <div class="flex flex-col gap-1">
|
||||||
|
- <div class="{{ $headerStyle }}">resources</div>
|
||||||
|
- <a href="https://blog.tangled.org" class="{{ $linkStyle }}" target="_blank" rel="noopener noreferrer">{{ i "book-open" $iconStyle }} blog</a>
|
||||||
|
- <a href="https://docs.tangled.org" class="{{ $linkStyle }}">{{ i "book" $iconStyle }} docs</a>
|
||||||
|
- <a href="https://tangled.org/@tangled.org/core" class="{{ $linkStyle }}">{{ i "code" $iconStyle }} source</a>
|
||||||
|
- <a href="https://tangled.org/brand" class="{{ $linkStyle }}">{{ i "paintbrush" $iconStyle }} brand</a>
|
||||||
|
- </div>
|
||||||
|
-
|
||||||
|
- <div class="flex flex-col gap-1">
|
||||||
|
- <div class="{{ $headerStyle }}">social</div>
|
||||||
|
- <a href="https://chat.tangled.org" class="{{ $linkStyle }}" target="_blank" rel="noopener noreferrer">{{ i "message-circle" $iconStyle }} discord</a>
|
||||||
|
- <a href="https://web.libera.chat/#tangled" class="{{ $linkStyle }}" target="_blank" rel="noopener noreferrer">{{ i "hash" $iconStyle }} irc</a>
|
||||||
|
- <a href="https://bsky.app/profile/tangled.org" class="{{ $linkStyle }}" target="_blank" rel="noopener noreferrer">{{ template "user/fragments/bluesky" $iconStyle }} bluesky</a>
|
||||||
|
- </div>
|
||||||
|
-
|
||||||
|
- <div class="flex flex-col gap-1">
|
||||||
|
- <div class="{{ $headerStyle }}">contact</div>
|
||||||
|
- <a href="mailto:team@tangled.org" class="{{ $linkStyle }}">{{ i "mail" "w-4 h-4 flex-shrink-0" }} team@tangled.org</a>
|
||||||
|
- <a href="mailto:security@tangled.org" class="{{ $linkStyle }}">{{ i "shield-check" "w-4 h-4 flex-shrink-0" }} security@tangled.org</a>
|
||||||
|
- </div>
|
||||||
|
- </div>
|
||||||
|
-
|
||||||
|
- <div class="text-center">
|
||||||
|
- <div class="text-xs">© 2026 Tangled Labs Oy. All rights reserved.</div>
|
||||||
|
- </div>
|
||||||
|
- </div>
|
||||||
|
- </div>
|
||||||
|
+<div class="w-full py-6 bg-white dark:bg-gray-800">
|
||||||
|
+ <div class="mx-auto px-4 flex items-center justify-center gap-4 text-sm text-gray-500 dark:text-gray-400">
|
||||||
|
+ <a href="https://tangled.org/@tangled.org" class="hover:text-gray-900 dark:hover:text-gray-200 hover:underline inline-flex gap-1 items-center">
|
||||||
|
+ {{ i "code" "w-4 h-4" }} tangled
|
||||||
|
+ </a>
|
||||||
|
+ <span class="text-gray-300 dark:text-gray-600">|</span>
|
||||||
|
+ <a href="https://tangled.org/@tangled.org/core/blob/master/license" class="hover:text-gray-900 dark:hover:text-gray-200 hover:underline inline-flex gap-1 items-center">
|
||||||
|
+ {{ i "file-text" "w-4 h-4" }} license
|
||||||
|
+ </a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{{ end }}
|
||||||
15
patching/120-appview-custom-header-logo.patch
Normal file
15
patching/120-appview-custom-header-logo.patch
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
--- a/appview/pages/templates/fragments/logotypeSmall.html 2026-03-10 20:00:17
|
||||||
|
+++ b/appview/pages/templates/fragments/logotypeSmall.html 2026-03-10 20:00:23
|
||||||
|
@@ -1,9 +1,9 @@
|
||||||
|
{{ define "fragments/logotypeSmall" }}
|
||||||
|
<span class="flex items-center gap-2">
|
||||||
|
- {{ template "fragments/dolly/logo" (dict "Classes" "size-8 text-black dark:text-white")}}
|
||||||
|
- <span class="font-bold text-xl not-italic">tangled</span>
|
||||||
|
+ <img src="/static/logos/ai.svg" alt="logo" class="size-8" />
|
||||||
|
+ <span class="font-bold text-xl not-italic">git</span>
|
||||||
|
<span class="font-normal not-italic text-xs rounded bg-gray-100 dark:bg-gray-700 px-1">
|
||||||
|
- alpha
|
||||||
|
+ syu.is
|
||||||
|
</span>
|
||||||
|
<span>
|
||||||
|
{{ end }}
|
||||||
18
readme.md
Normal file
18
readme.md
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
# tangled
|
||||||
|
|
||||||
|
git + atproto
|
||||||
|
|
||||||
|
1. start knot (knot.example.com)
|
||||||
|
2. `tangled.org` oauth login (user.bsky.social)
|
||||||
|
3. `knot.example.com` verifiyed
|
||||||
|
|
||||||
|
- https://docs.tangled.org/spindles.html#self-hosting-guide
|
||||||
|
|
||||||
|
## self-hosting
|
||||||
|
|
||||||
|
1. knot, `git clone https://tangled.org/tangled.org/knot-docker`
|
||||||
|
2. appviewe, `git clone https://tangled.org/tangled.org/infra`
|
||||||
|
|
||||||
|
## lexicon
|
||||||
|
|
||||||
|
`at://did:plc:6qyecktefllvenje24fcxnie/sh.tangled.knot/knot.syu.is`
|
||||||
Reference in New Issue
Block a user