mirror of
https://github.com/immich-app/data.immich.app.git
synced 2026-09-30 13:23:26 +08:00
feat: immich data (#1)
This commit is contained in:
@@ -0,0 +1,42 @@
|
||||
name: Build
|
||||
on:
|
||||
push:
|
||||
branches: [main]
|
||||
pull_request:
|
||||
branches: [main]
|
||||
release:
|
||||
types: [published]
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
build:
|
||||
name: Build
|
||||
runs-on: ubuntu-latest
|
||||
defaults:
|
||||
run:
|
||||
working-directory: ./web
|
||||
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Setup Node
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version-file: './web/.nvmrc'
|
||||
|
||||
- name: Run npm install
|
||||
run: npm ci
|
||||
|
||||
- name: Run build
|
||||
run: npm run build
|
||||
|
||||
- name: Upload build output
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: build-output-web
|
||||
path: build
|
||||
retention-days: 1
|
||||
@@ -0,0 +1,178 @@
|
||||
name: Deploy
|
||||
on:
|
||||
workflow_run:
|
||||
workflows: ['Build']
|
||||
types:
|
||||
- completed
|
||||
|
||||
jobs:
|
||||
checks:
|
||||
name: Deploy checks
|
||||
runs-on: ubuntu-latest
|
||||
outputs:
|
||||
parameters: ${{ steps.parameters.outputs.result }}
|
||||
steps:
|
||||
- if: ${{ github.event.workflow_run.conclusion == 'failure' }}
|
||||
run: echo 'The triggering workflow failed' && exit 1
|
||||
|
||||
- name: Determine deploy parameters
|
||||
id: parameters
|
||||
uses: actions/github-script@v7
|
||||
with:
|
||||
script: |
|
||||
const eventType = context.payload.workflow_run.event;
|
||||
const isFork = context.payload.workflow_run.repository.fork;
|
||||
|
||||
let parameters;
|
||||
|
||||
console.log({eventType, isFork});
|
||||
|
||||
if (eventType == "push") {
|
||||
const branch = context.payload.workflow_run.head_branch;
|
||||
console.log({branch});
|
||||
const shouldDeploy = !isFork && branch == "main";
|
||||
parameters = {
|
||||
event: "branch",
|
||||
name: "main",
|
||||
shouldDeploy
|
||||
};
|
||||
} else if (eventType == "pull_request") {
|
||||
let pull_number = context.payload.workflow_run.pull_requests[0]?.number;
|
||||
if(!pull_number) {
|
||||
const response = await github.rest.search.issuesAndPullRequests({q: 'repo:${{ github.repository }} is:pr sha:${{ github.event.workflow_run.head_sha }}',per_page: 1,})
|
||||
const items = response.data.items
|
||||
if (items.length < 1) {
|
||||
throw new Error("No pull request found for the commit")
|
||||
}
|
||||
const pullRequestNumber = items[0].number
|
||||
console.info("Pull request number is", pullRequestNumber)
|
||||
pull_number = pullRequestNumber
|
||||
}
|
||||
const {data: pr} = await github.rest.pulls.get({
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
pull_number
|
||||
});
|
||||
|
||||
console.log({pull_number});
|
||||
|
||||
parameters = {
|
||||
event: "pr",
|
||||
name: `pr-${pull_number}`,
|
||||
pr_number: pull_number,
|
||||
shouldDeploy: true
|
||||
};
|
||||
} else if (eventType == "release") {
|
||||
parameters = {
|
||||
event: "release",
|
||||
name: context.payload.workflow_run.head_branch,
|
||||
shouldDeploy: !isFork
|
||||
};
|
||||
}
|
||||
|
||||
console.log(parameters);
|
||||
return parameters;
|
||||
|
||||
deploy:
|
||||
name: Deploy
|
||||
runs-on: ubuntu-latest
|
||||
needs: checks
|
||||
if: ${{ fromJson(needs.checks.outputs.parameters).shouldDeploy }}
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Load parameters
|
||||
id: parameters
|
||||
uses: actions/github-script@v7
|
||||
with:
|
||||
script: |
|
||||
const json = `${{ needs.checks.outputs.parameters }}`;
|
||||
const parameters = JSON.parse(json);
|
||||
core.setOutput("event", parameters.event);
|
||||
core.setOutput("name", parameters.name);
|
||||
core.setOutput("shouldDeploy", parameters.shouldDeploy);
|
||||
|
||||
- run: |
|
||||
echo "Starting docs deployment for ${{ steps.parameters.outputs.event }} ${{ steps.parameters.outputs.name }}"
|
||||
|
||||
- name: Download artifact
|
||||
uses: actions/github-script@v7
|
||||
with:
|
||||
script: |
|
||||
let allArtifacts = await github.rest.actions.listWorkflowRunArtifacts({
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
run_id: context.payload.workflow_run.id,
|
||||
});
|
||||
let matchArtifact = allArtifacts.data.artifacts.find((artifact) => artifact.name == "build-output-web");
|
||||
let download = await github.rest.actions.downloadArtifact({
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
artifact_id: matchArtifact.id,
|
||||
archive_format: 'zip',
|
||||
});
|
||||
let fs = require('fs');
|
||||
fs.writeFileSync(`${process.env.GITHUB_WORKSPACE}/build-output.zip`, Buffer.from(download.data));
|
||||
|
||||
- name: Unzip artifact
|
||||
run: unzip "${{ github.workspace }}/build-output.zip" -d "${{ github.workspace }}/build"
|
||||
|
||||
- name: Deploy App
|
||||
env:
|
||||
TF_VAR_prefix_name: ${{ steps.parameters.outputs.name }}
|
||||
TF_VAR_prefix_event_type: ${{ steps.parameters.outputs.event }}
|
||||
TF_VAR_app_url: data.immich.app
|
||||
TF_VAR_app_name: immich-data
|
||||
CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }}
|
||||
CLOUDFLARE_ACCOUNT_ID: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
|
||||
TF_STATE_POSTGRES_CONN_STR: ${{ secrets.TF_STATE_POSTGRES_CONN_STR }}
|
||||
uses: gruntwork-io/terragrunt-action@v2
|
||||
with:
|
||||
tg_version: '0.58.12'
|
||||
tofu_version: '1.7.1'
|
||||
tg_dir: 'deployment/modules/cloudflare/static-pages'
|
||||
tg_command: 'apply'
|
||||
|
||||
- name: Deploy App Output
|
||||
id: terraform-output
|
||||
env:
|
||||
TF_VAR_prefix_name: ${{ steps.parameters.outputs.name }}
|
||||
TF_VAR_prefix_event_type: ${{ steps.parameters.outputs.event }}
|
||||
TF_VAR_app_url: data.immich.app
|
||||
TF_VAR_app_name: immich-data
|
||||
CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }}
|
||||
CLOUDFLARE_ACCOUNT_ID: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
|
||||
TF_STATE_POSTGRES_CONN_STR: ${{ secrets.TF_STATE_POSTGRES_CONN_STR }}
|
||||
uses: gruntwork-io/terragrunt-action@v2
|
||||
with:
|
||||
tg_version: '0.58.12'
|
||||
tofu_version: '1.7.1'
|
||||
tg_dir: 'deployment/modules/cloudflare/static-pages'
|
||||
tg_command: 'output -json'
|
||||
|
||||
- name: Output Cleaning
|
||||
id: clean
|
||||
run: |
|
||||
TG_OUT=$(echo '${{ steps.terraform-output.outputs.tg_action_output }}' | sed 's|%0A|\n|g ; s|%3C|<|g' | jq -c .)
|
||||
echo "output=$TG_OUT" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Publish to Cloudflare Pages
|
||||
uses: cloudflare/pages-action@v1
|
||||
with:
|
||||
apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN_PAGES_UPLOAD }}
|
||||
accountId: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
|
||||
projectName: ${{ fromJson(steps.clean.outputs.output).pages_project_name.value }}
|
||||
directory: 'build'
|
||||
branch: ${{ steps.parameters.outputs.name }}
|
||||
wranglerVersion: '3'
|
||||
|
||||
- name: Comment
|
||||
uses: actions-cool/maintain-one-comment@v3
|
||||
if: ${{ steps.parameters.outputs.event == 'pr' }}
|
||||
with:
|
||||
number: ${{ fromJson(needs.checks.outputs.parameters).pr_number }}
|
||||
body: |
|
||||
📖 Preview of web deployed to [${{ fromJson(steps.clean.outputs.output).immich_app_branch_subdomain.value }}](https://${{ fromJson(steps.clean.outputs.output).immich_app_branch_subdomain.value }})
|
||||
emojis: 'rocket'
|
||||
body-include: '<!-- web PR URL -->'
|
||||
@@ -0,0 +1,34 @@
|
||||
name: Docs destroy
|
||||
on:
|
||||
pull_request_target:
|
||||
types: [closed]
|
||||
|
||||
jobs:
|
||||
deploy:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Destroy Docs Subdomain
|
||||
env:
|
||||
TF_VAR_prefix_name: 'pr-${{ github.event.number }}'
|
||||
TF_VAR_prefix_event_type: 'pr'
|
||||
TF_VAR_app_url: data.immich.app
|
||||
TF_VAR_app_name: immich-data
|
||||
CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }}
|
||||
CLOUDFLARE_ACCOUNT_ID: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
|
||||
TF_STATE_POSTGRES_CONN_STR: ${{ secrets.TF_STATE_POSTGRES_CONN_STR }}
|
||||
uses: gruntwork-io/terragrunt-action@v2
|
||||
with:
|
||||
tg_version: '0.58.12'
|
||||
tofu_version: '1.7.1'
|
||||
tg_dir: 'deployment/modules/cloudflare/static-pages'
|
||||
tg_command: 'destroy'
|
||||
|
||||
- name: Comment
|
||||
uses: actions-cool/maintain-one-comment@v3
|
||||
with:
|
||||
number: ${{ github.event.number }}
|
||||
delete: true
|
||||
body-include: '<!-- web PR URL -->'
|
||||
@@ -0,0 +1,46 @@
|
||||
name: Test
|
||||
on:
|
||||
workflow_dispatch:
|
||||
pull_request:
|
||||
push:
|
||||
branches: [main]
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
test:
|
||||
name: Test
|
||||
runs-on: ubuntu-latest
|
||||
defaults:
|
||||
run:
|
||||
working-directory: ./web
|
||||
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Setup Node
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version-file: './web/.nvmrc'
|
||||
|
||||
- name: Run npm install
|
||||
run: npm ci
|
||||
|
||||
- name: Run linter
|
||||
run: npm run lint
|
||||
if: ${{ !cancelled() }}
|
||||
|
||||
- name: Run formatter
|
||||
run: npm run format
|
||||
if: ${{ !cancelled() }}
|
||||
|
||||
- name: Run tsc
|
||||
run: npm run check
|
||||
if: ${{ !cancelled() }}
|
||||
|
||||
- name: Run unit tests
|
||||
run: npm test
|
||||
if: ${{ !cancelled() }}
|
||||
@@ -0,0 +1,38 @@
|
||||
# create-svelte
|
||||
|
||||
Everything you need to build a Svelte project, powered by [`create-svelte`](https://github.com/sveltejs/kit/tree/main/packages/create-svelte).
|
||||
|
||||
## Creating a project
|
||||
|
||||
If you're seeing this, you've probably already done this step. Congrats!
|
||||
|
||||
```bash
|
||||
# create a new project in the current directory
|
||||
npm create svelte@latest
|
||||
|
||||
# create a new project in my-app
|
||||
npm create svelte@latest my-app
|
||||
```
|
||||
|
||||
## Developing
|
||||
|
||||
Once you've created a project and installed dependencies with `npm install` (or `pnpm install` or `yarn`), start a development server:
|
||||
|
||||
```bash
|
||||
npm run dev
|
||||
|
||||
# or start the server and open the app in a new browser tab
|
||||
npm run dev -- --open
|
||||
```
|
||||
|
||||
## Building
|
||||
|
||||
To create a production version of your app:
|
||||
|
||||
```bash
|
||||
npm run build
|
||||
```
|
||||
|
||||
You can preview the production build with `npm run preview`.
|
||||
|
||||
> To deploy your app, you may need to install an [adapter](https://kit.svelte.dev/docs/adapters) for your target environment.
|
||||
@@ -0,0 +1,38 @@
|
||||
# OpenTofu
|
||||
|
||||
# Local .terraform directories
|
||||
**/.terraform/*
|
||||
|
||||
# .tfstate files
|
||||
*.tfstate
|
||||
*.tfstate.*
|
||||
|
||||
# Crash log files
|
||||
crash.log
|
||||
crash.*.log
|
||||
|
||||
# Ignore override files as they are usually used to override resources locally and so
|
||||
# are not checked in
|
||||
override.tf
|
||||
override.tf.json
|
||||
*_override.tf
|
||||
*_override.tf.json
|
||||
|
||||
# Include override files you do wish to add to version control using negated pattern
|
||||
# !example_override.tf
|
||||
|
||||
# Include tfplan files to ignore the plan output of command: terraform plan -out=tfplan
|
||||
# example: *tfplan*
|
||||
|
||||
# Ignore CLI configuration files
|
||||
.terraformrc
|
||||
terraform.rc
|
||||
|
||||
# Terragrunt
|
||||
|
||||
# terragrunt cache directories
|
||||
**/.terragrunt-cache/*
|
||||
|
||||
# Terragrunt debug output file (when using `--terragrunt-debug` option)
|
||||
# See: https://terragrunt.gruntwork.io/docs/reference/cli-options/#terragrunt-debug
|
||||
terragrunt-debug.tfvars.json
|
||||
@@ -0,0 +1,38 @@
|
||||
# This file is maintained automatically by "tofu init".
|
||||
# Manual edits may be lost in future updates.
|
||||
|
||||
provider "registry.opentofu.org/cloudflare/cloudflare" {
|
||||
version = "4.42.0"
|
||||
constraints = "4.42.0"
|
||||
hashes = [
|
||||
"h1:+1iz3OcEEYBLeVS07cqRP5Kef0Y0XS8YEj/I1HH9J/A=",
|
||||
"h1:/XZtSyok+I0hAHqj4hcA2RP4G9uvTABG4oMGC3vlS6o=",
|
||||
"h1:5Z9Kfc5ufjqbLBXP9lZqQ11PAc4m6aTf/0M6miceOVQ=",
|
||||
"h1:6cupVsiQundwTt+/lSuiR3s1s1H0JDN1H7USaF/+nDg=",
|
||||
"h1:FasXNkaO7MNWy6GtuB/QFlnpQ7UuQQNotN1asY/r0Z8=",
|
||||
"h1:G+5pvEHQlVkPXW6HK1twiWHOV/pavtSpQthZ0wb0HYM=",
|
||||
"h1:HYhFNiRR1InZGjelCdQmg/KJHL2lFDlaWGSl2KA2fwk=",
|
||||
"h1:LkMNEQUnYBAx8EFvl1BU/AVG1cs1Xi62kCvTVvYvDZ8=",
|
||||
"h1:McPTXlnBSEzFGmVJHU7KyoBI3hJRh/eRcFTcijAfO/I=",
|
||||
"h1:MoqiPtyXewRdNsevZUMqb0rXXpeLUVxNVEzux4AC7y4=",
|
||||
"h1:RUgEZET04NprAFc4XAJwqqLiwNKaCTQEQEXtIZtNu1E=",
|
||||
"h1:UCneKnBS53RlyJsdCqCCWrw19GE48tzTyO2u/V5u24c=",
|
||||
"h1:aGbtjN8I2mLyW7aJ8KVRYuVdYeQCh3Ee8c3ixiijmjM=",
|
||||
"h1:phTeKoT4aUmPXQO6d7ZbSQ8Cu41dhosACCEiDpRsL/I=",
|
||||
"zh:1abb93dda2bf73b1656dc63673c752642bfa4c31c8ca1e83cdd278f42fa121c1",
|
||||
"zh:2b9c90fe4fffaadfeccd0f457bd1354ba2dba920c5525748d8f8f24656d6c7bd",
|
||||
"zh:710a0cf84406df09705115a62bd6a418188a3b884f615fe7122a6fc51ec59bc0",
|
||||
"zh:7875b38b281d17a24d89116b33f92b8b24292be160a2c618874a0f674171bd34",
|
||||
"zh:890df766e9b839623b1f0437355032a3c006226a6c200cd911e15ee1a9014e9f",
|
||||
"zh:ad28c94908c336ca97feabb02734a2c115eddaa5f4a625f00bfafb3ac65646e4",
|
||||
"zh:aee7861d44cf1a71a4846e1ffda20992259838ee600ca79d3abc80b43f4ff0f0",
|
||||
"zh:b1327e8ea04f0df5efc2b8848c358bf0d256716ad5372f91f5960296a1f68677",
|
||||
"zh:b9ec2310feffef38c1488bed038ad7942c54f930f2166a600b5fc850e377bddf",
|
||||
"zh:d04178727d7157aae8eb66b4f7318338c89cd685b53c67f5ce41de4160c2d484",
|
||||
"zh:d76c4bb5a5bfed710fcc8a1d919172cbfcbda0cec177f1d2cb44aff82a862a32",
|
||||
"zh:ddf3c126b5c98267240f960f8fed381115675793e5b86dd2cbdebeb628efb0cb",
|
||||
"zh:e3efb3b9409626f15931a81edaeb96e4baf462a24b32dac9d97cc36d1fef1f01",
|
||||
"zh:e925c963cddf5778829f0b26f72ad8bcbc1aed3510cfa0bd5a9e7cbf4c64a6e8",
|
||||
"zh:ff78a903b2432fbff7b04e84a23c71425589bad7a4b846e08bc131268b80900f",
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
terraform {
|
||||
backend "pg" {}
|
||||
required_version = "~> 1.7"
|
||||
|
||||
required_providers {
|
||||
cloudflare = {
|
||||
source = "cloudflare/cloudflare"
|
||||
version = "4.42.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
resource "cloudflare_pages_domain" "immich_app_branch_domain" {
|
||||
account_id = var.cloudflare_account_id
|
||||
project_name = data.terraform_remote_state.cloudflare_account.outputs.static_pages_project_names[var.app_url]
|
||||
domain = local.domain
|
||||
}
|
||||
|
||||
resource "cloudflare_record" "immich_app_branch_subdomain" {
|
||||
name = local.domain
|
||||
proxied = true
|
||||
ttl = 1
|
||||
type = "CNAME"
|
||||
value = local.is_main ? data.terraform_remote_state.cloudflare_account.outputs.static_pages_project_subdomains[var.app_url] : "${replace(var.prefix_name, "/\\/|\\./", "-")}.${data.terraform_remote_state.cloudflare_account.outputs.static_pages_project_subdomains[var.app_url]}"
|
||||
zone_id = data.terraform_remote_state.cloudflare_account.outputs.immich_app_zone_id
|
||||
}
|
||||
|
||||
output "immich_app_branch_subdomain" {
|
||||
value = cloudflare_record.immich_app_branch_subdomain.hostname
|
||||
}
|
||||
|
||||
output "immich_app_branch_pages_hostname" {
|
||||
value = cloudflare_record.immich_app_branch_subdomain.value
|
||||
}
|
||||
|
||||
output "pages_project_name" {
|
||||
value = cloudflare_pages_domain.immich_app_branch_domain.project_name
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
locals {
|
||||
is_main = var.prefix_name == "main"
|
||||
domain_prefix = !local.is_main && contains(["branch", "pr"], var.prefix_event_type) ? "${var.prefix_name}.preview." : ""
|
||||
domain = "${local.domain_prefix}${var.app_url}"
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
provider "cloudflare" {
|
||||
api_token = data.terraform_remote_state.api_keys_state.outputs.terraform_key_cloudflare_docs
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
data "terraform_remote_state" "api_keys_state" {
|
||||
backend = "pg"
|
||||
|
||||
config = {
|
||||
conn_str = var.tf_state_postgres_conn_str
|
||||
schema_name = "prod_cloudflare_api_keys"
|
||||
}
|
||||
}
|
||||
|
||||
data "terraform_remote_state" "cloudflare_account" {
|
||||
backend = "pg"
|
||||
|
||||
config = {
|
||||
conn_str = var.tf_state_postgres_conn_str
|
||||
schema_name = "prod_cloudflare_account"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
terraform {
|
||||
source = "."
|
||||
|
||||
extra_arguments custom_vars {
|
||||
commands = get_terraform_commands_that_need_vars()
|
||||
}
|
||||
}
|
||||
|
||||
include {
|
||||
path = find_in_parent_folders("state.hcl")
|
||||
}
|
||||
|
||||
locals {
|
||||
prefix_name = get_env("TF_VAR_prefix_name")
|
||||
app_name = replace(get_env("TF_VAR_app_name"), "-", "_")
|
||||
}
|
||||
|
||||
remote_state {
|
||||
backend = "pg"
|
||||
|
||||
config = {
|
||||
conn_str = get_env("TF_STATE_POSTGRES_CONN_STR")
|
||||
schema_name = "prod_cloudflare_immich_app_${local.app_name}_${local.prefix_name}"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
variable "cloudflare_account_id" {}
|
||||
variable "tf_state_postgres_conn_str" {}
|
||||
|
||||
variable "prefix_name" {}
|
||||
variable "prefix_event_type" {}
|
||||
variable "app_url" {}
|
||||
@@ -0,0 +1,20 @@
|
||||
locals {
|
||||
cloudflare_account_id = get_env("CLOUDFLARE_ACCOUNT_ID")
|
||||
cloudflare_api_token = get_env("CLOUDFLARE_API_TOKEN")
|
||||
|
||||
tf_state_postgres_conn_str = get_env("TF_STATE_POSTGRES_CONN_STR")
|
||||
}
|
||||
|
||||
remote_state {
|
||||
backend = "pg"
|
||||
|
||||
config = {
|
||||
conn_str = local.tf_state_postgres_conn_str
|
||||
}
|
||||
}
|
||||
|
||||
inputs = {
|
||||
cloudflare_account_id = local.cloudflare_account_id
|
||||
cloudflare_api_token = local.cloudflare_api_token
|
||||
tf_state_postgres_conn_str = local.tf_state_postgres_conn_str
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
{
|
||||
"$schema": "https://docs.renovatebot.com/renovate-schema.json",
|
||||
"extends": ["config:base", "docker:pinDigests"],
|
||||
"minimumReleaseAge": "5 days",
|
||||
"packageRules": [
|
||||
{
|
||||
"groupName": "core",
|
||||
"matchUpdateTypes": ["minor", "patch"],
|
||||
"excludePackageNames": ["node", "@types/node"],
|
||||
"schedule": "on tuesday"
|
||||
},
|
||||
{
|
||||
"groupName": "svelte",
|
||||
"matchUpdateTypes": ["major"],
|
||||
"matchPackagePrefixes": ["@sveltejs"],
|
||||
"schedule": "on tuesday"
|
||||
},
|
||||
{
|
||||
"matchFileNames": [".github/**"],
|
||||
"groupName": "github-actions",
|
||||
"schedule": "on tuesday"
|
||||
},
|
||||
{
|
||||
"matchDatasources": ["npm"],
|
||||
"rangeStrategy": "bump",
|
||||
"groupName": "node",
|
||||
"versioning": "node",
|
||||
"matchPackageNames": ["node", "@types/node"],
|
||||
"schedule": "on tuesday"
|
||||
},
|
||||
{
|
||||
"groupName": "node",
|
||||
"matchDatasources": ["docker"],
|
||||
"matchPackageNames": ["node"],
|
||||
"versionCompatibility": "^(?<version>[^-]+)(?<compatibility>-.*)?$",
|
||||
"versioning": "node",
|
||||
"schedule": "on tuesday"
|
||||
}
|
||||
],
|
||||
"labels": ["dependencies", "renovate"]
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
node_modules
|
||||
|
||||
# Output
|
||||
.output
|
||||
.vercel
|
||||
/.svelte-kit
|
||||
/build
|
||||
|
||||
# OS
|
||||
.DS_Store
|
||||
Thumbs.db
|
||||
|
||||
# Env
|
||||
.env
|
||||
.env.*
|
||||
!.env.example
|
||||
!.env.test
|
||||
|
||||
# Vite
|
||||
vite.config.js.timestamp-*
|
||||
vite.config.ts.timestamp-*
|
||||
@@ -0,0 +1 @@
|
||||
engine-strict=true
|
||||
@@ -0,0 +1 @@
|
||||
20.17
|
||||
@@ -0,0 +1,5 @@
|
||||
# Package Managers
|
||||
package-lock.json
|
||||
pnpm-lock.yaml
|
||||
yarn.lock
|
||||
src/lib/assets/data/*.json
|
||||
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"singleQuote": true,
|
||||
"trailingComma": "all",
|
||||
"printWidth": 120,
|
||||
"plugins": ["prettier-plugin-svelte"],
|
||||
"overrides": [{ "files": "*.svelte", "options": { "parser": "svelte" } }]
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
import js from '@eslint/js';
|
||||
import ts from 'typescript-eslint';
|
||||
import svelte from 'eslint-plugin-svelte';
|
||||
import prettier from 'eslint-config-prettier';
|
||||
import globals from 'globals';
|
||||
|
||||
/** @type {import('eslint').Linter.Config[]} */
|
||||
export default [
|
||||
js.configs.recommended,
|
||||
...ts.configs.recommended,
|
||||
...svelte.configs['flat/recommended'],
|
||||
prettier,
|
||||
...svelte.configs['flat/prettier'],
|
||||
{
|
||||
languageOptions: {
|
||||
globals: {
|
||||
...globals.browser,
|
||||
...globals.node,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
files: ['**/*.svelte'],
|
||||
languageOptions: {
|
||||
parserOptions: {
|
||||
parser: ts.parser,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
ignores: ['build/', '.svelte-kit/', 'dist/'],
|
||||
},
|
||||
];
|
||||
@@ -0,0 +1,3 @@
|
||||
IMMICH_APP=buy.immich.app
|
||||
PUBLIC_IMMICH_PAY_HOST=https://futopay-test.azurewebsites.net
|
||||
orderId=e1eddcf3-ae45-4124-bba0-f9c7ec67b255
|
||||
Generated
+6190
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,47 @@
|
||||
{
|
||||
"name": "my.immich.app",
|
||||
"version": "0.0.1",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"start": "vite dev",
|
||||
"build": "npm run sync && vite build",
|
||||
"preview": "vite preview",
|
||||
"check": "npm run sync && svelte-check --tsconfig ./tsconfig.json",
|
||||
"sync": "svelte-kit sync",
|
||||
"test": "vitest",
|
||||
"lint": "prettier --check . && eslint . --max-warnings 0",
|
||||
"lint:fix": "npm run lint -- --fix",
|
||||
"format": "prettier --check .",
|
||||
"format:fix": "prettier --write ."
|
||||
},
|
||||
"devDependencies": {
|
||||
"@sveltejs/adapter-static": "^3.0.2",
|
||||
"@sveltejs/kit": "^2.0.0",
|
||||
"@sveltejs/vite-plugin-svelte": "^3.0.0",
|
||||
"@types/eslint": "^9.0.0",
|
||||
"@types/luxon": "^3.4.2",
|
||||
"autoprefixer": "^10.4.19",
|
||||
"eslint": "^9.0.0",
|
||||
"eslint-config-prettier": "^9.1.0",
|
||||
"eslint-plugin-svelte": "^2.36.0",
|
||||
"globals": "^15.0.0",
|
||||
"postcss": "^8.4.39",
|
||||
"prettier": "^3.1.1",
|
||||
"prettier-plugin-svelte": "^3.1.2",
|
||||
"svelte": "^4.2.7",
|
||||
"svelte-check": "^4.0.0",
|
||||
"tailwindcss": "^3.4.4",
|
||||
"tslib": "^2.4.1",
|
||||
"typescript": "^5.0.0",
|
||||
"typescript-eslint": "^8.0.0-alpha.20",
|
||||
"vite": "^5.0.3",
|
||||
"vitest": "^2.0.0"
|
||||
},
|
||||
"type": "module",
|
||||
"dependencies": {
|
||||
"@mdi/js": "^7.4.47",
|
||||
"@unovis/svelte": "^1.4.3-beta.0",
|
||||
"@unovis/ts": "^1.4.3-beta.0",
|
||||
"luxon": "^3.5.0"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
export default {
|
||||
plugins: {
|
||||
tailwindcss: {},
|
||||
autoprefixer: {},
|
||||
},
|
||||
};
|
||||
Vendored
+13
@@ -0,0 +1,13 @@
|
||||
// See https://kit.svelte.dev/docs/types#app
|
||||
// for information about these interfaces
|
||||
declare global {
|
||||
namespace App {
|
||||
// interface Error {}
|
||||
// interface Locals {}
|
||||
// interface PageData {}
|
||||
// interface PageState {}
|
||||
// interface Platform {}
|
||||
}
|
||||
}
|
||||
|
||||
export {};
|
||||
@@ -0,0 +1,16 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<link rel="icon" href="%sveltekit.assets%/favicon.ico" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<title>Immich - Data</title>
|
||||
<meta name="theme-color" content="currentColor" />
|
||||
<meta name="description" content="Graphs and charts for data around Immich" />
|
||||
|
||||
%sveltekit.head%
|
||||
</head>
|
||||
<body data-sveltekit-preload-data="hover" class="bg-gray-200">
|
||||
<div style="display: contents">%sveltekit.body%</div>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,7 @@
|
||||
import { describe, it, expect } from 'vitest';
|
||||
|
||||
describe('sum test', () => {
|
||||
it('adds 1 + 2 to equal 3', () => {
|
||||
expect(1 + 2).toBe(3);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,77 @@
|
||||
@tailwind base;
|
||||
@tailwind components;
|
||||
@tailwind utilities;
|
||||
|
||||
@layer base {
|
||||
:root {
|
||||
/* light */
|
||||
--immich-primary: 66 80 175;
|
||||
--immich-bg: 255 255 255;
|
||||
--immich-fg: 0 0 0;
|
||||
--immich-gray: 246 246 244;
|
||||
--immich-error: 229 115 115;
|
||||
--immich-success: 129 199 132;
|
||||
--immich-warning: 255 183 77;
|
||||
|
||||
/* dark */
|
||||
--immich-dark-primary: 172 203 250;
|
||||
--immich-dark-bg: 0 0 0;
|
||||
--immich-dark-fg: 229 231 235;
|
||||
--immich-dark-gray: 33 33 33;
|
||||
--immich-dark-error: 211 47 47;
|
||||
--immich-dark-success: 56 142 60;
|
||||
--immich-dark-warning: 245 124 0;
|
||||
}
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'Overpass';
|
||||
src: url('$lib/assets/fonts/overpass/Overpass.ttf') format('truetype-variations');
|
||||
font-weight: 1 999;
|
||||
font-style: normal;
|
||||
ascent-override: 100%;
|
||||
}
|
||||
|
||||
:root {
|
||||
font-family: 'Overpass', sans-serif;
|
||||
}
|
||||
|
||||
:root.dark {
|
||||
color-scheme: dark;
|
||||
}
|
||||
|
||||
:root:not(.dark) {
|
||||
color-scheme: light;
|
||||
}
|
||||
|
||||
html {
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
font-size: 17px;
|
||||
}
|
||||
|
||||
body {
|
||||
margin: 0;
|
||||
color: #3a3a3a;
|
||||
}
|
||||
|
||||
@layer utilities {
|
||||
.immich-gradient {
|
||||
background:
|
||||
linear-gradient(to bottom right, #ededed 0%, #f0f1fc 50%) bottom right / 50% 50% no-repeat,
|
||||
linear-gradient(to bottom left, #ededed 0%, #f0f1fc 50%) bottom left / 50% 50% no-repeat,
|
||||
linear-gradient(to top left, #ededed 0%, #f0f1fc 50%) top left / 50% 50% no-repeat,
|
||||
linear-gradient(to top right, #ededed 0%, #f0f1fc 50%) top right / 50% 50% no-repeat;
|
||||
}
|
||||
}
|
||||
|
||||
.area-graph {
|
||||
--vis-area-cursor: default;
|
||||
--vis-area-fill-opacity: 1;
|
||||
--vis-area-stroke-color: none;
|
||||
--vis-area-stroke-width: 0px;
|
||||
--vis-area-stroke-dasharray: none;
|
||||
--vis-area-stroke-opacity: 1;
|
||||
--vis-area-hover-fill-opacity: none;
|
||||
--vis-area-hover-stroke-width: none;
|
||||
}
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,84 @@
|
||||
<script lang="ts" context="module">
|
||||
export type Type = 'button' | 'submit' | 'reset';
|
||||
export type Color =
|
||||
| 'primary'
|
||||
| 'secondary'
|
||||
| 'transparent-primary'
|
||||
| 'text-primary'
|
||||
| 'light-red'
|
||||
| 'red'
|
||||
| 'green'
|
||||
| 'gray'
|
||||
| 'transparent-gray'
|
||||
| 'dark-gray'
|
||||
| 'overlay-primary';
|
||||
export type Size = 'tiny' | 'icon' | 'link' | 'sm' | 'base' | 'lg';
|
||||
export type Rounded = 'lg' | '3xl' | 'full' | false;
|
||||
export type Shadow = 'md' | false;
|
||||
</script>
|
||||
|
||||
<script lang="ts">
|
||||
export let type: Type = 'button';
|
||||
export let color: Color = 'primary';
|
||||
export let size: Size = 'base';
|
||||
export let rounded: Rounded = '3xl';
|
||||
export let shadow: Shadow = 'md';
|
||||
export let disabled = false;
|
||||
export let fullwidth = false;
|
||||
export let border = false;
|
||||
export let title: string | undefined = '';
|
||||
export let form: string | undefined = undefined;
|
||||
|
||||
let className = '';
|
||||
export { className as class };
|
||||
|
||||
const colorClasses: Record<Color, string> = {
|
||||
primary:
|
||||
'bg-immich-primary dark:bg-immich-dark-primary text-white dark:text-immich-dark-gray enabled:dark:hover:bg-immich-dark-primary/80 enabled:hover:bg-immich-primary/90',
|
||||
secondary:
|
||||
'bg-gray-500 dark:bg-gray-200 text-white dark:text-immich-dark-gray enabled:hover:bg-gray-500/90 enabled:dark:hover:bg-gray-200/90',
|
||||
'transparent-primary':
|
||||
'text-gray-500 dark:text-immich-dark-primary enabled:hover:bg-gray-100 enabled:dark:hover:bg-gray-700',
|
||||
'text-primary':
|
||||
'text-immich-primary dark:text-immich-dark-primary enabled:dark:hover:bg-immich-dark-primary/10 enabled:hover:bg-immich-primary/10',
|
||||
'light-red': 'bg-[#F9DEDC] text-[#410E0B] enabled:hover:bg-red-50',
|
||||
red: 'bg-red-500 text-white enabled:hover:bg-red-400',
|
||||
green: 'bg-green-400 text-gray-800 enabled:hover:bg-green-400/90',
|
||||
gray: 'bg-gray-500 dark:bg-gray-200 enabled:hover:bg-gray-500/75 enabled:dark:hover:bg-gray-200/80 text-white dark:text-immich-dark-gray',
|
||||
'transparent-gray':
|
||||
'dark:text-immich-dark-fg enabled:hover:bg-immich-primary/5 enabled:hover:text-gray-700 enabled:hover:dark:text-immich-dark-fg enabled:dark:hover:bg-immich-dark-primary/25',
|
||||
'dark-gray':
|
||||
'dark:border-immich-dark-gray dark:bg-gray-500 enabled:dark:hover:bg-immich-dark-primary/50 enabled:hover:bg-immich-primary/10 dark:text-white',
|
||||
'overlay-primary': 'text-gray-500 enabled:hover:bg-gray-100',
|
||||
};
|
||||
|
||||
const sizeClasses: Record<Size, string> = {
|
||||
tiny: 'p-0 ml-2 mr-0 align-top',
|
||||
icon: 'p-2.5',
|
||||
link: 'p-2 font-medium',
|
||||
sm: 'px-4 py-2 text-sm font-medium',
|
||||
base: 'px-6 py-3 font-medium',
|
||||
lg: 'px-6 py-4 font-semibold',
|
||||
};
|
||||
</script>
|
||||
|
||||
<button
|
||||
{type}
|
||||
{disabled}
|
||||
{title}
|
||||
{form}
|
||||
on:click
|
||||
on:focus
|
||||
on:blur
|
||||
class="{className} inline-flex items-center justify-center transition-colors disabled:cursor-not-allowed disabled:opacity-60 {colorClasses[
|
||||
color
|
||||
]} {sizeClasses[size]}"
|
||||
class:rounded-lg={rounded === 'lg'}
|
||||
class:rounded-3xl={rounded === '3xl'}
|
||||
class:rounded-full={rounded === 'full'}
|
||||
class:shadow-md={shadow === 'md'}
|
||||
class:w-full={fullwidth}
|
||||
class:border
|
||||
>
|
||||
<slot />
|
||||
</button>
|
||||
@@ -0,0 +1,28 @@
|
||||
<script lang="ts">
|
||||
import Icon from '$lib/components/icon.svelte';
|
||||
import LoadingSpinner from '$lib/components/loading-spinner.svelte';
|
||||
import { mdiAlertCircleOutline, mdiCheckCircleOutline } from '@mdi/js';
|
||||
import { fade } from 'svelte/transition';
|
||||
|
||||
export let status: 'loading' | 'success' | 'error' | undefined = undefined;
|
||||
</script>
|
||||
|
||||
<div
|
||||
class="flex gap-4 flex-col place-content-center place-items-center text-center mt-4 justify-between relative border p-10 rounded-3xl bg-gray-100"
|
||||
>
|
||||
<div class="absolute -top-[24px] left-[calc(50%-24px)]">
|
||||
{#if status === 'loading'}
|
||||
<div in:fade={{ duration: 200 }}>
|
||||
<div class="bg-immich-bg rounded-full p-1 border">
|
||||
<LoadingSpinner size="48" />
|
||||
</div>
|
||||
</div>
|
||||
{:else if status === 'success'}
|
||||
<Icon path={mdiCheckCircleOutline} size="48" class="text-white rounded-full bg-immich-primary" />
|
||||
{:else if status === 'error'}
|
||||
<Icon path={mdiAlertCircleOutline} size="48" class="text-white rounded-full bg-red-500" />
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
<slot />
|
||||
</div>
|
||||
@@ -0,0 +1,26 @@
|
||||
<script lang="ts">
|
||||
import '$lib/app.css';
|
||||
import starData from '$lib/assets/data/star-data.json';
|
||||
import { VisAxis, VisCrosshair, VisArea, VisTooltip, VisXYContainer } from '@unovis/svelte';
|
||||
import { DateTime } from 'luxon';
|
||||
|
||||
type DataRecord = [DateTime, number];
|
||||
|
||||
const data = starData.map(([timestamp, value]) => [DateTime.fromSeconds(timestamp), value]);
|
||||
const x = ([timestamp]: DataRecord) => timestamp.toMillis();
|
||||
const y = ([, value]: DataRecord) => value;
|
||||
const tickFormatX = (value: number) => DateTime.fromMillis(value).toFormat('MMM yy');
|
||||
const tickFormatY = (i: number) =>
|
||||
new Intl.NumberFormat(navigator.language, { maximumSignificantDigits: 3 }).format(i);
|
||||
const template = ([timestamp, value]: DataRecord) =>
|
||||
`${timestamp.toLocaleString()} - ${value.toLocaleString()} discussions`;
|
||||
</script>
|
||||
|
||||
<VisXYContainer {data} height={250} class="area-graph">
|
||||
<VisArea {x} {y} color="royalblue" />
|
||||
<!-- <VisBulletLegend {items} {onLegendItemClick} bulletSize="15px" /> -->
|
||||
<VisTooltip />
|
||||
<VisCrosshair {x} {y} {template} />
|
||||
<VisAxis tickFormat={tickFormatX} type="x" numTicks={6} gridLine={false} />
|
||||
<VisAxis tickFormat={tickFormatY} type="y" numTicks={4} gridLine={true} />
|
||||
</VisXYContainer>
|
||||
@@ -0,0 +1,25 @@
|
||||
<script lang="ts">
|
||||
import '$lib/app.css';
|
||||
import issueData from '$lib/assets/data/issue-data.json';
|
||||
import { VisAxis, VisCrosshair, VisArea, VisTooltip, VisXYContainer } from '@unovis/svelte';
|
||||
import { DateTime } from 'luxon';
|
||||
|
||||
type DataRecord = [DateTime, number, number, number, number];
|
||||
|
||||
const data = issueData.map(([timestamp, ...rest]) => [DateTime.fromSeconds(timestamp), ...rest]);
|
||||
const x = ([timestamp]: DataRecord) => timestamp.toMillis();
|
||||
const y = ([, , , total]: DataRecord) => total;
|
||||
const tickFormatX = (value: number) => DateTime.fromMillis(value).toFormat('MMM yy');
|
||||
const tickFormatY = (i: number) =>
|
||||
new Intl.NumberFormat(navigator.language, { maximumSignificantDigits: 3 }).format(i);
|
||||
const template = ([timestamp, value]: DataRecord) =>
|
||||
`${timestamp.toLocaleString()} - ${value.toLocaleString()} open issues`;
|
||||
</script>
|
||||
|
||||
<VisXYContainer {data} height={250} class="area-graph">
|
||||
<VisArea {x} {y} color="#3fb950" />
|
||||
<VisTooltip />
|
||||
<VisCrosshair {x} {y} {template} />
|
||||
<VisAxis tickFormat={tickFormatX} type="x" numTicks={6} gridLine={false} />
|
||||
<VisAxis tickFormat={tickFormatY} type="y" numTicks={4} gridLine={true} />
|
||||
</VisXYContainer>
|
||||
@@ -0,0 +1,31 @@
|
||||
<script lang="ts">
|
||||
import '$lib/app.css';
|
||||
import prData from '$lib/assets/data/pr-data.json';
|
||||
import { VisAxis, VisCrosshair, VisArea, VisTooltip, VisXYContainer } from '@unovis/svelte';
|
||||
import { DateTime } from 'luxon';
|
||||
|
||||
type DataRecord = [DateTime, number, number, number];
|
||||
|
||||
// remove headers
|
||||
prData.shift();
|
||||
|
||||
const data = (prData as Array<[number, number, number, number]>).map(([timestamp, , , total]) => [
|
||||
DateTime.fromSeconds(timestamp),
|
||||
total,
|
||||
]);
|
||||
const x = ([timestamp]: DataRecord) => timestamp.toMillis();
|
||||
const y = ([, value]: DataRecord) => value;
|
||||
const tickFormatX = (value: number) => DateTime.fromMillis(value).toFormat('MMM yy');
|
||||
const tickFormatY = (i: number) =>
|
||||
new Intl.NumberFormat(navigator.language, { maximumSignificantDigits: 3 }).format(i);
|
||||
const template = ([timestamp, value]: DataRecord) =>
|
||||
`${timestamp.toLocaleString()} - ${value.toLocaleString()} open pull requests`;
|
||||
</script>
|
||||
|
||||
<VisXYContainer {data} height={250} class="area-graph">
|
||||
<VisArea {x} {y} color="#ab7df8" />
|
||||
<VisTooltip />
|
||||
<VisCrosshair {x} {y} {template} />
|
||||
<VisAxis tickFormat={tickFormatX} type="x" numTicks={6} gridLine={false} />
|
||||
<VisAxis tickFormat={tickFormatY} type="y" numTicks={4} gridLine={true} />
|
||||
</VisXYContainer>
|
||||
@@ -0,0 +1,25 @@
|
||||
<script lang="ts">
|
||||
import '$lib/app.css';
|
||||
import starData from '$lib/assets/data/star-data.json';
|
||||
import { VisAxis, VisCrosshair, VisArea, VisTooltip, VisXYContainer } from '@unovis/svelte';
|
||||
import { DateTime } from 'luxon';
|
||||
|
||||
type DataRecord = [DateTime, number];
|
||||
|
||||
const data = starData.map(([timestamp, value]) => [DateTime.fromSeconds(timestamp), value]);
|
||||
const x = ([timestamp]: DataRecord) => timestamp.toMillis();
|
||||
const y = ([, value]: DataRecord) => value;
|
||||
const tickFormatX = (value: number) => DateTime.fromMillis(value).toFormat('MMM yy');
|
||||
const tickFormatY = (i: number) =>
|
||||
new Intl.NumberFormat(navigator.language, { maximumSignificantDigits: 3 }).format(i);
|
||||
const template = ([timestamp, value]: DataRecord) =>
|
||||
`${timestamp.toLocaleString()} - ${value.toLocaleString()} stars`;
|
||||
</script>
|
||||
|
||||
<VisXYContainer {data} height={250} class="area-graph">
|
||||
<VisArea {x} {y} color="#ffc501" />
|
||||
<VisTooltip />
|
||||
<VisCrosshair {x} {y} {template} />
|
||||
<VisAxis tickFormat={tickFormatX} type="x" numTicks={6} gridLine={false} />
|
||||
<VisAxis tickFormat={tickFormatY} type="y" numTicks={4} gridLine={true} />
|
||||
</VisXYContainer>
|
||||
@@ -0,0 +1,36 @@
|
||||
<script lang="ts">
|
||||
import type { AriaRole } from 'svelte/elements';
|
||||
|
||||
export let size: string | number = '1em';
|
||||
export let color = 'currentColor';
|
||||
export let path: string;
|
||||
export let title: string | null = null;
|
||||
export let desc = '';
|
||||
export let flipped = false;
|
||||
let className = '';
|
||||
export { className as class };
|
||||
export let viewBox = '0 0 24 24';
|
||||
export let role: AriaRole = 'img';
|
||||
export let ariaHidden: boolean | undefined = undefined;
|
||||
export let ariaLabel: string | undefined = undefined;
|
||||
export let ariaLabelledby: string | undefined = undefined;
|
||||
</script>
|
||||
|
||||
<svg
|
||||
width={size}
|
||||
height={size}
|
||||
{viewBox}
|
||||
class="{className} {flipped ? '-scale-x-100' : ''}"
|
||||
{role}
|
||||
aria-label={ariaLabel}
|
||||
aria-hidden={ariaHidden}
|
||||
aria-labelledby={ariaLabelledby}
|
||||
>
|
||||
{#if title}
|
||||
<title>{title}</title>
|
||||
{/if}
|
||||
{#if desc}
|
||||
<desc>{desc}</desc>
|
||||
{/if}
|
||||
<path d={path} fill={color} />
|
||||
</svg>
|
||||
@@ -0,0 +1,24 @@
|
||||
<script lang="ts">
|
||||
export let size: string = '24';
|
||||
</script>
|
||||
|
||||
<div>
|
||||
<svg
|
||||
role="status"
|
||||
style:height="{size}px"
|
||||
style:width="{size}px"
|
||||
class="animate-spin fill-immich-primary text-gray-400 dark:text-gray-600"
|
||||
viewBox="0 0 100 101"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
d="M100 50.5908C100 78.2051 77.6142 100.591 50 100.591C22.3858 100.591 0 78.2051 0 50.5908C0 22.9766 22.3858 0.59082 50 0.59082C77.6142 0.59082 100 22.9766 100 50.5908ZM9.08144 50.5908C9.08144 73.1895 27.4013 91.5094 50 91.5094C72.5987 91.5094 90.9186 73.1895 90.9186 50.5908C90.9186 27.9921 72.5987 9.67226 50 9.67226C27.4013 9.67226 9.08144 27.9921 9.08144 50.5908Z"
|
||||
fill="currentColor"
|
||||
/>
|
||||
<path
|
||||
d="M93.9676 39.0409C96.393 38.4038 97.8624 35.9116 97.0079 33.5539C95.2932 28.8227 92.871 24.3692 89.8167 20.348C85.8452 15.1192 80.8826 10.7238 75.2124 7.41289C69.5422 4.10194 63.2754 1.94025 56.7698 1.05124C51.7666 0.367541 46.6976 0.446843 41.7345 1.27873C39.2613 1.69328 37.813 4.19778 38.4501 6.62326C39.0873 9.04874 41.5694 10.4717 44.0505 10.1071C47.8511 9.54855 51.7191 9.52689 55.5402 10.0491C60.8642 10.7766 65.9928 12.5457 70.6331 15.2552C75.2735 17.9648 79.3347 21.5619 82.5849 25.841C84.9175 28.9121 86.7997 32.2913 88.1811 35.8758C89.083 38.2158 91.5421 39.6781 93.9676 39.0409Z"
|
||||
fill="currentFill"
|
||||
/>
|
||||
</svg>
|
||||
</div>
|
||||
@@ -0,0 +1,7 @@
|
||||
// place files you want to import through the `$lib` alias in this folder.
|
||||
|
||||
export enum StorageKey {
|
||||
INSTANCE_URL = 'immich-instance-url',
|
||||
}
|
||||
|
||||
export type Fetch = typeof fetch;
|
||||
@@ -0,0 +1,8 @@
|
||||
<script lang="ts">
|
||||
import '$lib/app.css';
|
||||
// document.documentElement.classList.add('dark');
|
||||
</script>
|
||||
|
||||
<section class="h-full flex flex-col align-center gap-2 max-w-screen-lg mx-auto bg-white pb-36">
|
||||
<slot />
|
||||
</section>
|
||||
@@ -0,0 +1,57 @@
|
||||
<script lang="ts">
|
||||
import '$lib/app.css';
|
||||
import GithubDiscussionGraph from '$lib/components/graphs/github-discussion-graph.svelte';
|
||||
import GithubIssueGraph from '$lib/components/graphs/github-issue-graph.svelte';
|
||||
import GithubPullRequestGraph from '$lib/components/graphs/github-pull-request-graph.svelte';
|
||||
import GithubStarsGraph from '$lib/components/graphs/github-stars-graph.svelte';
|
||||
import Icon from '$lib/components/icon.svelte';
|
||||
import { mdiBug, mdiGithub, mdiMessageOutline, mdiSourceBranch, mdiStarOutline } from '@mdi/js';
|
||||
</script>
|
||||
|
||||
<main class="p-4 md:p-8">
|
||||
<div
|
||||
class="flex flex-col align-center gap-2 dark:border-immich-dark-gray dark:bg-immich-dark-gray rounded-lg md:rounded-2xl"
|
||||
>
|
||||
<div class="w-full h-full flex gap-2 place-items-center mb-2">
|
||||
<img src="/img/immich-logo.svg" alt={'immich-logo'} class="h-12 w-12" />
|
||||
<p class="dark:text-gray-100 text-2xl font-medium text-immich-primary">Immich Data</p>
|
||||
</div>
|
||||
|
||||
<section class="flex flex-col gap-4">
|
||||
<h2 class="flex gap-1 text-xl">
|
||||
<Icon path={mdiGithub} size="24" />
|
||||
<span>Repro Trends</span>
|
||||
</h2>
|
||||
<div class="grid grid-cols-1 lg:grid-cols-2 gap-4">
|
||||
<div>
|
||||
<h3 class="flex gap-1 text-lg">
|
||||
<Icon path={mdiStarOutline} size="24" />
|
||||
<span>Stars</span>
|
||||
</h3>
|
||||
<GithubStarsGraph />
|
||||
</div>
|
||||
<div>
|
||||
<h3 class="flex gap-1 text-lg">
|
||||
<Icon path={mdiBug} size="24" />
|
||||
<span>Open Issues</span>
|
||||
</h3>
|
||||
<GithubIssueGraph />
|
||||
</div>
|
||||
<div>
|
||||
<h3 class="flex gap-1 text-lg">
|
||||
<Icon path={mdiSourceBranch} size="24" />
|
||||
<span>Open Pull Requests</span>
|
||||
</h3>
|
||||
<GithubPullRequestGraph />
|
||||
</div>
|
||||
<div>
|
||||
<h3 class="flex gap-1 text-lg">
|
||||
<Icon path={mdiMessageOutline} size="24" />
|
||||
<span>Total Discussions</span>
|
||||
</h3>
|
||||
<GithubDiscussionGraph />
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
</main>
|
||||
@@ -0,0 +1 @@
|
||||
export const ssr = false;
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 15 KiB |
@@ -0,0 +1,62 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Generator: Adobe Illustrator 28.3.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<svg version="1.1" id="Router_Medium_x5F_White" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
x="0px" y="0px" viewBox="0 0 792 266.25" style="enable-background:new 0 0 792 266.25;" xml:space="preserve">
|
||||
<style type="text/css">
|
||||
.st0{fill:#4251B0;}
|
||||
.st1{fill:#FA2921;}
|
||||
.st2{fill:#ED79B5;}
|
||||
.st3{fill:#FFB400;}
|
||||
.st4{fill:#1E83F7;}
|
||||
.st5{fill:#18C249;}
|
||||
</style>
|
||||
<g>
|
||||
<path class="st0" d="M268.73,63.18c6.34,0,11.52,5.18,11.52,11.35c0,6.34-5.18,11.35-11.52,11.35s-11.69-5.01-11.69-11.35
|
||||
C257.04,68.36,262.39,63.18,268.73,63.18z M258.88,122.45c0-3.01-0.67-7.85-0.67-10.68c0-6.01,4.67-10.68,10.52-10.68
|
||||
c5.84,0,10.52,4.67,10.52,10.68c0,2.84-0.83,7.68-0.83,10.68v38.73c0,3.01,0.83,7.85,0.83,10.68c0,6.01-4.67,10.68-10.52,10.68
|
||||
c-5.84,0-10.52-4.67-10.52-10.68c0-2.84,0.67-7.68,0.67-10.68V122.45z"/>
|
||||
<path class="st0" d="M394.28,171.87c0-2.84,0.83-7.68,0.83-10.68V132.3c0-10.18-5.34-16.86-14.52-16.86c-6.01,0-11.35,3-14.86,8.85
|
||||
c0.33,1.84,0.5,3.67,0.5,5.68v31.22c0,3.01,0.83,7.85,0.83,10.68c0,6.01-4.67,10.68-10.68,10.68c-5.51,0-10.35-4.67-10.35-10.68
|
||||
c0-2.84,0.83-7.68,0.83-10.68V131.8c0-3.17-0.5-6.01-1.67-8.51c-2.17-4.84-6.51-7.85-12.52-7.85c-6.18,0-11.19,3.17-14.86,8.85
|
||||
v36.9c0,3.01,0.83,7.85,0.83,10.68c0,6.01-4.84,10.68-10.52,10.68c-5.84,0-10.52-4.67-10.52-10.68c0-2.84,0.67-7.68,0.67-10.68
|
||||
v-38.57c0-3.01-1.5-8.35-1.5-10.85c0-6.01,4.34-10.68,10.18-10.68c5.51,0,8.68,3.67,9.68,8.51c5.01-6.68,12.02-10.85,21.2-10.85
|
||||
c10.85,0,18.7,5.18,23.54,13.52c5.51-8.68,13.52-13.52,23.54-13.52c16.86,0,29.72,12.19,29.72,31.72v30.72
|
||||
c0,3.01,0.67,7.85,0.67,10.68c0,6.01-4.51,10.68-10.52,10.68C399.12,182.55,394.28,177.88,394.28,171.87z"/>
|
||||
<path class="st0" d="M528.5,171.87c0-2.84,0.83-7.68,0.83-10.68V132.3c0-10.18-5.34-16.86-14.52-16.86c-6.01,0-11.35,3-14.86,8.85
|
||||
c0.33,1.84,0.5,3.67,0.5,5.68v31.22c0,3.01,0.84,7.85,0.84,10.68c0,6.01-4.67,10.68-10.68,10.68c-5.51,0-10.35-4.67-10.35-10.68
|
||||
c0-2.84,0.84-7.68,0.84-10.68V131.8c0-3.17-0.5-6.01-1.67-8.51c-2.17-4.84-6.51-7.85-12.52-7.85c-6.18,0-11.19,3.17-14.86,8.85
|
||||
v36.9c0,3.01,0.83,7.85,0.83,10.68c0,6.01-4.84,10.68-10.52,10.68c-5.84,0-10.52-4.67-10.52-10.68c0-2.84,0.67-7.68,0.67-10.68
|
||||
v-38.57c0-3.01-1.5-8.35-1.5-10.85c0-6.01,4.34-10.68,10.18-10.68c5.51,0,8.68,3.67,9.68,8.51c5.01-6.68,12.02-10.85,21.2-10.85
|
||||
c10.85,0,18.7,5.18,23.54,13.52c5.51-8.68,13.52-13.52,23.54-13.52c16.86,0,29.72,12.19,29.72,31.72v30.72
|
||||
c0,3.01,0.67,7.85,0.67,10.68c0,6.01-4.51,10.68-10.52,10.68C533.35,182.55,528.5,177.88,528.5,171.87z"/>
|
||||
<path class="st0" d="M576.92,63.18c6.34,0,11.52,5.18,11.52,11.35c0,6.34-5.18,11.35-11.52,11.35s-11.69-5.01-11.69-11.35
|
||||
C565.23,68.36,570.57,63.18,576.92,63.18z M567.07,122.45c0-3.01-0.67-7.85-0.67-10.68c0-6.01,4.67-10.68,10.52-10.68
|
||||
s10.52,4.67,10.52,10.68c0,2.84-0.84,7.68-0.84,10.68v38.73c0,3.01,0.84,7.85,0.84,10.68c0,6.01-4.67,10.68-10.52,10.68
|
||||
s-10.52-4.67-10.52-10.68c0-2.84,0.67-7.68,0.67-10.68V122.45z"/>
|
||||
<path class="st0" d="M601.79,141.31c0-23.54,14.69-42.57,39.07-42.57c12.86,0,24.71,5.84,30.05,14.53c2,3.17,2.34,5.01,2.34,6.51
|
||||
c0,5.18-4.01,9.52-9.85,9.52c-3.84,0-7.34-2.17-8.85-6.01c-2.34-5.18-6.85-8.18-13.69-8.18c-12.86,0-20.03,11.52-20.03,26.04
|
||||
c0,14.69,7.51,26.04,20.53,26.04c7.01,0,12.02-2.5,14.36-7.68c1.67-3.51,4.84-6.51,9.18-6.51c6.01,0,9.68,4.17,9.68,9.35
|
||||
c0,2.5-1,5.51-3.17,8.35c-5.51,7.35-15.86,13.19-30.05,13.19C616.32,183.89,601.79,165.19,601.79,141.31z"/>
|
||||
<path class="st0" d="M737.69,171.87c0-2.84,0.67-7.68,0.67-10.68v-28.55c0-10.18-5.68-17.2-15.36-17.2
|
||||
c-6.68,0-12.35,3.17-16.03,8.35v37.4c0,3.01,0.67,7.85,0.67,10.68c0,6.01-4.67,10.68-10.52,10.68s-10.52-4.67-10.52-10.68
|
||||
c0-2.84,0.84-7.68,0.84-10.68v-80.8c0-3.01-0.84-7.85-0.84-10.68c0-6.01,4.84-10.68,10.52-10.68c5.84,0,10.52,4.67,10.52,10.68
|
||||
c0,2.84-0.67,7.68-0.67,10.68v27.21c5.01-5.51,12.19-8.85,21.37-8.85c17.2,0,29.55,12.86,29.55,31.22v31.22
|
||||
c0,3.01,0.83,7.85,0.83,10.68c0,6.01-4.84,10.68-10.52,10.68C742.36,182.55,737.69,177.88,737.69,171.87z"/>
|
||||
</g>
|
||||
<g>
|
||||
<path class="st1" d="M114.82,96.21c11.92,10.55,21.52,21.86,27.7,32.52c10.62-18.99,17.71-41.55,17.8-55.92c0-0.1,0-0.19,0-0.28
|
||||
c0-21.26-21.21-29.54-39.48-29.54s-39.48,8.28-39.48,29.54c0,0.29,0,0.68,0,1.15C91.54,78.2,103.61,86.29,114.82,96.21z"/>
|
||||
<path class="st2" d="M49.8,154.19c7.45-8.29,18.88-17.27,31.77-24.86c13.72-8.07,27.44-13.71,39.49-16.3
|
||||
c-14.78-15.96-34.04-29.68-47.68-34.21c-0.1-0.03-0.18-0.06-0.27-0.09c-20.22-6.57-34.65,11.05-40.3,28.42s-4.33,40.11,15.89,46.68
|
||||
C48.99,153.93,49.35,154.05,49.8,154.19z"/>
|
||||
<path class="st3" d="M209.07,106.86c-5.65-17.38-20.07-34.99-40.3-28.42c-0.28,0.09-0.65,0.21-1.09,0.35
|
||||
c-1.16,11.08-5.12,25.07-11.09,38.79c-6.35,14.6-14.14,27.23-22.36,36.39c21.34,4.23,44.99,4,58.68-0.35
|
||||
c0.1-0.03,0.19-0.06,0.27-0.09C213.4,146.97,214.71,124.24,209.07,106.86z"/>
|
||||
<path class="st4" d="M102.8,171.18c-3.44-15.54-4.56-30.34-3.3-42.59c-19.75,9.12-38.75,23.2-47.27,34.78
|
||||
c-0.06,0.08-0.11,0.16-0.16,0.23c-12.5,17.2-0.2,36.37,14.58,47.11s36.81,16.51,49.31-0.69c0.17-0.24,0.4-0.55,0.68-0.93
|
||||
C111.05,199.44,106.04,185.79,102.8,171.18z"/>
|
||||
<path class="st5" d="M189.48,162.49c-10.9,2.33-25.42,2.88-40.32,1.44c-15.84-1.53-30.26-5.03-41.52-10.02
|
||||
c2.57,21.6,10.09,44.02,18.47,55.7c0.06,0.08,0.11,0.16,0.16,0.23c12.5,17.2,34.52,11.43,49.31,0.69
|
||||
c14.78-10.74,27.08-29.9,14.58-47.11C189.99,163.18,189.76,162.86,189.48,162.49z"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 5.4 KiB |
@@ -0,0 +1,66 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Generator: Adobe Illustrator 28.3.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<svg version="1.1" id="Router_Medium_x5F_Black_00000037681990313894948460000012967653829507626171_"
|
||||
xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="0 0 792 792"
|
||||
style="enable-background:new 0 0 792 792;" xml:space="preserve">
|
||||
<style type="text/css">
|
||||
.st0{fill:#ACCBFA;}
|
||||
.st1{fill:#FA2921;}
|
||||
.st2{fill:#ED79B5;}
|
||||
.st3{fill:#FFB400;}
|
||||
.st4{fill:#1E83F7;}
|
||||
.st5{fill:#18C249;}
|
||||
</style>
|
||||
<g>
|
||||
<path class="st0" d="M110.16,537.4c7.85,0,14.25,6.4,14.25,14.04c0,7.85-6.4,14.04-14.25,14.04s-14.45-6.19-14.45-14.04
|
||||
C95.71,543.8,102.32,537.4,110.16,537.4z M97.98,610.7c0-3.72-0.83-9.71-0.83-13.22c0-7.43,5.78-13.22,13.01-13.22
|
||||
s13.01,5.78,13.01,13.22c0,3.51-1.03,9.5-1.03,13.22v47.9c0,3.72,1.03,9.71,1.03,13.22c0,7.43-5.78,13.22-13.01,13.22
|
||||
s-13.01-5.78-13.01-13.22c0-3.51,0.83-9.5,0.83-13.22V610.7z"/>
|
||||
<path class="st0" d="M265.44,671.82c0-3.51,1.03-9.5,1.03-13.22v-35.72c0-12.6-6.61-20.85-17.96-20.85
|
||||
c-7.43,0-14.04,3.72-18.38,10.94c0.41,2.27,0.62,4.54,0.62,7.02v38.61c0,3.72,1.03,9.71,1.03,13.22c0,7.43-5.78,13.22-13.22,13.22
|
||||
c-6.81,0-12.8-5.78-12.8-13.22c0-3.51,1.03-9.5,1.03-13.22v-36.34c0-3.92-0.62-7.43-2.06-10.53c-2.69-5.99-8.05-9.71-15.49-9.71
|
||||
c-7.64,0-13.83,3.92-18.38,10.94v45.63c0,3.72,1.03,9.71,1.03,13.22c0,7.43-5.99,13.22-13.01,13.22c-7.23,0-13.01-5.78-13.01-13.22
|
||||
c0-3.51,0.83-9.5,0.83-13.22v-47.7c0-3.72-1.86-10.32-1.86-13.42c0-7.43,5.37-13.22,12.6-13.22c6.81,0,10.74,4.54,11.98,10.53
|
||||
c6.19-8.26,14.87-13.42,26.22-13.42c13.42,0,23.13,6.4,29.11,16.73c6.81-10.74,16.73-16.73,29.11-16.73
|
||||
c20.86,0,36.75,15.07,36.75,39.23v37.99c0,3.72,0.83,9.71,0.83,13.22c0,7.43-5.57,13.22-13.01,13.22
|
||||
C271.43,685.04,265.44,679.26,265.44,671.82z"/>
|
||||
<path class="st0" d="M431.45,671.82c0-3.51,1.03-9.5,1.03-13.22v-35.72c0-12.6-6.61-20.85-17.96-20.85
|
||||
c-7.43,0-14.04,3.72-18.38,10.94c0.41,2.27,0.62,4.54,0.62,7.02v38.61c0,3.72,1.03,9.71,1.03,13.22c0,7.43-5.78,13.22-13.22,13.22
|
||||
c-6.82,0-12.8-5.78-12.8-13.22c0-3.51,1.03-9.5,1.03-13.22v-36.34c0-3.92-0.62-7.43-2.06-10.53c-2.68-5.99-8.05-9.71-15.49-9.71
|
||||
c-7.64,0-13.83,3.92-18.38,10.94v45.63c0,3.72,1.03,9.71,1.03,13.22c0,7.43-5.99,13.22-13.01,13.22c-7.23,0-13.01-5.78-13.01-13.22
|
||||
c0-3.51,0.83-9.5,0.83-13.22v-47.7c0-3.72-1.86-10.32-1.86-13.42c0-7.43,5.37-13.22,12.6-13.22c6.82,0,10.74,4.54,11.98,10.53
|
||||
c6.2-8.26,14.87-13.42,26.22-13.42c13.42,0,23.13,6.4,29.11,16.73c6.81-10.74,16.72-16.73,29.11-16.73
|
||||
c20.86,0,36.75,15.07,36.75,39.23v37.99c0,3.72,0.83,9.71,0.83,13.22c0,7.43-5.57,13.22-13.01,13.22
|
||||
C437.44,685.04,431.45,679.26,431.45,671.82z"/>
|
||||
<path class="st0" d="M491.33,537.4c7.85,0,14.25,6.4,14.25,14.04c0,7.85-6.4,14.04-14.25,14.04s-14.45-6.19-14.45-14.04
|
||||
C476.87,543.8,483.48,537.4,491.33,537.4z M479.15,610.7c0-3.72-0.83-9.71-0.83-13.22c0-7.43,5.78-13.22,13.01-13.22
|
||||
s13.01,5.78,13.01,13.22c0,3.51-1.03,9.5-1.03,13.22v47.9c0,3.72,1.03,9.71,1.03,13.22c0,7.43-5.78,13.22-13.01,13.22
|
||||
s-13.01-5.78-13.01-13.22c0-3.51,0.83-9.5,0.83-13.22V610.7z"/>
|
||||
<path class="st0" d="M522.09,634.04c0-29.11,18.17-52.65,48.32-52.65c15.9,0,30.56,7.23,37.17,17.97c2.48,3.92,2.89,6.19,2.89,8.05
|
||||
c0,6.4-4.96,11.77-12.18,11.77c-4.75,0-9.08-2.68-10.94-7.43c-2.89-6.4-8.47-10.12-16.93-10.12c-15.9,0-24.78,14.25-24.78,32.21
|
||||
c0,18.17,9.29,32.21,25.4,32.21c8.67,0,14.87-3.1,17.76-9.5c2.06-4.34,5.99-8.05,11.36-8.05c7.43,0,11.98,5.16,11.98,11.56
|
||||
c0,3.1-1.24,6.81-3.92,10.32c-6.82,9.09-19.62,16.31-37.17,16.31C540.06,686.69,522.09,663.56,522.09,634.04z"/>
|
||||
<path class="st0" d="M690.17,671.82c0-3.51,0.83-9.5,0.83-13.22v-35.3c0-12.6-7.02-21.27-19-21.27c-8.26,0-15.28,3.92-19.82,10.32
|
||||
v46.25c0,3.72,0.83,9.71,0.83,13.22c0,7.43-5.78,13.22-13.01,13.22s-13.01-5.78-13.01-13.22c0-3.51,1.03-9.5,1.03-13.22v-99.94
|
||||
c0-3.72-1.03-9.71-1.03-13.22c0-7.43,5.99-13.22,13.01-13.22c7.23,0,13.01,5.78,13.01,13.22c0,3.51-0.83,9.5-0.83,13.22v33.66
|
||||
c6.2-6.81,15.07-10.94,26.43-10.94c21.27,0,36.55,15.9,36.55,38.61v38.61c0,3.72,1.03,9.71,1.03,13.22
|
||||
c0,7.43-5.99,13.22-13.01,13.22C695.95,685.04,690.17,679.26,690.17,671.82z"/>
|
||||
</g>
|
||||
<g>
|
||||
<path class="st1" d="M376.76,216.42c28.32,25.07,51.15,51.95,65.83,77.27c25.23-45.12,42.08-98.73,42.3-132.88
|
||||
c0-0.24,0-0.46,0-0.66c0-50.53-50.41-70.2-93.82-70.2s-93.82,19.66-93.82,70.2c0,0.69,0,1.62,0,2.73
|
||||
C321.44,173.62,350.14,192.84,376.76,216.42z"/>
|
||||
<path class="st2" d="M222.27,354.21c17.7-19.69,44.85-41.04,75.5-59.08c32.6-19.19,65.21-32.59,93.83-38.73
|
||||
c-35.11-37.94-80.89-70.53-113.31-81.29c-0.23-0.07-0.44-0.14-0.63-0.21c-48.06-15.61-82.34,26.25-95.75,67.54
|
||||
c-13.42,41.29-10.29,95.31,37.77,110.92C220.33,353.58,221.21,353.86,222.27,354.21z"/>
|
||||
<path class="st3" d="M600.73,241.74c-13.42-41.29-47.69-83.15-95.75-67.54c-0.66,0.21-1.54,0.5-2.6,0.84
|
||||
c-2.75,26.34-12.16,59.57-26.36,92.17c-15.09,34.68-33.6,64.69-53.14,86.48c50.7,10.05,106.9,9.52,139.45-0.83
|
||||
c0.23-0.07,0.44-0.14,0.63-0.21C611.02,337.05,614.15,283.03,600.73,241.74z"/>
|
||||
<path class="st4" d="M348.22,394.58c-8.17-36.93-10.84-72.09-7.84-101.2c-46.93,21.67-92.08,55.14-112.33,82.64
|
||||
c-0.14,0.19-0.27,0.37-0.39,0.54c-29.7,40.88-0.48,86.42,34.64,111.94s87.46,39.24,117.16-1.64c0.41-0.56,0.95-1.31,1.6-2.21
|
||||
C367.81,461.72,355.9,429.3,348.22,394.58z"/>
|
||||
<path class="st5" d="M554.19,373.91c-25.9,5.53-60.41,6.84-95.81,3.42c-37.65-3.64-71.91-11.96-98.67-23.82
|
||||
c6.11,51.33,23.99,104.61,43.89,132.37c0.14,0.19,0.27,0.37,0.39,0.54c29.7,40.88,82.04,27.16,117.16,1.64S585.5,417,555.8,376.12
|
||||
C555.39,375.56,554.85,374.81,554.19,373.91z"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 5.5 KiB |
@@ -0,0 +1,29 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Generator: Adobe Illustrator 28.3.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<svg version="1.1" id="Flower" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||
viewBox="0 0 792 792" style="enable-background:new 0 0 792 792;" xml:space="preserve">
|
||||
<style type="text/css">
|
||||
.st0{fill:#FA2921;}
|
||||
.st1{fill:#ED79B5;}
|
||||
.st2{fill:#FFB400;}
|
||||
.st3{fill:#1E83F7;}
|
||||
.st4{fill:#18C249;}
|
||||
</style>
|
||||
<g id="Flower_00000077325900055813483940000000694823054982625702_">
|
||||
<path class="st0" d="M375.48,267.63c38.64,34.21,69.78,70.87,89.82,105.42c34.42-61.56,57.42-134.71,57.71-181.3
|
||||
c0-0.33,0-0.63,0-0.91c0-68.94-68.77-95.77-128.01-95.77s-128.01,26.83-128.01,95.77c0,0.94,0,2.2,0,3.72
|
||||
C300.01,209.24,339.15,235.47,375.48,267.63z"/>
|
||||
<path class="st1" d="M164.7,455.63c24.15-26.87,61.2-55.99,103.01-80.61c44.48-26.18,88.97-44.47,128.02-52.84
|
||||
c-47.91-51.76-110.37-96.24-154.6-110.91c-0.31-0.1-0.6-0.19-0.86-0.28c-65.57-21.3-112.34,35.81-130.64,92.15
|
||||
c-18.3,56.34-14.04,130.04,51.53,151.34C162.05,454.77,163.25,455.16,164.7,455.63z"/>
|
||||
<path class="st2" d="M681.07,302.19c-18.3-56.34-65.07-113.45-130.64-92.15c-0.9,0.29-2.1,0.68-3.54,1.15
|
||||
c-3.75,35.93-16.6,81.27-35.96,125.76c-20.59,47.32-45.84,88.27-72.51,118c69.18,13.72,145.86,12.98,190.26-1.14
|
||||
c0.31-0.1,0.6-0.2,0.86-0.28C695.11,432.22,699.37,358.52,681.07,302.19z"/>
|
||||
<path class="st3" d="M336.54,510.71c-11.15-50.39-14.8-98.36-10.7-138.08c-64.03,29.57-125.63,75.23-153.26,112.76
|
||||
c-0.19,0.26-0.37,0.51-0.53,0.73c-40.52,55.78-0.66,117.91,47.27,152.72c47.92,34.82,119.33,53.54,159.86-2.24
|
||||
c0.56-0.76,1.3-1.78,2.19-3.01C363.28,602.32,347.02,558.08,336.54,510.71z"/>
|
||||
<path class="st4" d="M617.57,482.52c-35.33,7.54-82.42,9.33-130.72,4.66c-51.37-4.96-98.11-16.32-134.63-32.5
|
||||
c8.33,70.03,32.73,142.73,59.88,180.6c0.19,0.26,0.37,0.51,0.53,0.73c40.52,55.78,111.93,37.06,159.86,2.24
|
||||
c47.92-34.82,87.79-96.95,47.27-152.72C619.2,484.77,618.46,483.75,617.57,482.52z"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 2.0 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 594 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 49 KiB |
@@ -0,0 +1,17 @@
|
||||
import adapter from '@sveltejs/adapter-static';
|
||||
import { vitePreprocess } from '@sveltejs/vite-plugin-svelte';
|
||||
|
||||
/** @type {import('@sveltejs/kit').Config} */
|
||||
const config = {
|
||||
// Consult https://kit.svelte.dev/docs/integrations#preprocessors
|
||||
// for more information about preprocessors
|
||||
preprocess: vitePreprocess(),
|
||||
|
||||
kit: {
|
||||
adapter: adapter({
|
||||
fallback: 'index.html',
|
||||
}),
|
||||
},
|
||||
};
|
||||
|
||||
export default config;
|
||||
@@ -0,0 +1,38 @@
|
||||
/** @type {import('tailwindcss').Config} */
|
||||
module.exports = {
|
||||
content: ['./{apps,src}/**/*.{html,js,svelte,ts}'],
|
||||
darkMode: 'class',
|
||||
theme: {
|
||||
extend: {
|
||||
colors: {
|
||||
// Light Theme
|
||||
'immich-primary': 'rgb(var(--immich-primary) / <alpha-value>)',
|
||||
'immich-bg': 'rgb(var(--immich-bg) / <alpha-value>)',
|
||||
'immich-fg': 'rgb(var(--immich-fg) / <alpha-value>)',
|
||||
'immich-gray': 'rgb(var(--immich-gray) / <alpha-value>)',
|
||||
'immich-error': 'rgb(var(--immich-error) / <alpha-value>)',
|
||||
'immich-success': 'rgb(var(--immich-success) / <alpha-value>)',
|
||||
'immich-warning': 'rgb(var(--immich-warning) / <alpha-value>)',
|
||||
|
||||
// Dark Theme
|
||||
'immich-dark-primary': 'rgb(var(--immich-dark-primary) / <alpha-value>)',
|
||||
'immich-dark-bg': 'rgb(var(--immich-dark-bg) / <alpha-value>)',
|
||||
'immich-dark-fg': 'rgb(var(--immich-dark-fg) / <alpha-value>)',
|
||||
'immich-dark-gray': 'rgb(var(--immich-dark-gray) / <alpha-value>)',
|
||||
'immich-dark-error': 'rgb(var(--immich-dark-error) / <alpha-value>)',
|
||||
'immich-dark-success': 'rgb(var(--immich-dark-success) / <alpha-value>)',
|
||||
'immich-dark-warning': 'rgb(var(--immich-dark-warning) / <alpha-value>)',
|
||||
},
|
||||
fontFamily: {
|
||||
'immich-title': ['Snowburst One', 'cursive'],
|
||||
'immich-mono': ['Overpass Mono', 'monospace'],
|
||||
},
|
||||
spacing: {
|
||||
18: '4.5rem',
|
||||
},
|
||||
screens: {
|
||||
tall: { raw: '(min-height: 800px)' },
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
@@ -0,0 +1,19 @@
|
||||
{
|
||||
"extends": "./.svelte-kit/tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"allowJs": true,
|
||||
"checkJs": true,
|
||||
"esModuleInterop": true,
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"resolveJsonModule": true,
|
||||
"skipLibCheck": true,
|
||||
"sourceMap": true,
|
||||
"strict": true,
|
||||
"moduleResolution": "bundler"
|
||||
}
|
||||
// Path aliases are handled by https://kit.svelte.dev/docs/configuration#alias
|
||||
// except $lib which is handled by https://kit.svelte.dev/docs/configuration#files
|
||||
//
|
||||
// If you want to overwrite includes/excludes, make sure to copy over the relevant includes/excludes
|
||||
// from the referenced tsconfig.json - TypeScript does not merge them in
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
import { sveltekit } from '@sveltejs/kit/vite';
|
||||
import { defineConfig } from 'vitest/config';
|
||||
|
||||
export default defineConfig({
|
||||
plugins: [sveltekit()],
|
||||
test: {
|
||||
include: ['src/**/*.{test,spec}.{js,ts}'],
|
||||
},
|
||||
});
|
||||
Reference in New Issue
Block a user