| -rw-r--r-- | .github/workflows/build-and-deploy-prod.yml | 102 | ||||
| -rw-r--r-- | .github/workflows/build-and-deploy-stage.yml | 104 | ||||
| -rw-r--r-- | Dockerfile | 9 | ||||
| -rw-r--r-- | Jenkinsfile | 313 | ||||
| -rw-r--r-- | config/config.go | 6 | ||||
| -rw-r--r-- | config/config.prod.yaml | 8 | ||||
| -rw-r--r-- | deploy/playbook.yml | 9 | ||||
| -rw-r--r-- | internal/router/handlers/lang-blog-title.go | 6 | ||||
| -rw-r--r-- | internal/router/handlers/root.go | 7 | ||||
| -rw-r--r-- | internal/router/router.go | 2 | ||||
| -rw-r--r-- | static/input.css | 8 | ||||
| -rw-r--r-- | views/layouts/general-page.html | 37 | ||||
| -rw-r--r-- | views/partials/general-page-header.html | 2 |
13 files changed, 255 insertions, 358 deletions
diff --git a/.github/workflows/build-and-deploy-prod.yml b/.github/workflows/build-and-deploy-prod.yml new file mode 100644 index 0000000..060ae32 --- /dev/null +++ b/.github/workflows/build-and-deploy-prod.yml @@ -0,0 +1,102 @@ +name: Docker image building and publishing onto Production +on: + push: + tags: + - "*" +jobs: + build-and-push: + if: github.repository == 'SayaAndy/saya-today-web' + runs-on: ubuntu-latest + environment: Production + permissions: + packages: write + steps: + - name: Checkout + uses: actions/checkout@v6 + + - name: Generate output.css with tailwindcss + uses: ZoeyVid/tailwindcss-update@main + with: + input: static/input.css + output: static/output.css + params: "--minify" + + - name: Set up QEMU + uses: docker/setup-qemu-action@v4 + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v4 + + - name: Login to GitHub Container Registry + uses: docker/login-action@v4 + with: + registry: ghcr.io + username: ${{ github.repository_owner }} + password: ${{ secrets.GHCR_TOKEN }} + + - name: Build and push + uses: docker/build-push-action@v7 + with: + context: . + file: ./Dockerfile + push: true + cache-from: type=gha + cache-to: type=gha,mode=max + tags: | + ghcr.io/sayaandy/saya-today-web:latest + ghcr.io/sayaandy/saya-today-web:stable + ghcr.io/sayaandy/saya-today-web:${{ github.ref_name }} + + deploy: + if: github.repository == 'SayaAndy/saya-today-web' + runs-on: ubuntu-latest + environment: Production + needs: [build-and-push] + container: + image: ghcr.io/ansible/community-ansible-dev-tools:v26.4.6 + options: --user root + steps: + - name: Checkout + uses: actions/checkout@v6 + + - name: Install community.docker collection + run: ansible-galaxy collection install community.docker + + - name: Set up SSH connection for uz.saya.casa + run: | + mkdir -p ~/.ssh + (cat <<EOF + ${{ secrets.SVC_GITHUB_PK }} + EOF + ) > ~/.ssh/id_ed25519 + chmod 600 ~/.ssh/id_ed25519 + sed -i 's/\r$//' ~/.ssh/id_ed25519 + ssh-keyscan -H uz.saya.casa >> ~/.ssh/known_hosts + + - name: Test SSH connection + run: | + ssh -o ConnectTimeout=10 -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -i ~/.ssh/id_ed25519 svc_github@uz.saya.casa "echo 'SSH connection successful'" + + - name: Run Ansible playbook + env: + ANSIBLE_HOST_KEY_CHECKING: "False" + working-directory: ./deploy + run: | + ansible-playbook \ + playbook.yml \ + -i inventory.yml \ + -l prod \ + --private-key ~/.ssh/id_ed25519 \ + -u svc_github \ + -e saya_today_web_auth_salt="${{ secrets.AUTH_SALT }}" \ + -e saya_today_web_s3_access_key_id="${{ secrets.S3_ACCESS_KEY_ID }}" \ + -e saya_today_web_s3_secret_access_key="${{ secrets.S3_SECRET_ACCESS_KEY }}" \ + -e saya_today_web_environment=prod \ + -e saya_today_web_tag=${{ github.ref_name }} \ + -e saya_today_web_mail_salt="${{ secrets.MAIL_SALT }}" \ + -e saya_today_web_mail_host="${{ secrets.MAIL_HOST }}" \ + -e saya_today_web_mail_address="${{ secrets.MAIL_ADDRESS }}" \ + -e saya_today_web_mail_username="${{ secrets.MAIL_USERNAME }}" \ + -e saya_today_web_mail_password="${{ secrets.MAIL_PASSWORD }}" \ + -e saya_today_google_site_verification="${{ secrets.GOOGLE_SITE_VERIFICATION }}" \ + -e saya_today_yandex_verification="${{ secrets.YANDEX_VERIFICATION }}" diff --git a/.github/workflows/build-and-deploy-stage.yml b/.github/workflows/build-and-deploy-stage.yml new file mode 100644 index 0000000..ce4a1fb --- /dev/null +++ b/.github/workflows/build-and-deploy-stage.yml @@ -0,0 +1,104 @@ +name: Docker image building and publishing onto Stage +on: + push: + branches: [stage] +jobs: + build-and-push: + if: github.repository == 'SayaAndy/saya-today-web' + runs-on: ubuntu-latest + environment: Stage + permissions: + packages: write + outputs: + sha_short: ${{ steps.ghss_vars.outputs.sha_short }} + steps: + - name: Checkout + uses: actions/checkout@v6 + + - name: Generate output.css with tailwindcss + uses: ZoeyVid/tailwindcss-update@main + with: + input: static/input.css + output: static/output.css + params: "--minify" + + - name: Set up QEMU + uses: docker/setup-qemu-action@v4 + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v4 + + - name: Login to GitHub Container Registry + uses: docker/login-action@v4 + with: + registry: ghcr.io + username: ${{ github.repository_owner }} + password: ${{ secrets.GHCR_TOKEN }} + + - name: Set github short sha + id: ghss_vars + run: echo "sha_short=${GITHUB_SHA::7}" >> $GITHUB_OUTPUT + + - name: Build and push + uses: docker/build-push-action@v7 + with: + context: . + file: ./Dockerfile + push: true + cache-from: type=gha + cache-to: type=gha,mode=max + tags: | + ghcr.io/sayaandy/saya-today-web:latest + ghcr.io/sayaandy/saya-today-web:commit-${{ steps.ghss_vars.outputs.sha_short }} + + deploy: + if: github.repository == 'SayaAndy/saya-today-web' + runs-on: ubuntu-latest + environment: Stage + needs: [build-and-push] + container: + image: ghcr.io/ansible/community-ansible-dev-tools:v26.4.6 + options: --user root + steps: + - name: Checkout + uses: actions/checkout@v6 + + - name: Install community.docker collection + run: ansible-galaxy collection install community.docker + + - name: Set up SSH connection for uz.saya.casa + run: | + mkdir -p ~/.ssh + (cat <<EOF + ${{ secrets.SVC_GITHUB_PK }} + EOF + ) > ~/.ssh/id_ed25519 + chmod 600 ~/.ssh/id_ed25519 + sed -i 's/\r$//' ~/.ssh/id_ed25519 + ssh-keyscan -H uz.saya.casa >> ~/.ssh/known_hosts + + - name: Test SSH connection + run: | + ssh -o ConnectTimeout=10 -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -i ~/.ssh/id_ed25519 svc_github@uz.saya.casa "echo 'SSH connection successful'" + + - name: Run Ansible playbook + env: + ANSIBLE_HOST_KEY_CHECKING: "False" + working-directory: ./deploy + run: | + ansible-playbook \ + playbook.yml \ + -i inventory.yml \ + -l stage \ + --private-key ~/.ssh/id_ed25519 \ + -u svc_github \ + -e saya_today_web_auth_salt="${{ secrets.AUTH_SALT }}" \ + -e saya_today_web_s3_access_key_id="${{ secrets.S3_ACCESS_KEY_ID }}" \ + -e saya_today_web_s3_secret_access_key="${{ secrets.S3_SECRET_ACCESS_KEY }}" \ + -e saya_today_web_environment=stage \ + -e saya_today_web_tag=commit-${{ needs.build-and-push.outputs.sha_short }} \ + -e saya_today_web_mail_salt="${{ secrets.MAIL_SALT }}" \ + -e saya_today_web_mail_host="${{ secrets.MAIL_HOST }}" \ + -e saya_today_web_mail_address="${{ secrets.MAIL_ADDRESS }}" \ + -e saya_today_web_mail_username="${{ secrets.MAIL_USERNAME }}" \ + -e saya_today_web_mail_password="${{ secrets.MAIL_PASSWORD }}" @@ -1,9 +1,4 @@ -FROM golang:1.26.4-alpine3.24 AS build-stage - -ARG TARGETOS=linux -ARG TARGETARCH=amd64 -ENV GOOS=${TARGETOS} -ENV GOARCH=${TARGETARCH} +FROM golang:1.26-alpine3.23 AS build-stage RUN apk add --no-cache sqlite-dev musl-dev gcc @@ -12,7 +7,7 @@ COPY . . RUN go mod download RUN CGO_ENABLED=1 go build -o sayana-web . -FROM alpine:3.24 AS runtime-stage +FROM alpine:3.23 AS runtime-stage ENV ENVIRONMENT="" ENV AUTH_SALT="" diff --git a/Jenkinsfile b/Jenkinsfile deleted file mode 100644 index 8633145..0000000 --- a/Jenkinsfile +++ /dev/null @@ -1,313 +0,0 @@ -pipeline { - agent none - - stages { - stage('Compile Tailwind CSS') { - agent { - docker { - image 'node:26.3.1-alpine3.24' - args '-v /tmp:/tmp -v /.npm:/.npm' - } - } - steps { - checkout scm - sh ''' - npm install tailwindcss @tailwindcss/cli @tailwindcss/forms - npx tailwindcss -i static/input.css -o static/output.css --minify - ''' - stash name: 'tailwindcss-output', includes: 'static/output.css' - } - } - - stage('Matrix Build') { - matrix { - axes { - axis { - name 'GOOS' - values 'linux' - } - axis { - name 'GOARCH' - values 'arm64', 'amd64' - } - } - stages { - stage('Build') { - agent { - kubernetes { - defaultContainer 'kaniko' - yaml """ -apiVersion: v1 -kind: Pod -metadata: - namespace: jenkins -spec: - nodeSelector: - kubernetes.io/arch: ${GOARCH} - containers: - - name: kaniko - image: gcr.io/kaniko-project/executor:v1.24.0-debug - imagePullPolicy: Always - command: [ /busybox/cat ] - tty: true - resources: - requests: - cpu: "1" - memory: 2Gi - ephemeral-storage: 4Gi - limits: - memory: 4Gi - ephemeral-storage: 8Gi -""" - } - } - environment { - IMAGE_PUSH_DESTINATION="registry.sayag.it/sayauz/web" - } - steps { - checkout scm - unstash 'tailwindcss-output' - container(name: 'kaniko', shell: '/busybox/sh') { - withCredentials([string(credentialsId: 'registry-sayagit-jenkins-password', variable: 'REGISTRY_SAYAGIT_JENKINS_PASSWORD')]) { - withEnv(['PATH+EXTRA=/busybox']) { - script { - env.GIT_COMMIT_SHORT = env.GIT_COMMIT ? env.GIT_COMMIT.take(7) : "unknown" - try { - sh '''#!/busybox/sh - mkdir -p /kaniko/.docker - printf '{"auths":{"registry.sayag.it":{"username":"jenkins","password":"%s"}}}' "$REGISTRY_SAYAGIT_JENKINS_PASSWORD" > /kaniko/.docker/config.json - /kaniko/executor --context `pwd` \ - --custom-platform=linux/${GOARCH} \ - --build-arg TARGETOS=linux \ - --build-arg TARGETARCH=${GOARCH} \ - --destination $IMAGE_PUSH_DESTINATION:commit-$GIT_COMMIT_SHORT-$GOARCH - ''' - } catch (Exception e) { - echo "Caught exception: ${e.getMessage()}" - currentBuild.result = 'FAILURE' - throw e - } - } - } - } - } - } - } - } - } - } - stage('Stitch Manifest') { - agent { - kubernetes { - defaultContainer 'manifest-tool' - yaml """ -apiVersion: v1 -kind: Pod -metadata: - namespace: jenkins -spec: - containers: - - name: manifest-tool - image: mplatform/manifest-tool:alpine-v2.2.2 - imagePullPolicy: Always - command: [ 'cat' ] - tty: true - resources: - requests: - cpu: "1" - memory: 2Gi - ephemeral-storage: 4Gi -""" - } - } - environment { - IMAGE_PUSH_DESTINATION="registry.sayag.it/sayauz/web" - } - steps { - script { - env.GIT_COMMIT_SHORT = env.GIT_COMMIT ? env.GIT_COMMIT.take(7) : "unknown" - } - withCredentials([string(credentialsId: 'registry-sayagit-jenkins-password', variable: 'REGISTRY_SAYAGIT_JENKINS_PASSWORD')]) { - sh '''mkdir -p /root/.docker - printf '{"auths":{"registry.sayag.it":{"username":"jenkins","password":"%s"}}}' "$REGISTRY_SAYAGIT_JENKINS_PASSWORD" > /root/.docker/config.json - - manifest-tool push from-args \ - --platforms linux/amd64,linux/arm64 \ - --template $IMAGE_PUSH_DESTINATION:commit-$GIT_COMMIT_SHORT-ARCH \ - --target $IMAGE_PUSH_DESTINATION:commit-$GIT_COMMIT_SHORT - manifest-tool push from-args \ - --platforms linux/amd64,linux/arm64 \ - --template $IMAGE_PUSH_DESTINATION:commit-$GIT_COMMIT_SHORT-ARCH \ - --target $IMAGE_PUSH_DESTINATION:latest - if [ "$TAG_NAME" != "" ]; then - manifest-tool push from-args \ - --platforms linux/amd64,linux/arm64 \ - --template $IMAGE_PUSH_DESTINATION:commit-$GIT_COMMIT_SHORT-ARCH \ - --target $IMAGE_PUSH_DESTINATION:stable - manifest-tool push from-args \ - --platforms linux/amd64,linux/arm64 \ - --template $IMAGE_PUSH_DESTINATION:commit-$GIT_COMMIT_SHORT-ARCH \ - --target $IMAGE_PUSH_DESTINATION:$TAG_NAME - fi - ''' - } - } - } - stage('Deploy (Stage)') { - when { branch 'stage' } - agent { - kubernetes { - defaultContainer 'ansible' - yaml """ -apiVersion: v1 -kind: Pod -metadata: - namespace: jenkins -spec: - containers: - - name: ansible - image: ghcr.io/ansible/community-ansible-dev-tools:v26.7.2 - command: [ 'cat' ] - tty: true - resources: - requests: - cpu: "500m" - memory: 1Gi -""" - } - } - steps { - checkout scm - container('ansible') { - script { - env.GIT_COMMIT_SHORT = env.GIT_COMMIT ? env.GIT_COMMIT.take(7) : "unknown" - - def secretVars = [ - 'sayauz-web-stage-auth-salt' : 'AUTH_SALT', - 'sayauz-web-stage-s3-access-key-id' : 'S3_ACCESS_KEY_ID', - 'sayauz-web-stage-s3-secret-access-key' : 'S3_SECRET_ACCESS_KEY', - 'sayauz-web-stage-mail-salt' : 'MAIL_SALT', - 'sayauz-web-stage-mail-host' : 'MAIL_HOST', - 'sayauz-web-stage-mail-address' : 'MAIL_ADDRESS', - 'sayauz-web-stage-mail-username' : 'MAIL_USERNAME', - 'sayauz-web-stage-mail-password' : 'MAIL_PASSWORD' - ] - def bindings = secretVars.collect { id, varName -> string(credentialsId: id, variable: varName) } - bindings << sshUserPrivateKey(credentialsId: 'sayauz-svc-github', keyFileVariable: 'SSH_KEY_FILE', usernameVariable: 'SSH_USER') - - withCredentials(bindings) { - sh ''' - ansible-galaxy collection install community.docker - - mkdir -p ~/.ssh - cp "$SSH_KEY_FILE" ~/.ssh/id_ed25519 - chmod 600 ~/.ssh/id_ed25519 - ssh-keyscan -H uz.saya.casa >> ~/.ssh/known_hosts - - ssh -o ConnectTimeout=10 -i ~/.ssh/id_ed25519 "$SSH_USER@uz.saya.casa" "echo 'SSH connection successful'" - - cd deploy - ANSIBLE_HOST_KEY_CHECKING=False ansible-playbook \ - playbook.yml \ - -i inventory.yml \ - -l stage \ - --private-key ~/.ssh/id_ed25519 \ - -u "$SSH_USER" \ - -e saya_today_web_auth_salt="$AUTH_SALT" \ - -e saya_today_web_s3_access_key_id="$S3_ACCESS_KEY_ID" \ - -e saya_today_web_s3_secret_access_key="$S3_SECRET_ACCESS_KEY" \ - -e saya_today_web_environment=stage \ - -e saya_today_web_tag=commit-$GIT_COMMIT_SHORT \ - -e saya_today_web_mail_salt="$MAIL_SALT" \ - -e saya_today_web_mail_host="$MAIL_HOST" \ - -e saya_today_web_mail_address="$MAIL_ADDRESS" \ - -e saya_today_web_mail_username="$MAIL_USERNAME" \ - -e saya_today_web_mail_password="$MAIL_PASSWORD" - ''' - } - } - } - } - } - stage('Deploy (Prod)') { - when { buildingTag() } - agent { - kubernetes { - defaultContainer 'ansible' - yaml """ -apiVersion: v1 -kind: Pod -metadata: - namespace: jenkins -spec: - containers: - - name: ansible - image: ghcr.io/ansible/community-ansible-dev-tools:v26.7.2 - command: [ 'cat' ] - tty: true - resources: - requests: - cpu: "500m" - memory: 1Gi -""" - } - } - steps { - checkout scm - container('ansible') { - script { - def secretVars = [ - 'sayauz-web-prod-auth-salt' : 'AUTH_SALT', - 'sayauz-web-prod-s3-access-key-id' : 'S3_ACCESS_KEY_ID', - 'sayauz-web-prod-s3-secret-access-key' : 'S3_SECRET_ACCESS_KEY', - 'sayauz-web-prod-mail-salt' : 'MAIL_SALT', - 'sayauz-web-prod-mail-host' : 'MAIL_HOST', - 'sayauz-web-prod-mail-address' : 'MAIL_ADDRESS', - 'sayauz-web-prod-mail-username' : 'MAIL_USERNAME', - 'sayauz-web-prod-mail-password' : 'MAIL_PASSWORD', - 'sayauz-web-prod-verification-google' : 'GOOGLE_VERIFICATION', - 'sayauz-web-prod-verification-yandex' : 'YANDEX_VERIFICATION', - 'sayauz-web-prod-verification-bing' : 'BING_VERIFICATION' - ] - def bindings = secretVars.collect { id, varName -> string(credentialsId: id, variable: varName) } - bindings << sshUserPrivateKey(credentialsId: 'sayauz-svc-github', keyFileVariable: 'SSH_KEY_FILE', usernameVariable: 'SSH_USER') - - withCredentials(bindings) { - sh ''' - ansible-galaxy collection install community.docker - - mkdir -p ~/.ssh - cp "$SSH_KEY_FILE" ~/.ssh/id_ed25519 - chmod 600 ~/.ssh/id_ed25519 - ssh-keyscan -H uz.saya.casa >> ~/.ssh/known_hosts - - ssh -o ConnectTimeout=10 -i ~/.ssh/id_ed25519 "$SSH_USER@uz.saya.casa" "echo 'SSH connection successful'" - - cd deploy - ANSIBLE_HOST_KEY_CHECKING=False ansible-playbook \ - playbook.yml \ - -i inventory.yml \ - -l prod \ - --private-key ~/.ssh/id_ed25519 \ - -u "$SSH_USER" \ - -e saya_today_web_auth_salt="$AUTH_SALT" \ - -e saya_today_web_s3_access_key_id="$S3_ACCESS_KEY_ID" \ - -e saya_today_web_s3_secret_access_key="$S3_SECRET_ACCESS_KEY" \ - -e saya_today_web_environment=prod \ - -e saya_today_web_tag=$TAG_NAME \ - -e saya_today_web_mail_salt="$MAIL_SALT" \ - -e saya_today_web_mail_host="$MAIL_HOST" \ - -e saya_today_web_mail_address="$MAIL_ADDRESS" \ - -e saya_today_web_mail_username="$MAIL_USERNAME" \ - -e saya_today_web_mail_password="$MAIL_PASSWORD" \ - -e saya_today_google_verification="$GOOGLE_VERIFICATION" \ - -e saya_today_yandex_verification="$YANDEX_VERIFICATION" \ - -e saya_today_bing_verification="$BING_VERIFICATION" - ''' - } - } - } - } - } - } -} diff --git a/config/config.go b/config/config.go index 9185e6a..8ab1bfc 100644 --- a/config/config.go +++ b/config/config.go @@ -20,7 +20,7 @@ type Config struct { Auth AuthConfig `json:"Auth" yaml:"auth" validate:"required"` Mail MailConfig `json:"Mail" yaml:"mail" validate:"required"` CanonicalEndpoint string `json:"CanonicalEndpoint" yaml:"canonicalEndpoint" validate:"required"` - Meta []MetaConfig `json:"Meta" yaml:"meta"` + Meta MetaConfig `json:"Meta" yaml:"meta"` PhotoStorage PhotoStorageConfig `json:"PhotoStorage" yaml:"photoStorage"` StaticStorage StaticStorageConfig `json:"StaticStorage" yaml:"staticStorage" validate:"required"` AllowOrigins []string `json:"AllowOrigins" yaml:"allowOrigins"` @@ -237,8 +237,8 @@ type TriggerConfig struct { } type MetaConfig struct { - Name string `json:"Name" yaml:"name"` - Value string `json:"Value" yaml:"value"` + GoogleSiteVerification string `json:"GoogleSiteVerification" yaml:"googleSiteVerification"` + YandexVerification string `json:"YandexVerification" yaml:"yandexVerification"` } type PhotoStorageConfig struct { diff --git a/config/config.prod.yaml b/config/config.prod.yaml index 6ec00d8..ce0941d 100644 --- a/config/config.prod.yaml +++ b/config/config.prod.yaml @@ -55,12 +55,8 @@ mail: onNewPost: "0/5 * * * *" canonicalEndpoint: "https://${FQDN}" meta: - - name: google-site-verification - value: "${GOOGLE_SITE_VERIFICATION}" - - name: yandex-verification - value: "${YANDEX_VERIFICATION}" - - name: msvalidate.01 - value: "${BING_VERIFICATION}" + googleSiteVerification: "${GOOGLE_SITE_VERIFICATION}" + yandexVerification: "${YANDEX_VERIFICATION}" photoStorage: full: baseUrl: https://cdn.saya.uz/photos/jpeg-full/%s diff --git a/deploy/playbook.yml b/deploy/playbook.yml index 057cc19..ae3e936 100644 --- a/deploy/playbook.yml +++ b/deploy/playbook.yml @@ -6,7 +6,7 @@ vars: docker_volumes: - "{{ saya_today_web_name }}-volume:/data:rw" - + tasks: - name: Initialize Unix socket volume when: >- @@ -26,11 +26,11 @@ community.docker.docker_volume: name: "{{ saya_today_web_name }}-volume" - - name: Deploy sayauz/web Docker Container + - name: Deploy saya-today-web Docker Container community.docker.docker_container: name: "{{ saya_today_web_name }}" hostname: "{{ saya_today_web_hostname }}" - image: "registry.sayag.it/sayauz/web:{{ saya_today_web_tag }}" + image: "ghcr.io/sayaandy/saya-today-web:{{ saya_today_web_tag }}" env: S3_ACCESS_KEY_ID: "{{ saya_today_web_s3_access_key_id }}" S3_SECRET_ACCESS_KEY: "{{ saya_today_web_s3_secret_access_key }}" @@ -42,9 +42,8 @@ MAIL_PASSWORD: "{{ saya_today_web_mail_password }}" MAIL_SALT: "{{ saya_today_web_mail_salt }}" FQDN: "{{ saya_today_web_listen_address }}" - GOOGLE_VERIFICATION: "{{ saya_today_google_verification | default('') }}" + GOOGLE_SITE_VERIFICATION: "{{ saya_today_google_site_verification | default('') }}" YANDEX_VERIFICATION: "{{ saya_today_yandex_verification | default('') }}" - BING_VERIFICATION: "{{ saya_today_bing_verification | default('') }}" network_mode: caddy networks: - name: caddy diff --git a/internal/router/handlers/lang-blog-title.go b/internal/router/handlers/lang-blog-title.go index 76dc335..5a1155d 100644 --- a/internal/router/handlers/lang-blog-title.go +++ b/internal/router/handlers/lang-blog-title.go @@ -156,13 +156,7 @@ func (r *BlogPageHandler) RenderHeader(c *fiber.Ctx, supplements *router.Supplem return fiber.StatusNotFound, fmt.Errorf("could not read '%s' for metadata: %w", path, err) } - pageTitle := metadata.Title - if metadata.Medley != "" { - pageTitle += " // " + l10n.T.GetPath(lang, "Medleys", metadata.Medley).(string) - } - templateMap["Title"] = metadata.Title - templateMap["PageTitle"] = pageTitle return fiber.StatusOK, nil } diff --git a/internal/router/handlers/root.go b/internal/router/handlers/root.go index 4fc4e31..6a011e4 100644 --- a/internal/router/handlers/root.go +++ b/internal/router/handlers/root.go @@ -47,8 +47,11 @@ func (r *RootHandler) AddMeta(c *fiber.Ctx, supplements *router.Supplements, lan {Property: "og:url", Content: fmt.Sprint(templateMap["CanonicalEndpoint"]) + "/"}, {Property: "og:type", Content: "website"}, } - for _, field := range supplements.Meta { - meta = append(meta, router.MetaField{Name: field.Name, Content: field.Value}) + if supplements.Meta.GoogleSiteVerification != "" { + meta = append(meta, router.MetaField{Name: "google-site-verification", Content: supplements.Meta.GoogleSiteVerification}) + } + if supplements.Meta.YandexVerification != "" { + meta = append(meta, router.MetaField{Name: "yandex-verification", Content: supplements.Meta.YandexVerification}) } return meta, nil } diff --git a/internal/router/router.go b/internal/router/router.go index a11a934..c8b5686 100644 --- a/internal/router/router.go +++ b/internal/router/router.go @@ -102,7 +102,7 @@ type Supplements struct { BlogTrigger *blogtrigger.BlogTriggerScheduler TemplateManager *templatemanager.TemplateManager MarkdownRenderer goldmark.Markdown - Meta []config.MetaConfig + Meta config.MetaConfig PhotoStorage config.PhotoStorageConfig StaticStorage config.StaticStorageConfig } diff --git a/static/input.css b/static/input.css index e0c5c81..0dfb137 100644 --- a/static/input.css +++ b/static/input.css @@ -87,10 +87,6 @@ body { scrollbar-color: var(--color-background-light) var(--color-main-soft); } -body.glightbox-open { - height: 100dvh; -} - @media screen and (min-width: 900px) and (min-height: 900px) { html { font-size: clamp(16px, min(1dvw, 1dvh) + 7px, 20px); @@ -904,8 +900,8 @@ form.crossable.htmx-request input { } .ram-frame { - width: 8rem; - height: 8rem; + width: 20vmin; + height: 20vmin; user-select: none; -webkit-user-select: none; } diff --git a/views/layouts/general-page.html b/views/layouts/general-page.html index 06ef625..78c7f0c 100644 --- a/views/layouts/general-page.html +++ b/views/layouts/general-page.html @@ -213,8 +213,18 @@ var seed = cyrb128("{{ .Title }}"); var rand = sfc32(seed[0], seed[1], seed[2], seed[3]); - function calculateRem(remNum) { - return remNum * parseFloat(getComputedStyle(document.documentElement).fontSize); + function calculateVmin(percent) { + const viewportWidth = window.innerWidth; + const viewportHeight = window.innerHeight; + + const smallerDimension = Math.min( + viewportWidth, + viewportHeight, + ); + + const vminValue = (smallerDimension / 100) * percent; + + return vminValue; } const _probe = document.createElement('div'); @@ -309,7 +319,7 @@ theme = document.body.getAttribute("data-theme"); } - rem = calculateRem(1); + vmin = calculateVmin(1); var clWidth = document.documentElement.clientWidth; var clHeight = document.documentElement.clientHeight; @@ -328,11 +338,11 @@ "z-0", "absolute", ); + const x = Math.floor(rand() * clWidth); + const y = Math.floor(rand() * clHeight * 0.8); const rot = rand() * 90; const animDuration = rand() * 10 + 3; const sz = Math.floor(rand() * 8) + 12; - const x = Math.floor(rand() * clWidth - 1.42 * sz); // 1.42 ~ sqrt(2) - const y = Math.floor(rand() * clHeight * 0.8); star.style.transform = `translateX(${x}px) translateY(${y}px) rotate(${rot}deg)`; star.style.animationDuration = `${animDuration}s`; star.style.fontSize = `${sz}px`; @@ -352,14 +362,14 @@ ); let x, y; outerLoop: while (true) { - x = Math.floor(rand() * clWidth - 22.64 * rem) + 11.32 * rem; // 11.32 ~ 8 * sqrt(2) - y = Math.floor(rand() * clHeight - 22.64 * rem) + 11.32 * rem; + x = Math.floor(rand() * clWidth - 20 * vmin); + y = Math.floor(rand() * clHeight - 20 * vmin); for (j = 0; j < i - 1; j++) { const xd = frameCenters[j].x - x; const yd = frameCenters[j].y - y; if ( Math.sqrt(xd * xd + yd * yd) < - 23 * rem + 30 * vmin ) { continue outerLoop; } @@ -704,6 +714,17 @@ } }); + function calculateVmax(percent) { + const viewportWidth = window.innerWidth; + const viewportHeight = window.innerHeight; + + const largerDimension = Math.max(viewportWidth, viewportHeight); + + const vmaxValue = (largerDimension / 100) * percent; + + return vmaxValue; + } + function positionThemeIcons() { const sliceAngle = 360 / themeIcons.length; diff --git a/views/partials/general-page-header.html b/views/partials/general-page-header.html index a75d32f..ce77b5c 100644 --- a/views/partials/general-page-header.html +++ b/views/partials/general-page-header.html @@ -1,4 +1,4 @@ -<title>{{ or .PageTitle .Title }}</title> +<title>{{ .Title }} // SAYA.UZ</title> <div class="flex flex-row mb-2"> {{ block "header" . }}{{ end }} <h1 |