flatten repo: remove pnpm workspace + merge workspaces (#688)

* remove unused components

* remove pnpm

* implementation of local dev pantry setup (#689)
This commit is contained in:
Neil 2023-06-30 10:33:39 +08:00 committed by GitHub
parent 9fe5a2b825
commit 6ad452331b
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
252 changed files with 14089 additions and 20380 deletions

View file

@ -8,10 +8,10 @@ node_modules
!.env.example !.env.example
# Ignore files for PNPM, NPM and YARN # Ignore files for PNPM, NPM and YARN
pnpm-lock.yaml
package-lock.json package-lock.json
yarn.lock yarn.lock
coverage/* coverage/*
build/* build/*
dist/* dist/*
electron/dist/* electron/dist/*
svelte/build/*

View file

@ -3,36 +3,34 @@ const { createReadStream, readFileSync, statSync, writeFileSync } = require("fs"
const path = require("path"); const path = require("path");
const yaml = require("yaml"); const yaml = require("yaml");
function getHashSum(file, encoding = "base64") { function getHashSum(file, encoding = "base64") {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
const hash = createHash("sha512") const hash = createHash("sha512");
hash.on("error", reject).setEncoding(encoding) hash.on("error", reject).setEncoding(encoding);
createReadStream(file, { highWaterMark: 1024 * 1024 /* better to use more memory but hash faster */ }) createReadStream(file, {
highWaterMark: 1024 * 1024 /* better to use more memory but hash faster */
})
.on("error", reject) .on("error", reject)
.on("end", () => { .on("end", () => {
hash.end() hash.end();
resolve(hash.read()) resolve(hash.read());
}) })
.pipe(hash, { end: false }) .pipe(hash, { end: false });
}) });
} }
async function main() { async function main() {
const args = process.argv; const args = process.argv;
const folderPath = args.pop(); const folderPath = args.pop();
const distPath = path.join(process.cwd(), folderPath); const distPath = path.join(process.cwd(), folderPath);
const releaseYamlPath = path.join(distPath, "latest-mac.yml"); const releaseYamlPath = path.join(distPath, "latest-mac.yml");
const releaseConfig = await readYaml(releaseYamlPath); const releaseConfig = await readYaml(releaseYamlPath);
for(const file of releaseConfig.files) { for (const file of releaseConfig.files) {
const filePath = path.join(distPath, file.url); const filePath = path.join(distPath, file.url);
const [stat, hash] = await Promise.all([ const [stat, hash] = await Promise.all([statSync(filePath), getHashSum(filePath)]);
statSync(filePath),
getHashSum(filePath),
]);
file.size = stat.size; file.size = stat.size;
file.sha512 = hash; file.sha512 = hash;
@ -52,4 +50,4 @@ async function readYaml(filePath) {
return config; return config;
} }
main(); main();

View file

@ -1,27 +1,28 @@
#!/usr/bin/env node #!/usr/bin/env node
async function main() { async function main() {
const message = { const message = {
blocks: [ blocks: [
{ {
type: 'section', type: "section",
text: { text: {
type: 'mrkdwn', type: "mrkdwn",
text: `NEW BUILD FOR ${process.env.PLATFORM} <${process.env.DOWNLOAD_URL}|download ${process.env.EXT || 'bin'} ${process.env.VERSION || ''}>` text: `NEW BUILD FOR ${process.env.PLATFORM} <${process.env.DOWNLOAD_URL}|download ${
process.env.EXT || "bin"
} ${process.env.VERSION || ""}>`
} }
} }
] ]
} };
const res = fetch(process.env.SLACK_WEBHOOK, { const res = fetch(process.env.SLACK_WEBHOOK, {
method: 'POST', method: "POST",
body: JSON.stringify(message), body: JSON.stringify(message),
headers: { 'Content-Type': 'application/json' } headers: { "Content-Type": "application/json" }
}) });
if (res.ok) { if (res.ok) {
const data = await res.json(); const data = await res.json();
console.log(data); console.log(data);
} }
} }
main(); main();

144
.github/template.json vendored
View file

@ -1,83 +1,77 @@
{ {
"Comment": "{{prefix}}", "Comment": "{{prefix}}",
"CacheBehaviors": { "CacheBehaviors": {
"Quantity": 0 "Quantity": 0
}, },
"Origins": { "Origins": {
"Items": [ "Items": [
{ {
"Id": "preview.gui.tea.xyz.s3-website.us-east-1.amazonaws.com-{{prefix}}", "Id": "preview.gui.tea.xyz.s3-website.us-east-1.amazonaws.com-{{prefix}}",
"DomainName": "preview.gui.tea.xyz.s3-website.us-east-1.amazonaws.com", "DomainName": "preview.gui.tea.xyz.s3-website.us-east-1.amazonaws.com",
"OriginPath": "/{{prefix}}", "OriginPath": "/{{prefix}}",
"CustomHeaders": { "CustomHeaders": {
"Quantity": 0 "Quantity": 0
},
"CustomOriginConfig": {
"HTTPPort": 80,
"HTTPSPort": 443,
"OriginProtocolPolicy": "http-only",
"OriginSslProtocols": {
"Quantity": 1,
"Items": [
"TLSv1.2"
]
},
"OriginReadTimeout": 30,
"OriginKeepaliveTimeout": 5
},
"ConnectionAttempts": 3,
"ConnectionTimeout": 10,
"OriginShield": {
"Enabled": false
}
}
],
"Quantity": 1
},
"DefaultRootObject": "index.html",
"PriceClass": "PriceClass_All",
"Enabled": true,
"DefaultCacheBehavior": {
"TrustedSigners": {
"Enabled": false,
"Quantity": 0
}, },
"TargetOriginId": "preview.gui.tea.xyz.s3-website.us-east-1.amazonaws.com-{{prefix}}", "CustomOriginConfig": {
"ViewerProtocolPolicy": "allow-all", "HTTPPort": 80,
"ForwardedValues": { "HTTPSPort": 443,
"Headers": { "OriginProtocolPolicy": "http-only",
"Quantity": 0 "OriginSslProtocols": {
}, "Quantity": 1,
"Cookies": { "Items": ["TLSv1.2"]
"Forward": "none" },
}, "OriginReadTimeout": 30,
"QueryString": false "OriginKeepaliveTimeout": 5
}, },
"SmoothStreaming": false, "ConnectionAttempts": 3,
"AllowedMethods": { "ConnectionTimeout": 10,
"Items": [ "OriginShield": {
"GET", "Enabled": false
"HEAD"
],
"Quantity": 2
},
"MinTTL": 0
},
"CallerReference": "{{caller_reference}}",
"ViewerCertificate": {
"CloudFrontDefaultCertificate": true
},
"CustomErrorResponses": {
"Quantity": 0
},
"Restrictions": {
"GeoRestriction": {
"RestrictionType": "none",
"Quantity": 0
} }
}
],
"Quantity": 1
},
"DefaultRootObject": "index.html",
"PriceClass": "PriceClass_All",
"Enabled": true,
"DefaultCacheBehavior": {
"TrustedSigners": {
"Enabled": false,
"Quantity": 0
}, },
"Aliases": { "TargetOriginId": "preview.gui.tea.xyz.s3-website.us-east-1.amazonaws.com-{{prefix}}",
"ViewerProtocolPolicy": "allow-all",
"ForwardedValues": {
"Headers": {
"Quantity": 0 "Quantity": 0
},
"Cookies": {
"Forward": "none"
},
"QueryString": false
},
"SmoothStreaming": false,
"AllowedMethods": {
"Items": ["GET", "HEAD"],
"Quantity": 2
},
"MinTTL": 0
},
"CallerReference": "{{caller_reference}}",
"ViewerCertificate": {
"CloudFrontDefaultCertificate": true
},
"CustomErrorResponses": {
"Quantity": 0
},
"Restrictions": {
"GeoRestriction": {
"RestrictionType": "none",
"Quantity": 0
} }
},
"Aliases": {
"Quantity": 0
}
} }

View file

@ -17,11 +17,11 @@ on:
type: string type: string
outputs: outputs:
s3-electron-dist-key: s3-electron-dist-key:
description: 'The S3 build key includes the installer files: [zip, dmg, etc, yml] from electron' description: "The S3 build key includes the installer files: [zip, dmg, etc, yml] from electron"
value: ${{ jobs.build.outputs.s3-artifacts-key }} value: ${{ jobs.build.outputs.s3-artifacts-key }}
s3-custom-notarized-installers-key: s3-custom-notarized-installers-key:
description: 'The S3 build key includes the installer files: [zip, dmg, etc, yml] from notarization strategy done outside of electron' description: "The S3 build key includes the installer files: [zip, dmg, etc, yml] from notarization strategy done outside of electron"
value: ${{ jobs.notarize-mac-installers.outputs.s3-installers-key }} value: ${{ jobs.build.outputs.s3-artifacts-key }}
jobs: jobs:
verify: verify:
runs-on: ubuntu-latest runs-on: ubuntu-latest
@ -38,14 +38,14 @@ jobs:
id: check_version id: check_version
run: | run: |
# Get the current version from package.json # Get the current version from package.json
CURRENT_VERSION=$(jq -r .version modules/desktop/package.json) CURRENT_VERSION=$(jq -r .version package.json)
# Get the list of changed files between HEAD and the previous commit # Get the list of changed files between HEAD and the previous commit
CHANGED_FILES=$(git diff --name-only HEAD^ HEAD) CHANGED_FILES=$(git diff --name-only HEAD^ HEAD)
# If package.json is in the list of changed files, check the old version # If package.json is in the list of changed files, check the old version
if echo "$CHANGED_FILES" | grep -q "desktop/package.json"; then if echo "$CHANGED_FILES" | grep -q "package.json"; then
OLD_VERSION=$(git show "HEAD^:modules/desktop/package.json" | jq -r .version 2>/dev/null) OLD_VERSION=$(git show "HEAD^:package.json" | jq -r .version 2>/dev/null)
else else
OLD_VERSION=$CURRENT_VERSION OLD_VERSION=$CURRENT_VERSION
fi fi
@ -62,7 +62,7 @@ jobs:
shell: bash shell: bash
build: build:
needs: verify # needs: verify
if: needs.verify.outputs.is-updated == 'true' if: needs.verify.outputs.is-updated == 'true'
runs-on: macos-latest runs-on: macos-latest
outputs: outputs:
@ -81,41 +81,20 @@ jobs:
if: startsWith(inputs.platform, 'linux') || matrix.platform.name == 'darwin+x86-64' if: startsWith(inputs.platform, 'linux') || matrix.platform.name == 'darwin+x86-64'
uses: actions/cache@v3 uses: actions/cache@v3
with: with:
key: ${{ runner.os }}-pnpm key: ${{ runner.os }}-npm
path: | path: ./node_modules
./pnpm
./.pnpm-store
./node_modules
./modules/desktop/node_modules
./modules/ui/node_modules
- name: cache electron build - name: cache electron build
uses: actions/cache@v3 uses: actions/cache@v3
with: with:
key: ${{ runner.os }}-electron key: ${{ runner.os }}-electron
path: | path: |
./modules/desktop/.svelte-kit ./svelte/.svelte-kit
./modules/desktop/build ./svelte/build
- name: build dev - name: build
if: inputs.s3-prefix != 'release'
run: tea -SE xc dist run: tea -SE xc dist
env: env:
SYNC_I18N: 1 NOTARIZE: true
PUBLIC_MIXPANEL_TOKEN: ${{ secrets.MIXPANEL_PROJECT_TOKEN }}
DEBUG_BUILD: ${{ inputs.debug }}
USE_HARD_LINKS: false
CSC_FOR_PULL_REQUEST: true
CSC_LINK: ${{ secrets.GUI_APPLE_CERTIFICATE }}
CSC_KEY_PASSWORD: ${{ secrets.GUI_APPLE_CERTIFICATE_PASSWORD }}
CSC_NAME: ${{ secrets.APPLE_IDENTITY_NO_PREFIX }}
PUBLISH_URL: "https://gui.tea.xyz/dev"
# slower build but dmg output is much nicer looking
- name: build release
if: inputs.s3-prefix == 'release'
run: tea -SE xc dist
env:
SYNC_I18N: 1
PUBLIC_MIXPANEL_TOKEN: ${{ secrets.MIXPANEL_PROJECT_TOKEN }} PUBLIC_MIXPANEL_TOKEN: ${{ secrets.MIXPANEL_PROJECT_TOKEN }}
DEBUG_BUILD: ${{ inputs.debug }} DEBUG_BUILD: ${{ inputs.debug }}
PUBLIC_VERSION: ${{ steps.gui-version.outputs.version }} PUBLIC_VERSION: ${{ steps.gui-version.outputs.version }}
@ -129,11 +108,12 @@ jobs:
APPLE_APP_SPECIFIC_PASSWORD: ${{ secrets.APPLE_PASSWORD }} APPLE_APP_SPECIFIC_PASSWORD: ${{ secrets.APPLE_PASSWORD }}
PUSHY_APP_ID: ${{ secrets.PUSHY_APP_ID }} PUSHY_APP_ID: ${{ secrets.PUSHY_APP_ID }}
SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }} SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }}
APPLE_TEAM_ID: ${{ secrets.APPLE_TEAM_ID }}
- name: build artifacts for publishing and notarization - name: build artifacts for publishing and notarization
run: | run: |
mkdir -p target mkdir -p target
cp ./modules/desktop/dist/*.{zip,dmg,yml,blockmap} ./target/ cp ./dist/*.{zip,dmg,yml,blockmap} ./target/
tar -czvf artifacts.tgz -C ./target/ . tar -czvf artifacts.tgz -C ./target/ .
- uses: aws-actions/configure-aws-credentials@v1 - uses: aws-actions/configure-aws-credentials@v1
@ -150,192 +130,3 @@ jobs:
S3_KEY=s3://preview.gui.tea.xyz/$prefix/artifacts.tgz S3_KEY=s3://preview.gui.tea.xyz/$prefix/artifacts.tgz
aws s3 cp artifacts.tgz $S3_KEY aws s3 cp artifacts.tgz $S3_KEY
echo key=$S3_KEY >> $GITHUB_OUTPUT echo key=$S3_KEY >> $GITHUB_OUTPUT
notarize-mac-installers:
if: inputs.s3-prefix != 'release' && needs.verify.outputs.is-updated == 'true'
# TODO: run only for mac, create separate Job for linux
needs: [build, verify]
runs-on: macos-11
outputs:
s3-installers-key: ${{ steps.s3-installers-upload.outputs.s3-key }}
strategy:
matrix:
platform:
# no need for x86-64
- darwin+aarch64
steps:
- uses: teaxyz/setup@v0
with:
version: 0.35.7
- uses: actions/checkout@v3
- run: rm -rf ./*.{dmg,zip} || true
- name: cache node_modules build
uses: actions/cache@v3
with:
key: darwin+x86-64-pnpm
path: |
./pnpm
./.pnpm-store
./node_modules
./modules/desktop/node_modules
./modules/ui/node_modules
- uses: aws-actions/configure-aws-credentials@v1
with:
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
aws-region: us-east-1
- name: s3 artifact download
env:
S3_KEY: ${{ needs.build.outputs.s3-artifacts-key }}
run: aws s3 cp $S3_KEY artifacts.tgz
# prepare folders
- run: mkdir dist
- run: tar xzf artifacts.tgz -C dist
- name: get .zip of arm64 and x86+64
id: app_files
working-directory: ./dist
run: |
ARM64_ZIP=$(ls | grep -Ev blockmap | grep arm64-mac.zip)
X86_ZIP=$(ls | grep -Ev blockmap | grep -Ev arm64 | grep mac.zip)
ARM64_DMG=$(ls | grep -Ev blockmap | grep arm64.dmg)
X86_DMG=$(ls | grep -Ev blockmap | grep -Ev arm64 | grep dmg)
echo zip_arm64=$ARM64_ZIP >> $GITHUB_OUTPUT
echo zip_x86=$X86_ZIP >> $GITHUB_OUTPUT
echo dmg_arm64=$ARM64_DMG >> $GITHUB_OUTPUT
echo dmg_x86=$X86_DMG >> $GITHUB_OUTPUT
- name: Codesign app bundle
env:
MACOS_CERTIFICATE: ${{ secrets.GUI_APPLE_CERTIFICATE }}
MACOS_CERTIFICATE_PWD: ${{ secrets.GUI_APPLE_CERTIFICATE_PASSWORD }}
MACOS_CERTIFICATE_NAME: ${{ secrets.APPLE_IDENTITY }}
MACOS_CI_KEYCHAIN_PWD: ${{ secrets.MACOS_CI_KEYCHAIN_PWD }}
ARM64_ZIP: ${{ steps.app_files.outputs.zip_arm64 }}
X86_ZIP: ${{ steps.app_files.outputs.zip_x86 }}
run: |
# Turn our base64-encoded certificate back to a regular .p12 file
echo $MACOS_CERTIFICATE | base64 --decode > certificate.p12
# We need to create a new keychain, otherwise using the certificate will prompt
# with a UI dialog asking for the certificate password, which we can't
# use in a headless CI environment
security create-keychain -p "$MACOS_CI_KEYCHAIN_PWD" build.keychain
security default-keychain -s build.keychain
security unlock-keychain -p "$MACOS_CI_KEYCHAIN_PWD" build.keychain
security import certificate.p12 -k build.keychain -P "$MACOS_CERTIFICATE_PWD" -T /usr/bin/codesign
security set-key-partition-list -S apple-tool:,apple:,codesign: -s -k "$MACOS_CI_KEYCHAIN_PWD" build.keychain
# skip: codesigning might need to move this inside the electron-builder codesigning step
# /usr/bin/codesign --force -s "$MACOS_CERTIFICATE_NAME" --options runtime dist/$ARM64_ZIP -v
# /usr/bin/codesign --force -s "$MACOS_CERTIFICATE_NAME" --options runtime dist/$X86_ZIP -v
# Notarize. Can take up to 10 minutes (and fail) asynchronously
# sometimes this might fail because exact the same zip has been uploaded already
- name: "Notarize and Staple app bundle"
# Extract the secrets we defined earlier as environment variables
env:
PROD_MACOS_NOTARIZATION_APPLE_ID: ${{ secrets.APPLE_ID }}
PROD_MACOS_NOTARIZATION_TEAM_ID: ${{ secrets.APPLE_TEAM_ID }}
PROD_MACOS_NOTARIZATION_PWD: ${{ secrets.APPLE_PASSWORD }}
MACOS_CI_KEYCHAIN_PWD: ${{ secrets.MACOS_CI_KEYCHAIN_PWD }}
ARM64_ZIP: ${{ steps.app_files.outputs.zip_arm64 }}
X86_ZIP: ${{ steps.app_files.outputs.zip_x86 }}
run: |
# Store the notarization credentials so that we can prevent a UI password dialog
# from blocking the CI
echo "Create keychain profile"
xcrun notarytool store-credentials "notarytool-profile" --apple-id "$PROD_MACOS_NOTARIZATION_APPLE_ID" --team-id "$PROD_MACOS_NOTARIZATION_TEAM_ID" --password "$PROD_MACOS_NOTARIZATION_PWD"
security unlock-keychain -p "$MACOS_CI_KEYCHAIN_PWD" build.keychain
echo "Notarize app"
xcrun notarytool submit dist/$ARM64_ZIP --keychain-profile "notarytool-profile" --wait
xcrun notarytool submit dist/$X86_ZIP --keychain-profile "notarytool-profile" --wait
echo "Unzipping files"
unzip dist/$ARM64_ZIP -d dist/mac-arm64
unzip dist/$X86_ZIP -d dist/mac
# TODO: might need to move this to the electron-builder codesigning step from dmg is created
# echo "Doing staple"
# xcrun stapler staple "dist/mac/tea.app"
# xcrun stapler staple "dist/mac-arm64/tea.app"
# echo "Rezip files"
# rm dist/$ARM64_ZIP
# rm dist/$X86_ZIP
# tea zip -r dist/$ARM64_ZIP dist/mac-arm64/tea.app
# tea zip -r dist/$X86_ZIP dist/mac/tea.app
# prepare for DMG creation
- name: prepare installer folders
run: |
mkdir x86_installer && mkdir arm64_installer
mv dist/mac-arm64/* arm64_installer
mv dist/mac/* x86_installer
# building this locally workds and the installer looks nice
# BUT, when --sandbox-safe is added to the create-dmg command, the installer UI is basic
# TODO: figure out issue with --sandbox-safe or try a different create-dmg package
- name: create x86 dmg
run: |
tea +github.com/create-dmg/create-dmg create-dmg \
--volname "Tea Installer" \
--window-pos 200 120 \
--window-size 684 465 \
--icon-size 128 \
--icon "tea.app" 158 219 \
--volicon "./modules/desktop/electron/icon.icns" \
--background "./modules/desktop/electron/bg.png" \
--hide-extension "tea.app" \
--app-drop-link 528 219 \
--sandbox-safe \
"$filename" \
"$installer_folder"
env:
filename: ${{ steps.app_files.outputs.dmg_x86 }}
installer_folder: x86_installer/
- name: create arm64 dmg
run: |
tea +github.com/create-dmg/create-dmg create-dmg \
--volname "Tea Installer" \
--window-pos 200 120 \
--window-size 684 465 \
--icon-size 128 \
--icon "tea.app" 158 219 \
--volicon "./modules/desktop/electron/icon.icns" \
--background "./modules/desktop/electron/bg.png" \
--hide-extension "tea.app" \
--app-drop-link 528 219 \
--sandbox-safe \
"$filename" \
"$installer_folder"
env:
filename: ${{ steps.app_files.outputs.dmg_arm64 }}
installer_folder: arm64_installer/
# finalize dist artifacts
- name: replace old DMG files in dist folder
run: |
mv $x86dmg dist
mv $arm64dmg dist
tea -E pnpm install
tea -E node .github/create-correct-release-yaml.js ./dist
tar -czvf dist.tgz -C dist/ .
env:
x86dmg: ${{ steps.app_files.outputs.dmg_x86 }}
arm64dmg: ${{ steps.app_files.outputs.dmg_arm64 }}
- name: s3 installers upload
id: s3-installers-upload
env:
prefix: ${{ inputs.s3-prefix }}
run: |
export S3_INSTALLERS_KEY=s3://preview.gui.tea.xyz/$prefix/dist.tgz
aws s3 cp dist.tgz $S3_INSTALLERS_KEY
echo s3-key=$S3_INSTALLERS_KEY >> $GITHUB_OUTPUT

View file

@ -4,9 +4,9 @@ on:
workflow_dispatch: workflow_dispatch:
inputs: inputs:
run_optional_build_desktop: run_optional_build_desktop:
description: 'Run the optional build_desktop job (yes/no)' description: "Run the optional build_desktop job (yes/no)"
required: true required: true
default: 'no' default: "no"
jobs: jobs:
changes: changes:
@ -16,33 +16,22 @@ jobs:
preview_folder: ${{steps.preview.outputs.folder}} preview_folder: ${{steps.preview.outputs.folder}}
is-fork: ${{steps.check-fork.outputs.is-fork}} is-fork: ${{steps.check-fork.outputs.is-fork}}
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v3
- uses: dorny/paths-filter@v2 - uses: dorny/paths-filter@v2
id: desktop id: desktop
with:
filters: |
src:
- 'modules/desktop/**'
- 'modules/ui/**'
- name: get s3 preview folder
id: preview
run: echo "folder=${{ github.event.number }}-merge" >> $GITHUB_OUTPUT
- name: Check if PR is from fork
id: check-fork
run: |
echo "is-fork=$(if [ \"${{ github.event.pull_request.head.repo.full_name }}\" != \"${{ github.repository }}\" ]; then echo true; else echo false; fi)" >> $GITHUB_OUTPUT
shell: bash
no_preview:
needs: changes
if: needs.changes.outputs.desktop == 'false' && needs.changes.outputs.is-fork == 'false'
runs-on: ubuntu-latest
steps:
- name: comment preview site
uses: mshick/add-pr-comment@v2
with: with:
message-id: preview-comment-${{needs.changes.outputs.preview_folder}} filters: |
message: | src:
no preview or changes related to UI - 'modules/desktop/**'
- 'modules/ui/**'
- name: get s3 preview folder
id: preview
run: echo "folder=${{ github.event.number }}-merge" >> $GITHUB_OUTPUT
- name: Check if PR is from fork
id: check-fork
run: |
echo "is-fork=$(if [ \"${{ github.event.pull_request.head.repo.full_name }}\" != \"${{ github.repository }}\" ]; then echo true; else echo false; fi)" >> $GITHUB_OUTPUT
shell: bash
test: test:
needs: changes needs: changes
runs-on: macos-latest runs-on: macos-latest
@ -51,39 +40,25 @@ jobs:
with: with:
version: 0.35.7 version: 0.35.7
- uses: actions/checkout@v3 - uses: actions/checkout@v3
# - name: cache node_modules build
# uses: actions/cache@v3
# with:
# key: test-ubuntu
# path: |
# ./pnpm
# ./.pnpm-store
# ./node_modules
# ./modules/desktop/node_modules
# ./modules/ui/node_modules
- name: cache node_modules build - name: cache node_modules build
uses: actions/cache@v3 uses: actions/cache@v3
with: with:
key: test-mac key: test-mac
path: | path: ./node_modules
./pnpm
./.pnpm-store
./node_modules
./modules/desktop/node_modules
./modules/ui/node_modules
- name: env file - name: env file
run: cp modules/desktop/.env.example modules/desktop/.env run: |
cp .env.example svelte/.env
- name: install app dependencies - name: install app dependencies
run: tea -E xc setup run: tea -E xc setup
- name: test build electron main process - name: test build electron main process
run: tea pnpm --filter tea exec pnpm build:main run: npm run build:main
# TODO: fix # TODO: fix
# - name: unit test # - name: unit test
# run: pnpm --filter desktop run coverage # run: pnpm --filter desktop run coverage
- name: lint - name: lint
run: tea -E pnpm -r lint run: npm run lint
- name: check - name: check
run: tea -E pnpm -r check run: npm run check
e2e_test: e2e_test:
needs: changes needs: changes
@ -100,19 +75,15 @@ jobs:
uses: actions/cache@v3 uses: actions/cache@v3
with: with:
key: e2e-macos key: e2e-macos
path: | path: ./node_modules
./pnpm
./.pnpm-store
./node_modules
./modules/desktop/node_modules
./modules/ui/node_modules
- name: env file - name: env file
run: cp modules/desktop/.env.example modules/desktop/.env run: cp .env.example svelte/.env
- name: install app dependencies - name: install app dependencies
run: tea -E xc setup run: tea -E xc setup
- name: test build electron main process - name: test build electron main process
run: tea -E xc build run: tea -E xc build
env: env:
NOTARIZE: "false"
CSC_IDENTITY_AUTO_DISCOVERY: "false" CSC_IDENTITY_AUTO_DISCOVERY: "false"
MAC_BUILD_TARGET: "dir" MAC_BUILD_TARGET: "dir"
- name: setup dev - name: setup dev
@ -135,25 +106,20 @@ jobs:
with: with:
# key: ubuntu-latest-pnpm # key: ubuntu-latest-pnpm
key: mac-latest-pnpm key: mac-latest-pnpm
path: | path: ./node_modules
./pnpm
./.pnpm-store
./node_modules
./modules/desktop/node_modules
./modules/ui/node_modules
- name: cache electron build - name: cache electron build
uses: actions/cache@v3 uses: actions/cache@v3
with: with:
key: mac-latest-electron key: mac-latest-electron
# key: ubuntu-latest-electron # key: ubuntu-latest-electron
path: | path: |
./modules/desktop/.svelte-kit ./svelte/.svelte-kit
./modules/desktop/build ./svelte/build
- name: get gui version - name: get gui version
id: gui-version id: gui-version
run: | run: |
tea +stedolan.github.io/jq tea +stedolan.github.io/jq
export version=$(echo $(cat modules/desktop/package.json) | jq --raw-output .version) export version=$(echo $(cat package.json) | jq --raw-output .version)
export postfix= export postfix=
if GIT_DIR=/path/to/repo/.git git rev-parse $1 >/dev/null 2>&1 if GIT_DIR=/path/to/repo/.git git rev-parse $1 >/dev/null 2>&1
then then
@ -164,45 +130,11 @@ jobs:
echo "version=$version$postfix" >> $GITHUB_OUTPUT echo "version=$version$postfix" >> $GITHUB_OUTPUT
- name: build - name: build
run: | run: tea -E xc build:lite
tea -SE xc setup
cd modules/desktop && tea -ES pnpm vite build && cp build/app.html build/index.html
env: env:
PUBLIC_VERSION: ${{ steps.gui-version.outputs.version }} PUBLIC_VERSION: ${{ steps.gui-version.outputs.version }}
BUILD_FOR: preview BUILD_FOR: preview
- uses: aws-actions/configure-aws-credentials@v1
if: needs.changes.outputs.is-fork == 'false'
with:
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
aws-region: us-east-1
- name: sync web files into preview folder
if: needs.changes.outputs.is-fork == 'false'
env:
prefix: ${{ needs.changes.outputs.preview_folder }}
run: |
aws s3 sync ./modules/desktop/build \
"s3://preview.gui.tea.xyz/$prefix"
- name: setup preview
if: needs.changes.outputs.is-fork == 'false'
id: preview_setup
run: |
tea +stedolan.github.io/jq .github/create-invalidate-preview.sh ${{ needs.changes.outputs.preview_folder }}
- name: comment preview site
if: needs.changes.outputs.is-fork == 'false'
uses: mshick/add-pr-comment@v2
with:
message-id: preview-comment-${{needs.changes.outputs.preview_folder}}
message: |
**preview is at**:
<a href="https://${{steps.preview_setup.outputs.domain}}" target="_blank">here</a>
```bash
https://${{steps.preview_setup.outputs.domain}}
```
copy-paste into a browser to view
build_desktop: build_desktop:
if: (github.event_name == 'workflow_dispatch' && github.event.inputs.run_optional_build_desktop == 'yes') if: (github.event_name == 'workflow_dispatch' && github.event.inputs.run_optional_build_desktop == 'yes')
needs: [changes, test] needs: [changes, test]
@ -220,7 +152,7 @@ jobs:
secrets: inherit secrets: inherit
upload: upload:
needs: [build_desktop, changes] needs: [build_desktop, changes]
if : needs.changes.outputs.is-fork == 'false' if: needs.changes.outputs.is-fork == 'false'
runs-on: ubuntu-latest runs-on: ubuntu-latest
strategy: strategy:
matrix: matrix:
@ -233,109 +165,109 @@ jobs:
# - name: linux+aarch64 # - name: linux+aarch64
# id: linux_arm64 # id: linux_arm64
steps: steps:
- uses: aws-actions/configure-aws-credentials@v1 - uses: aws-actions/configure-aws-credentials@v1
with: with:
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }} aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }} aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
aws-region: us-east-1 aws-region: us-east-1
- name: s3 artifact download - name: s3 artifact download
env: env:
S3_INSTALLER_KEY: ${{ needs.build_desktop.outputs.s3-custom-notarized-installers-key }} S3_INSTALLER_KEY: ${{ needs.build_desktop.outputs.s3-custom-notarized-installers-key }}
run: aws s3 cp $S3_INSTALLER_KEY dist.tgz run: aws s3 cp $S3_INSTALLER_KEY dist.tgz
- run: mkdir dist - run: mkdir dist
- run: tar xzf dist.tgz -C dist - run: tar xzf dist.tgz -C dist
- name: get installer filenames of arm64 and x86+64 - name: get installer filenames of arm64 and x86+64
id: app_files id: app_files
working-directory: ./dist working-directory: ./dist
run: | run: |
ARM64_ZIP=$(ls | grep -Ev blockmap | grep arm64-mac.zip) ARM64_ZIP=$(ls | grep -Ev blockmap | grep arm64-mac.zip)
X86_ZIP=$(ls | grep -Ev blockmap | grep -Ev arm64 | grep mac.zip) X86_ZIP=$(ls | grep -Ev blockmap | grep -Ev arm64 | grep mac.zip)
ARM64_DMG=$(ls | grep -Ev blockmap | grep arm64.dmg) ARM64_DMG=$(ls | grep -Ev blockmap | grep arm64.dmg)
X86_DMG=$(ls | grep -Ev blockmap | grep -Ev arm64 | grep dmg) X86_DMG=$(ls | grep -Ev blockmap | grep -Ev arm64 | grep dmg)
echo zip_arm64=$ARM64_ZIP >> $GITHUB_OUTPUT echo zip_arm64=$ARM64_ZIP >> $GITHUB_OUTPUT
echo zip_x86=$X86_ZIP >> $GITHUB_OUTPUT echo zip_x86=$X86_ZIP >> $GITHUB_OUTPUT
echo dmg_arm64=$ARM64_DMG >> $GITHUB_OUTPUT echo dmg_arm64=$ARM64_DMG >> $GITHUB_OUTPUT
echo dmg_x86=$X86_DMG >> $GITHUB_OUTPUT echo dmg_x86=$X86_DMG >> $GITHUB_OUTPUT
- name: build platform output - name: build platform output
id: build_platform id: build_platform
env: env:
platform: ${{ matrix.platform.name }} platform: ${{ matrix.platform.name }}
run: | run: |
BUILD_PLATFORM=$(echo $platform | sed -e "s/darwin+//g" | sed -e "s/linux+//g") BUILD_PLATFORM=$(echo $platform | sed -e "s/darwin+//g" | sed -e "s/linux+//g")
EXTENSION=dmg EXTENSION=dmg
case $platform in case $platform in
"linux+x86-64") "linux+x86-64")
BUILD_PLATFORM="amd64" BUILD_PLATFORM="amd64"
EXTENSION="deb" EXTENSION="deb"
;; ;;
"linux+aarch64") "linux+aarch64")
BUILD_PLATFORM="aarch64" BUILD_PLATFORM="aarch64"
EXTENSION="deb" EXTENSION="deb"
;; ;;
"darwin+aarch64") "darwin+aarch64")
BUILD_PLATFORM="aarch64" BUILD_PLATFORM="aarch64"
EXTENSION="dmg" EXTENSION="dmg"
;; ;;
"darwin+x86-64") "darwin+x86-64")
BUILD_PLATFORM="x64" BUILD_PLATFORM="x64"
EXTENSION="dmg" EXTENSION="dmg"
;; ;;
*) *)
echo "Unknown platform $platform" echo "Unknown platform $platform"
exit 1 exit 1
;; ;;
esac esac
echo "build_platform=$BUILD_PLATFORM" >> $GITHUB_OUTPUT echo "build_platform=$BUILD_PLATFORM" >> $GITHUB_OUTPUT
echo "extension=$EXTENSION" >> $GITHUB_OUTPUT echo "extension=$EXTENSION" >> $GITHUB_OUTPUT
- uses: aws-actions/configure-aws-credentials@v1 - uses: aws-actions/configure-aws-credentials@v1
with: with:
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }} aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }} aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
aws-region: us-east-1 aws-region: us-east-1
- name: cp package images from prod to preview bucket - name: cp package images from prod to preview bucket
env: env:
prefix: ${{ needs.changes.outputs.preview_folder }} prefix: ${{ needs.changes.outputs.preview_folder }}
run: | run: |
cd dist && \ cd dist && \
aws s3 sync . \ aws s3 sync . \
"s3://preview.gui.tea.xyz/$prefix/" "s3://preview.gui.tea.xyz/$prefix/"
- name: comment install for Linux - name: comment install for Linux
if: startsWith(matrix.platform.name, 'linux') if: startsWith(matrix.platform.name, 'linux')
uses: mshick/add-pr-comment@v2 uses: mshick/add-pr-comment@v2
with: with:
message-id: ${{ matrix.platform.id }}-comment message-id: ${{ matrix.platform.id }}-comment
message: | message: |
**installer for Linux ${{ matrix.platform.name }} is at**: **installer for Linux ${{ matrix.platform.name }} is at**:
```bash ```bash
http://preview.gui.tea.xyz.s3-website-us-east-1.amazonaws.com/${{ needs.changes.outputs.preview_folder }}/${{ steps.build_platform.outputs.filename }} http://preview.gui.tea.xyz.s3-website-us-east-1.amazonaws.com/${{ needs.changes.outputs.preview_folder }}/${{ steps.build_platform.outputs.filename }}
``` ```
copy-paste into a browser to download copy-paste into a browser to download
- name: comment install for MacOS - name: comment install for MacOS
if: startsWith(matrix.platform.name, 'darwin') if: startsWith(matrix.platform.name, 'darwin')
uses: mshick/add-pr-comment@v2 uses: mshick/add-pr-comment@v2
with: with:
message-id: darwin+aarch64-comment message-id: darwin+aarch64-comment
message: | message: |
**installers for MacOS darwin+aarch64 is at**: **installers for MacOS darwin+aarch64 is at**:
```bash ```bash
http://preview.gui.tea.xyz.s3-website-us-east-1.amazonaws.com/${{ needs.changes.outputs.preview_folder }}/${{ steps.app_files.outputs.dmg_arm64 }} http://preview.gui.tea.xyz.s3-website-us-east-1.amazonaws.com/${{ needs.changes.outputs.preview_folder }}/${{ steps.app_files.outputs.dmg_arm64 }}
``` ```
copy-paste into a browser to download copy-paste into a browser to download
- name: comment install for MacOS - name: comment install for MacOS
if: startsWith(matrix.platform.name, 'darwin') if: startsWith(matrix.platform.name, 'darwin')
uses: mshick/add-pr-comment@v2 uses: mshick/add-pr-comment@v2
with: with:
message-id: darwin+x86-64-comment message-id: darwin+x86-64-comment
message: | message: |
**installers for MacOS darwin+x86-64 is at**: **installers for MacOS darwin+x86-64 is at**:
```bash ```bash
http://preview.gui.tea.xyz.s3-website-us-east-1.amazonaws.com/${{ needs.changes.outputs.preview_folder }}/${{ steps.app_files.outputs.dmg_x86 }} http://preview.gui.tea.xyz.s3-website-us-east-1.amazonaws.com/${{ needs.changes.outputs.preview_folder }}/${{ steps.app_files.outputs.dmg_x86 }}
``` ```
copy-paste into a browser to download copy-paste into a browser to download

View file

@ -25,7 +25,6 @@ jobs:
- name: remove distribution preview - name: remove distribution preview
run: .github/remove-distribution.sh "${{ github.event.number }}-merge" run: .github/remove-distribution.sh "${{ github.event.number }}-merge"
# consider to rm the folder later, maybe someone might need to download the installer # consider to rm the folder later, maybe someone might need to download the installer
# - name: remove s3 folder # - name: remove s3 folder
# run: aws s3 rm s3://preview.gui.tea.xyz/ --recursive --exclude "*" --include "${{ steps.preview.outputs.folder }}/*" # run: aws s3 rm s3://preview.gui.tea.xyz/ --recursive --exclude "*" --include "${{ steps.preview.outputs.folder }}/*"

View file

@ -4,30 +4,8 @@ on:
push: push:
branches: branches:
- main - main
jobs: jobs:
changes:
runs-on: ubuntu-latest
outputs:
desktop: ${{steps.desktop.outputs.src}}
preview_folder: ${{steps.preview.outputs.folder}}
steps:
- uses: actions/checkout@v3
- uses: dorny/paths-filter@v2
id: desktop
with:
filters: |
src:
- 'modules/desktop/**'
- 'modules/ui/**'
- '.github/**'
- name: get s3 preview folder
id: preview
run: echo "folder=${{ github.event.number }}-merge" >> $GITHUB_OUTPUT
build_desktop: build_desktop:
needs: changes
# if: needs.changes.outputs.desktop == 'true'
strategy: strategy:
matrix: matrix:
platform: platform:
@ -51,107 +29,106 @@ jobs:
- darwin+aarch64 - darwin+aarch64
# - linux+aarch64 # - linux+aarch64
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v3
- uses: aws-actions/configure-aws-credentials@v1 - uses: aws-actions/configure-aws-credentials@v1
with: with:
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }} aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }} aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
aws-region: us-east-1 aws-region: us-east-1
- name: s3 artifact download - name: s3 artifact download
env: env:
S3_INSTALLER_KEY: ${{ needs.build_desktop.outputs.s3-custom-notarized-installers-key }} S3_INSTALLER_KEY: ${{ needs.build_desktop.outputs.s3-custom-notarized-installers-key }}
run: aws s3 cp $S3_INSTALLER_KEY dist.tgz run: aws s3 cp $S3_INSTALLER_KEY dist.tgz
- run: | - run: |
mkdir dist mkdir dist
tar xzf dist.tgz -C dist tar xzf dist.tgz -C dist
- name: get installer filenames of arm64 and x86+64 - name: get installer filenames of arm64 and x86+64
id: app_files id: app_files
working-directory: ./dist working-directory: ./dist
run: | run: |
ARM64_ZIP=$(ls | grep -Ev blockmap | grep arm64-mac.zip) ARM64_ZIP=$(ls | grep -Ev blockmap | grep arm64-mac.zip)
X86_ZIP=$(ls | grep -Ev blockmap | grep -Ev arm64 | grep mac.zip) X86_ZIP=$(ls | grep -Ev blockmap | grep -Ev arm64 | grep mac.zip)
ARM64_DMG=$(ls | grep -Ev blockmap | grep arm64.dmg) ARM64_DMG=$(ls | grep -Ev blockmap | grep arm64.dmg)
X86_DMG=$(ls | grep -Ev blockmap | grep -Ev arm64 | grep dmg) X86_DMG=$(ls | grep -Ev blockmap | grep -Ev arm64 | grep dmg)
echo zip_arm64=$ARM64_ZIP >> $GITHUB_OUTPUT echo zip_arm64=$ARM64_ZIP >> $GITHUB_OUTPUT
echo zip_x86=$X86_ZIP >> $GITHUB_OUTPUT echo zip_x86=$X86_ZIP >> $GITHUB_OUTPUT
echo dmg_arm64=$ARM64_DMG >> $GITHUB_OUTPUT echo dmg_arm64=$ARM64_DMG >> $GITHUB_OUTPUT
echo dmg_x86=$X86_DMG >> $GITHUB_OUTPUT echo dmg_x86=$X86_DMG >> $GITHUB_OUTPUT
- name: Get current unix ts - seconds
id: date
run: echo "unix_seconds=$(date +'%s')" >> $GITHUB_OUTPUT
- name: build platform output - name: Get current unix ts - seconds
id: build_platform id: date
env: run: echo "unix_seconds=$(date +'%s')" >> $GITHUB_OUTPUT
platform: ${{ matrix.platform }}
run: |
BUILD_PLATFORM=$(echo $platform | sed -e "s/darwin+//g" | sed -e "s/linux+//g")
EXTENSION=dmg
case $platform in
"linux+x86-64")
BUILD_PLATFORM="amd64"
EXTENSION="deb"
;;
"linux+aarch64")
BUILD_PLATFORM="aarch64"
EXTENSION="deb"
;;
"darwin+aarch64")
BUILD_PLATFORM="aarch64"
EXTENSION="dmg"
;;
"darwin+x86-64")
BUILD_PLATFORM="x64"
EXTENSION="dmg"
;;
*)
echo "Unknown platform $platform"
exit 1
;;
esac
echo "build_platform=$BUILD_PLATFORM" >> $GITHUB_OUTPUT
echo "extension=$EXTENSION" >> $GITHUB_OUTPUT
- name: cp package images from prod to gui bucket - name: build platform output
env: id: build_platform
arm64: ${{ steps.app_files.outputs.dmg_arm64 }} env:
x86: ${{ steps.app_files.outputs.dmg_x86 }} platform: ${{ matrix.platform }}
run: | run: |
cd dist && \ BUILD_PLATFORM=$(echo $platform | sed -e "s/darwin+//g" | sed -e "s/linux+//g")
aws s3 sync . \ EXTENSION=dmg
"s3://preview.gui.tea.xyz/dev/" case $platform in
"linux+x86-64")
BUILD_PLATFORM="amd64"
EXTENSION="deb"
;;
"linux+aarch64")
BUILD_PLATFORM="aarch64"
EXTENSION="deb"
;;
"darwin+aarch64")
BUILD_PLATFORM="aarch64"
EXTENSION="dmg"
;;
"darwin+x86-64")
BUILD_PLATFORM="x64"
EXTENSION="dmg"
;;
*)
echo "Unknown platform $platform"
exit 1
;;
esac
echo "build_platform=$BUILD_PLATFORM" >> $GITHUB_OUTPUT
echo "extension=$EXTENSION" >> $GITHUB_OUTPUT
- uses: actions/setup-node@v3 - name: cp package images from prod to gui bucket
with: env:
node-version: 18 arm64: ${{ steps.app_files.outputs.dmg_arm64 }}
x86: ${{ steps.app_files.outputs.dmg_x86 }}
run: |
cd dist && \
aws s3 sync . \
"s3://preview.gui.tea.xyz/dev/"
- name: get version - uses: actions/setup-node@v3
id: get-version with:
run: | node-version: 18
echo "version=$(node -p "require('./modules/desktop/package.json').version")" >> $GITHUB_OUTPUT
- name: get version
id: get-version
run: |
echo "version=$(node -p "require('./package.json').version")" >> $GITHUB_OUTPUT
- name: Slack Notification ARM64 - name: Slack Notification ARM64
run: ./.github/notify-slack.js run: ./.github/notify-slack.js
env: env:
SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK }} SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK }}
PLATFORM: darwin-aarch64 PLATFORM: darwin-aarch64
EXT: dmg EXT: dmg
VERSION: ${{ steps.get-version.outputs.version }}-dev VERSION: ${{ steps.get-version.outputs.version }}-dev
DOWNLOAD_URL: http://preview.gui.tea.xyz.s3-website-us-east-1.amazonaws.com/dev/${{ steps.app_files.outputs.dmg_arm64 }} DOWNLOAD_URL: http://preview.gui.tea.xyz.s3-website-us-east-1.amazonaws.com/dev/${{ steps.app_files.outputs.dmg_arm64 }}
- name: Slack Notification X86 - name: Slack Notification X86
run: ./.github/notify-slack.js run: ./.github/notify-slack.js
env: env:
SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK }} SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK }}
PLATFORM: darwin-x86+64 PLATFORM: darwin-x86+64
EXT: dmg EXT: dmg
VERSION: ${{ steps.get-version.outputs.version }}-dev VERSION: ${{ steps.get-version.outputs.version }}-dev
DOWNLOAD_URL: http://preview.gui.tea.xyz.s3-website-us-east-1.amazonaws.com/dev/${{ steps.app_files.outputs.dmg_x86 }} DOWNLOAD_URL: http://preview.gui.tea.xyz.s3-website-us-east-1.amazonaws.com/dev/${{ steps.app_files.outputs.dmg_x86 }}
- run: | - run: |
aws cloudfront create-invalidation \ aws cloudfront create-invalidation \
--distribution-id ${{ secrets.AWS_CF_GUI_RELEASE_ID }} \ --distribution-id ${{ secrets.AWS_CF_GUI_RELEASE_ID }} \
--paths '/*' --paths '/*'

View file

@ -1,7 +1,7 @@
on: on:
push: push:
tags: tags:
- 'v*.*.*' - "v*.*.*"
jobs: jobs:
build_desktop: build_desktop:
@ -27,128 +27,126 @@ jobs:
- darwin+aarch64 - darwin+aarch64
# - linux+aarch64 # - linux+aarch64
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v3
- uses: aws-actions/configure-aws-credentials@v1 - uses: aws-actions/configure-aws-credentials@v1
with: with:
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }} aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }} aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
aws-region: us-east-1 aws-region: us-east-1
- name: s3 artifact download - name: s3 artifact download
env: env:
S3_INSTALLER_KEY: ${{ needs.build_desktop.outputs.s3-electron-dist-key }} S3_INSTALLER_KEY: ${{ needs.build_desktop.outputs.s3-electron-dist-key }}
run: aws s3 cp $S3_INSTALLER_KEY dist.tgz run: aws s3 cp $S3_INSTALLER_KEY dist.tgz
- run: | - run: |
mkdir dist mkdir dist
tar xzf dist.tgz -C dist tar xzf dist.tgz -C dist
- name: get .zip of arm64 and x86+64 - name: get .zip of arm64 and x86+64
id: app_files id: app_files
working-directory: ./dist working-directory: ./dist
run: | run: |
ARM64_ZIP=$(ls | grep -Ev blockmap | grep arm64-mac.zip) ARM64_ZIP=$(ls | grep -Ev blockmap | grep arm64-mac.zip)
X86_ZIP=$(ls | grep -Ev blockmap | grep -Ev arm64 | grep mac.zip) X86_ZIP=$(ls | grep -Ev blockmap | grep -Ev arm64 | grep mac.zip)
ARM64_DMG=$(ls | grep -Ev blockmap | grep arm64.dmg) ARM64_DMG=$(ls | grep -Ev blockmap | grep arm64.dmg)
X86_DMG=$(ls | grep -Ev blockmap | grep -Ev arm64 | grep dmg) X86_DMG=$(ls | grep -Ev blockmap | grep -Ev arm64 | grep dmg)
echo zip_arm64=$ARM64_ZIP >> $GITHUB_OUTPUT echo zip_arm64=$ARM64_ZIP >> $GITHUB_OUTPUT
echo zip_x86=$X86_ZIP >> $GITHUB_OUTPUT echo zip_x86=$X86_ZIP >> $GITHUB_OUTPUT
echo dmg_arm64=$ARM64_DMG >> $GITHUB_OUTPUT echo dmg_arm64=$ARM64_DMG >> $GITHUB_OUTPUT
echo dmg_x86=$X86_DMG >> $GITHUB_OUTPUT echo dmg_x86=$X86_DMG >> $GITHUB_OUTPUT
- name: build platform output - name: build platform output
id: build_platform id: build_platform
env: env:
platform: ${{ matrix.platform }} platform: ${{ matrix.platform }}
run: | run: |
BUILD_PLATFORM=$(echo $platform | sed -e "s/darwin+//g" | sed -e "s/linux+//g") BUILD_PLATFORM=$(echo $platform | sed -e "s/darwin+//g" | sed -e "s/linux+//g")
EXTENSION=dmg EXTENSION=dmg
case $platform in case $platform in
"linux+x86-64") "linux+x86-64")
BUILD_PLATFORM="amd64" BUILD_PLATFORM="amd64"
EXTENSION="deb" EXTENSION="deb"
;; ;;
"linux+aarch64") "linux+aarch64")
BUILD_PLATFORM="aarch64" BUILD_PLATFORM="aarch64"
EXTENSION="deb" EXTENSION="deb"
;; ;;
"darwin+aarch64") "darwin+aarch64")
BUILD_PLATFORM="aarch64" BUILD_PLATFORM="aarch64"
EXTENSION="dmg" EXTENSION="dmg"
;; ;;
"darwin+x86-64") "darwin+x86-64")
BUILD_PLATFORM="x64" BUILD_PLATFORM="x64"
EXTENSION="dmg" EXTENSION="dmg"
;; ;;
*) *)
echo "Unknown platform $platform" echo "Unknown platform $platform"
exit 1 exit 1
;; ;;
esac esac
echo "build_platform=$BUILD_PLATFORM" >> $GITHUB_OUTPUT echo "build_platform=$BUILD_PLATFORM" >> $GITHUB_OUTPUT
echo "extension=$EXTENSION" >> $GITHUB_OUTPUT echo "extension=$EXTENSION" >> $GITHUB_OUTPUT
# update and replace latest release bin in s3
- name: Set tag
id: tag
run: echo "tag=${GITHUB_REF#refs/*/}" >> $GITHUB_OUTPUT
# update and replace latest release bin in s3 # TODO:
- name: Set tag # - configure correct blockmap and checksum hash on latest-mac.yml
id: tag - name: cp latest as previous release
run: echo "tag=${GITHUB_REF#refs/*/}" >> $GITHUB_OUTPUT run: |
aws s3 cp \
s3://dist.tea.xyz/tea.xyz/gui/tea-latest-arm64.dmg \
s3://dist.tea.xyz/tea.xyz/gui/tea-previous-arm64.dmg
aws s3 cp \
s3://dist.tea.xyz/tea.xyz/gui/tea-latest.dmg \
s3://dist.tea.xyz/tea.xyz/gui/tea-previous.dmg
- name: publish release
run: |
cd dist && \
aws s3 sync . \
"s3://preview.gui.tea.xyz/release/"
aws s3 cp $ARM_URL s3://dist.tea.xyz/tea.xyz/gui/tea-latest-arm64.dmg
aws s3 cp $X86_URL s3://dist.tea.xyz/tea.xyz/gui/tea-previous-arm64.dmg
env:
ARM_URL: s3://preview.gui.tea.xyz/release/${{ steps.app_files.outputs.dmg_arm64 }}
X86_URL: s3://preview.gui.tea.xyz/release/${{ steps.app_files.outputs.dmg_x86 }}
# TODO: - run: |
# - configure correct blockmap and checksum hash on latest-mac.yml aws cloudfront create-invalidation \
- name: cp latest as previous release --distribution-id ${{ secrets.AWS_GUI_DISTRIBUTION_ID }} \
run: | --paths "/release/*"
aws s3 cp \
s3://dist.tea.xyz/tea.xyz/gui/tea-latest-arm64.dmg \
s3://dist.tea.xyz/tea.xyz/gui/tea-previous-arm64.dmg
aws s3 cp \
s3://dist.tea.xyz/tea.xyz/gui/tea-latest.dmg \
s3://dist.tea.xyz/tea.xyz/gui/tea-previous.dmg
- name: publish release
run: |
cd dist && \
aws s3 sync . \
"s3://preview.gui.tea.xyz/release/"
aws s3 cp $ARM_URL s3://dist.tea.xyz/tea.xyz/gui/tea-latest-arm64.dmg
aws s3 cp $X86_URL s3://dist.tea.xyz/tea.xyz/gui/tea-previous-arm64.dmg
env:
ARM_URL: s3://preview.gui.tea.xyz/release/${{ steps.app_files.outputs.dmg_arm64 }}
X86_URL: s3://preview.gui.tea.xyz/release/${{ steps.app_files.outputs.dmg_x86 }}
- run: | - uses: actions/setup-node@v3
aws cloudfront create-invalidation \ with:
--distribution-id ${{ secrets.AWS_GUI_DISTRIBUTION_ID }} \ node-version: 18
--paths "/release/*" - name: Slack Notification ARM64 Build
run: ./.github/notify-slack.js
env:
SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK }}
PLATFORM: darwin+aarch64
VERSION: ${{steps.tag.outputs.tag}}
EXT: "${{ steps.build_platform.outputs.extension }}"
DOWNLOAD_URL: http://preview.gui.tea.xyz.s3-website-us-east-1.amazonaws.com/release/${{ steps.app_files.outputs.dmg_arm64 }}
- uses: actions/setup-node@v3 - name: Slack Notification X86 Build
with: run: ./.github/notify-slack.js
node-version: 18 env:
- name: Slack Notification ARM64 Build SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK }}
run: ./.github/notify-slack.js PLATFORM: darwin+x86-64
env: VERSION: ${{steps.tag.outputs.tag}}
SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK }} EXT: ${{ steps.build_platform.outputs.extension }}
PLATFORM: darwin+aarch64 DOWNLOAD_URL: http://preview.gui.tea.xyz.s3-website-us-east-1.amazonaws.com/release/${{ steps.app_files.outputs.dmg_x86 }}
VERSION: ${{steps.tag.outputs.tag}}
EXT: "${{ steps.build_platform.outputs.extension }}"
DOWNLOAD_URL: http://preview.gui.tea.xyz.s3-website-us-east-1.amazonaws.com/release/${{ steps.app_files.outputs.dmg_arm64 }}
- name: Slack Notification X86 Build - run: |
run: ./.github/notify-slack.js aws cloudfront create-invalidation \
env: --distribution-id ${{ secrets.AWS_CF_GUI_RELEASE_ID }} \
SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK }} --paths '/*'
PLATFORM: darwin+x86-64 - name: upload builds
VERSION: ${{steps.tag.outputs.tag}} uses: softprops/action-gh-release@v1
EXT: ${{ steps.build_platform.outputs.extension }} if: startsWith(github.ref, 'refs/tags/')
DOWNLOAD_URL: http://preview.gui.tea.xyz.s3-website-us-east-1.amazonaws.com/release/${{ steps.app_files.outputs.dmg_x86 }} with:
files: |
- run: | dist/${{ steps.app_files.outputs.dmg_arm64 }}
aws cloudfront create-invalidation \ dist/${{ steps.app_files.outputs.dmg_x86 }}
--distribution-id ${{ secrets.AWS_CF_GUI_RELEASE_ID }} \
--paths '/*'
- name: upload builds
uses: softprops/action-gh-release@v1
if: startsWith(github.ref, 'refs/tags/')
with:
files: |
dist/${{ steps.app_files.outputs.dmg_arm64 }}
dist/${{ steps.app_files.outputs.dmg_x86 }}

6
.gitignore vendored
View file

@ -3,4 +3,8 @@ yarn-error.log
.DS_Store .DS_Store
.pnpm-store .pnpm-store
target target
copy.json copy.json
electron/dist
electrin/config.json
dist
.env

View file

@ -1,19 +1,15 @@
.DS_Store .DS_Store
node_modules node_modules
/build svelte/.svelte-kit
/.svelte-kit
/package /package
.env .env
.env.* .env.*
!.env.example !.env.example
# Ignore files for PNPM, NPM and YARN # Ignore files for PNPM, NPM and YARN
pnpm-lock.yaml
package-lock.json package-lock.json
yarn.lock dist
build
coverage/* coverage/*
**/*.plist **/*.plist
build/* svelte/build/*
dist/*
electron/dist/* electron/dist/*

View file

@ -5,6 +5,6 @@
"trailingComma": "none", "trailingComma": "none",
"printWidth": 100, "printWidth": 100,
"plugins": ["prettier-plugin-svelte", "prettier-plugin-tailwindcss"], "plugins": ["prettier-plugin-svelte", "prettier-plugin-tailwindcss"],
"pluginSearchDirs": ["../../node_modules"], "pluginSearchDirs": ["./node_modules"],
"overrides": [{ "files": "*.svelte", "options": { "parser": "svelte" } }] "overrides": [{ "files": "*.svelte", "options": { "parser": "svelte" } }]
} }

View file

@ -31,10 +31,7 @@ move it to an issue. Bug fixes straight to pull request or issue please!
## Anatomy ## Anatomy
tea/gui is a Svelte Electon app. The electron “backend” can be found in tea/gui is a Svelte Electon app. The electron “backend” can be found in
`modules/desktop/electron`, the Svelte “frontend” is in both `modules/ui` and `modules/desktop/src`. `electron/`, the Svelte “frontend” is in `svelte/`.
Generic UI components designed for use with Storybook are located in `modules/ui` and more complex
components with integrated business logic are in `modules/desktop/src`.
The following technologies are used: The following technologies are used:
@ -54,14 +51,15 @@ xc dev # opens the app in dev mode
> Make sure to run `xc prettier` before submitting pull-requests. > Make sure to run `xc prettier` before submitting pull-requests.
&nbsp; &nbsp;
# Internationalization / Translations # Internationalization / Translations
We need help translating our user interface into different languages. The translation related source code are all in `./modules/desktop/src/libs/translations/*`.
We need help translating our user interface into different languages. The translation related source code are all in `./svelte/src/libs/translations/*`.
To add a new language: To add a new language:
1. Create a json file in `./modules/desktop/src/libs/translations/languages/[lang].json`. Copy the contents of `en.json` then translate. 1. Create a json file in `./svelte/src/libs/translations/languages/[lang].json`. Copy the contents of `en.json` then translate.
2. Import the new language in `./modules/desktop/src/libs/translations/index.ts`. More instructions are in that file. 2. Import the new language in `./svelte/src/libs/translations/index.ts`. More instructions are in that file.
# Tasks # Tasks
@ -72,55 +70,56 @@ The following can be run with [`xc`], eg. `xc build`.
Setup ensures that required configuration placeholder files are present and installs dependencies. Setup ensures that required configuration placeholder files are present and installs dependencies.
```sh ```sh
if [ ! -e modules/desktop/electron/config.json ]; then if [ ! -e electron/config.json ]; then
echo '{}' > modules/desktop/electron/config.json echo '{}' > electron/config.json
fi fi
if [ ! -e modules/desktop/.env ]; then if [ ! -e modules/desktop/.env ]; then
cp modules/desktop/.env.example modules/desktop/.env cp .env.example .env
fi fi
pnpm install npm install
pnpm run -r prepare npm run prepare
``` ```
## Build ## Build
```sh ```sh
pnpm install npm install
pnpm build:desktop npm run package
``` ```
## Build:lite ## Build:lite
Builds a `.app` that is not codesigned or notarized. Ideal for local testing. Builds only a `.app` that is not codesigned or notarized. Ideal for local testing.
``` ```
export CSC_IDENTITY_AUTO_DISCOVER=false export CSC_IDENTITY_AUTO_DISCOVER=false
export MAC_BUILD_TARGET=dir export MAC_BUILD_TARGET=dir
pnpm install export NOTARIZE=false
pnpm build:desktop npm install
npm run package
``` ```
## Dev ## Dev
```sh ```sh
pnpm install npm install
pnpm dev npm run dev
``` ```
## Prettier ## Prettier
```sh ```sh
pnpm run --reporter append-only -r format npm run format
``` ```
## Dist ## Dist
```sh ```sh
pnpm install npm install
pnpm --filter tea exec pnpm predist npm run predist
pnpm --filter tea exec pnpm dist npm run dist
``` ```
## Check ## Check
@ -128,8 +127,8 @@ pnpm --filter tea exec pnpm dist
Runs the typescript compiler and linter. Runs the typescript compiler and linter.
```sh ```sh
pnpm run -r check npm run check
pnpm run -r lint npm run lint
``` ```
## e2e ## e2e
@ -137,7 +136,7 @@ pnpm run -r lint
Runs the webdriver.io end to end tests. Assumes that `xc build` has already been executed. Runs the webdriver.io end to end tests. Assumes that `xc build` has already been executed.
```sh ```sh
pnpm run --reporter append-only -r e2e npm run e2e
``` ```
## Bump ## Bump
@ -155,13 +154,13 @@ if [ "$(git rev-parse --abbrev-ref HEAD)" != "main" ]; then
exit 1 exit 1
fi fi
V=$(node -p "require('./modules/desktop/package.json').version") V=$(node -p "require('./package.json').version")
V=$(tea semverator bump $V $PRIORITY) V=$(tea semverator bump $V $PRIORITY)
if ! grep -F "\"version\": \"$V\",$" modules/desktop/package.json; then if ! grep -F "\"version\": \"$V\",$" package.json; then
sed -i.bak -e "s/\"version\": .*,$/\"version\": \"$V\",/" modules/desktop/package.json sed -i.bak -e "s/\"version\": .*,$/\"version\": \"$V\",/" package.json
rm modules/desktop/package.json.bak rm package.json.bak
git add modules/desktop/package.json git add package.json
git commit -m "bump $V" --gpg-sign git commit -m "bump $V" --gpg-sign
fi fi
@ -171,25 +170,22 @@ git push origin main
## Release ## Release
```sh ```sh
V="$(node -p "require('./modules/desktop/package.json').version")" V="$(node -p "require('./package.json').version")"
tea gh release create "v$V" tea gh release create "v$V"
``` ```
&nbsp; &nbsp;
# Dependencies # Dependencies
[`tea/cli`] will automagically make these available to your environment. [`tea/cli`] will automagically make these available to your environment.
| Project | Version | | Project | Version |
|-----------------------------------|-----------| | ---------- | -------- |
| nodejs.org | =18.16.0 | | nodejs.org | =18.16.0 |
| pnpm.io | =7.33.1 | | npmjs.com | >=9.7.2 |
| xcfile.dev | >=0.4.1 | | xcfile.dev | >=0.4.1 |
| python.org | ^3.11 | | python.org | ^3.11 |
[`tea/cli`]: https://github.com/teaxyz/cli [`tea/cli`]: https://github.com/teaxyz/cli
[`xc`]: https://xcfile.dev [`xc`]: https://xcfile.dev

View file

@ -1,5 +1,5 @@
name: 'build-gui-linux' name: "build-gui-linux"
description: 'Tea GUI builder for linux' description: "Tea GUI builder for linux"
# TODO: cache # TODO: cache
# inputs: # inputs:
# who-to-greet: # id of input # who-to-greet: # id of input
@ -10,9 +10,9 @@ description: 'Tea GUI builder for linux'
# time: # id of output # time: # id of output
# description: 'The time we greeted you' # description: 'The time we greeted you'
runs: runs:
using: 'docker' using: "docker"
image: 'Dockerfile' image: "Dockerfile"
env: env:
CARGO_TARGET_DIR: /github/workspace/target CARGO_TARGET_DIR: /github/workspace/target
args: args:
- ${{ inputs.who-to-greet }} - ${{ inputs.who-to-greet }}

View file

@ -1,8 +1,8 @@
name: 'Tea Ubuntu' name: "Tea Ubuntu"
description: 'build gui using custom ubuntu' description: "build gui using custom ubuntu"
runs: runs:
using: 'docker' using: "docker"
image: 'Dockerfile' image: "Dockerfile"
args: args:
- build - build

View file

@ -9,7 +9,7 @@ module.exports = {
productName: "tea", productName: "tea",
asar: false, asar: false,
directories: { output: "dist" }, directories: { output: "dist" },
files: ["electron/dist/electron.cjs", { from: "build", to: "" }], files: ["electron/dist/electron.cjs", { from: "svelte/build", to: "" }],
linux: { linux: {
icon: "./icon.png" icon: "./icon.png"
}, },
@ -42,7 +42,9 @@ module.exports = {
] ]
}, },
afterSign: async (params) => { afterSign: async (params) => {
if (process.platform !== "darwin" || process.env.CSC_IDENTITY_AUTO_DISCOVERY === "false") { const shouldNotarize =
process.env.NOTARIZE === "true" || process.env.CSC_IDENTITY_AUTO_DISCOVERY === "true";
if (process.platform !== "darwin" || !shouldNotarize) {
console.log("not notarizing app"); console.log("not notarizing app");
return; return;
} }
@ -61,10 +63,12 @@ module.exports = {
try { try {
await notarize({ await notarize({
tool: "noatrytool",
appBundleId, appBundleId,
appPath, appPath,
appleId: process.env.APPLE_ID, appleId: process.env.APPLE_ID,
appleIdPassword: process.env.APPLE_APP_SPECIFIC_PASSWORD appleIdPassword: process.env.APPLE_APP_SPECIFIC_PASSWORD,
teamId: process.env.APPLE_TEAM_ID
}); });
} catch (error) { } catch (error) {
console.error(error); console.error(error);

View file

Before

Width:  |  Height:  |  Size: 1 MiB

After

Width:  |  Height:  |  Size: 1 MiB

3
electron/config.json Normal file
View file

@ -0,0 +1,3 @@
{
"PUSHY_APP_ID": "643647948f3b62fb34b29989"
}

View file

@ -6,7 +6,7 @@ import { app } from "electron";
import log from "./logger"; import log from "./logger";
import axios from "axios"; import axios from "axios";
import get from "./v1-client"; import get from "./v1-client";
import { DeviceAuth } from "../../src/libs/types"; import { DeviceAuth } from "../../svelte/src/libs/types";
import { notifyMainWindow } from "../electron"; import { notifyMainWindow } from "../electron";
import { InitWatcher } from "./initialize"; import { InitWatcher } from "./initialize";
import { baseURL } from "./v1-client"; import { baseURL } from "./v1-client";

View file

@ -1,5 +1,5 @@
import { spawn } from "child_process"; import { spawn } from "child_process";
import { getGuiPath } from "./tea-dir"; import { getGuiPath, getTeaPath } from "./tea-dir";
import fs from "fs"; import fs from "fs";
import path from "path"; import path from "path";
import { hooks } from "@teaxyz/lib"; import { hooks } from "@teaxyz/lib";
@ -8,6 +8,8 @@ import log from "./logger";
import { MainWindowNotifier } from "./types"; import { MainWindowNotifier } from "./types";
import { Installation, porcelain } from "@teaxyz/lib"; import { Installation, porcelain } from "@teaxyz/lib";
import type { Resolution } from "@teaxyz/lib/script/src/plumbing/resolve"; import type { Resolution } from "@teaxyz/lib/script/src/plumbing/resolve";
import { GUIPackage } from "../../svelte/src/libs/types";
import { getPantryDetails } from "./pantry";
export async function installPackage( export async function installPackage(
full_name: string, full_name: string,
@ -29,13 +31,19 @@ function newInstallProgressNotifier(full_name: string, notifyMainWindow: MainWin
}, },
progress: (progress: number) => { progress: (progress: number) => {
if (progress > 0 && progress <= 1) { if (progress > 0 && progress <= 1) {
notifyMainWindow("install-progress", { full_name, progress: progress * 100 }); notifyMainWindow("install-progress", {
full_name,
progress: progress * 100
});
} }
}, },
installed: (installation: Installation) => { installed: (installation: Installation) => {
log.info("installed", installation); log.info("installed", installation);
const { project, version } = installation.pkg; const { project, version } = installation.pkg;
notifyMainWindow("pkg-installed", { full_name: project, version: version.toString() }); notifyMainWindow("pkg-installed", {
full_name: project,
version: version.toString()
});
} }
}; };
} }
@ -51,24 +59,21 @@ async function installTeaCli() {
return teaPkg.path.join("bin/tea"); return teaPkg.path.join("bin/tea");
} }
export async function openPackageEntrypointInTerminal(pkg: string) { export async function openPackageEntrypointInTerminal(pkg: GUIPackage) {
const cliBinPath = await installTeaCli(); const cliBinPath = await installTeaCli();
log.info(`opening package ${pkg} with tea cli at ${cliBinPath}`); // look up the entrypoint for the package again in case it changed. This makes
// hacking on the entrypoint more ergonomic
const { entrypoint } = await getPantryDetails(pkg.full_name);
let sh = `"${cliBinPath}" --sync --env=false +${pkg} `; let sh = "sh";
switch (pkg) { if (entrypoint) {
case "github.com/AUTOMATIC1111/stable-diffusion-webui": sh = path.join(getTeaPath(), `${pkg.full_name}/v*`, entrypoint);
sh += `~/.tea/${pkg}/v*/entrypoint.sh`;
break;
case "cointop.sh":
sh += "cointop";
break;
default:
sh += "sh";
} }
const scriptPath = await createCommandScriptFile(sh); const cmd = `"${cliBinPath}" --env=false +${pkg.full_name} "${sh}"`;
log.info(`opening package ${pkg.full_name} in terminal with command: ${cmd}`);
const scriptPath = await createCommandScriptFile(cmd);
try { try {
let stdout = ""; let stdout = "";
let stderr = ""; let stderr = "";

View file

@ -8,7 +8,7 @@ import {
stopMonitoringTeaDir stopMonitoringTeaDir
} from "./tea-dir"; } from "./tea-dir";
import { readSessionData, writeSessionData, pollAuth } from "./auth"; import { readSessionData, writeSessionData, pollAuth } from "./auth";
import type { Packages, Session } from "../../src/libs/types"; import type { Packages, Session, GUIPackage } from "../../svelte/src/libs/types";
import log from "./logger"; import log from "./logger";
import { syncLogsAt } from "./v1-client"; import { syncLogsAt } from "./v1-client";
import { installPackage, openPackageEntrypointInTerminal, syncPantry } from "./cli"; import { installPackage, openPackageEntrypointInTerminal, syncPantry } from "./cli";
@ -20,6 +20,7 @@ import { nanoid } from "nanoid";
import { MainWindowNotifier } from "./types"; import { MainWindowNotifier } from "./types";
import { unsubscribeToPackageTopic } from "./push-notification"; import { unsubscribeToPackageTopic } from "./push-notification";
import { getHeaders } from "./v1-client"; import { getHeaders } from "./v1-client";
import { getPantryDetails } from "./pantry";
export type HandlerOptions = { export type HandlerOptions = {
// A function to call back to the current main // A function to call back to the current main
@ -94,11 +95,11 @@ export default function initializeHandlers({ notifyMainWindow }: HandlerOptions)
}); });
ipcMain.handle("open-terminal", async (_, data) => { ipcMain.handle("open-terminal", async (_, data) => {
const { pkg } = data as { pkg: string }; const { pkg } = data as { pkg: GUIPackage };
try { try {
// TODO: detect if mac or linux // TODO: detect if mac or linux
// current openTerminal is only design for Mac // current openTerminal is only design for Mac
log.info("open tea entrypoint in terminal for pkg:", pkg); log.info("open tea entrypoint in terminal for pkg:", pkg.full_name);
await openPackageEntrypointInTerminal(pkg); await openPackageEntrypointInTerminal(pkg);
} catch (error) { } catch (error) {
log.error(error); log.error(error);
@ -259,4 +260,12 @@ export default function initializeHandlers({ notifyMainWindow }: HandlerOptions)
return {}; return {};
} }
}); });
ipcMain.handle("get-pantry-details", async (_event, full_name: string) => {
try {
return await getPantryDetails(full_name);
} catch (error) {
return error;
}
});
} }

View file

@ -3,7 +3,7 @@ import { mkdirp } from "mkdirp";
import fs from "fs"; import fs from "fs";
import log from "./logger"; import log from "./logger";
import { getTeaPath } from "./tea-dir"; import { getTeaPath } from "./tea-dir";
import { GUIPackage, Packages } from "../../src/libs/types"; import { GUIPackage, Packages } from "../../svelte/src/libs/types";
import { isDev } from "./auto-updater"; import { isDev } from "./auto-updater";
const pkgsFilePath = path.join(getTeaPath(), "tea.xyz/gui/pkgs.json"); const pkgsFilePath = path.join(getTeaPath(), "tea.xyz/gui/pkgs.json");
@ -34,6 +34,11 @@ export async function loadPackageCache(): Promise<Packages> {
if (pkgs?.packages) { if (pkgs?.packages) {
// Remove any temporary properties that may have been added to the package (like installation progress) // Remove any temporary properties that may have been added to the package (like installation progress)
for (const [key, value] of Object.entries(pkgs.packages)) { for (const [key, value] of Object.entries(pkgs.packages)) {
// Don't load local packages from the cache
if (value.is_local) {
delete pkgs.packages[key];
continue;
}
const { install_progress_percentage, isUninstalling, synced, displayState, ...rest } = const { install_progress_percentage, isUninstalling, synced, displayState, ...rest } =
value; value;
pkgs.packages[key] = rest as GUIPackage; pkgs.packages[key] = rest as GUIPackage;

8
electron/libs/pantry.ts Normal file
View file

@ -0,0 +1,8 @@
import { hooks } from "@teaxyz/lib";
// Fetches the details for a package from the local pantry
export async function getPantryDetails(full_name: string) {
const packageYml = await hooks.usePantry().project(full_name).yaml();
const { ["display-name"]: display_name, entrypoint, provides } = packageYml;
return { display_name, entrypoint, provides };
}

View file

@ -30,7 +30,10 @@ export default function initialize(mainWindow: BrowserWindow) {
log.info( log.info(
`Registering device ${device_id} for push notifications with token: ${push_token}` `Registering device ${device_id} for push notifications with token: ${push_token}`
); );
if (device_id) await post(`/auth/device/${device_id}/register-push-token`, { push_token }); if (device_id)
await post(`/auth/device/${device_id}/register-push-token`, {
push_token
});
}) })
.catch((err) => { .catch((err) => {
log.error(err); log.error(err);

View file

@ -2,7 +2,7 @@ import fs from "fs";
import path from "path"; import path from "path";
import { app } from "electron"; import { app } from "electron";
import log from "./logger"; import log from "./logger";
import type { InstalledPackage } from "../../src/libs/types"; import type { InstalledPackage } from "../../svelte/src/libs/types";
import { mkdirp } from "mkdirp"; import { mkdirp } from "mkdirp";
import fetch from "node-fetch"; import fetch from "node-fetch";
import { SemVer, semver } from "@teaxyz/lib"; import { SemVer, semver } from "@teaxyz/lib";
@ -48,8 +48,11 @@ async function findInstalledVersions(pkgsPath: string): Promise<InstalledPackage
log.info("recursively reading:", pkgsPath); log.info("recursively reading:", pkgsPath);
const folders = await deepReadDir({ const folders = await deepReadDir({
dir: pkgsPath, dir: pkgsPath,
continueDeeper: (name: string) => !semver.isValid(name) && name !== ".tea", continueDeeper: (name: string, path: string) => {
filter: (name: string) => semver.isValid(name) && name !== ".tea" return !semver.isValid(name) && !name.startsWith(".") && !path.includes("tea.xyz/var");
},
filter: (name: string) => semver.isValid(name) && name !== ".tea",
maxDepth: 5
}); });
const bottles = folders const bottles = folders
@ -88,23 +91,35 @@ const parseVersionFromPath = (versionPath: string): ParsedVersion | null => {
} }
}; };
export const deepReadDir = async ({ export const deepReadDir = async (
dir, {
continueDeeper, dir,
filter continueDeeper,
}: { filter,
dir: string; maxDepth
continueDeeper?: (name: string) => boolean; }: {
filter?: (name: string) => boolean; dir: string;
}) => { continueDeeper?: (name: string, path: string) => boolean;
filter?: (name: string) => boolean;
maxDepth: number;
},
depth = 1
) => {
if (depth > maxDepth) {
return [];
}
const arrayOfFiles: string[] = []; const arrayOfFiles: string[] = [];
try { try {
const files = fs.readdirSync(dir, { withFileTypes: true }); const files = fs.readdirSync(dir, { withFileTypes: true });
for (const f of files) { for (const f of files) {
const nextPath = path.join(dir, f.name); const nextPath = path.join(dir, f.name);
const deeper = continueDeeper ? continueDeeper(f.name) : true; const deeper = f.isDirectory() && continueDeeper ? continueDeeper(f.name, nextPath) : true;
if (f.isDirectory() && deeper) { if (f.isDirectory() && deeper) {
const nextFiles = await deepReadDir({ dir: nextPath, continueDeeper, filter }); const nextFiles = await deepReadDir(
{ dir: nextPath, continueDeeper, filter, maxDepth },
depth + 1
);
arrayOfFiles.push(...nextFiles); arrayOfFiles.push(...nextFiles);
} else if (!f.isSymbolicLink() && filter && filter(f.name)) { } else if (!f.isSymbolicLink() && filter && filter(f.name)) {
arrayOfFiles.push(nextPath); arrayOfFiles.push(nextPath);
@ -226,7 +241,7 @@ export async function startMonitoringTeaDir(mainWindowNotifier: MainWindowNotifi
persistent: true, persistent: true,
followSymlinks: false, followSymlinks: false,
depth: 5, depth: 5,
ignored: ["**/var/pantry/projects/**", "**/local/tmp/**", "**/share/**"] ignored: ["**/var/pantry/projects/**", "**/local/tmp/**", "**/.local/tmp/**", "**/share/**"]
}); });
watcher watcher
@ -246,7 +261,11 @@ export async function startMonitoringTeaDir(mainWindowNotifier: MainWindowNotifi
if (semver.isValid(version)) { if (semver.isValid(version)) {
const full_name = dir.split(".tea/")[1]; const full_name = dir.split(".tea/")[1];
log.info(`Monitor - Removed Package: ${full_name} v${version}`); log.info(`Monitor - Removed Package: ${full_name} v${version}`);
mainWindowNotifier("pkg-modified", { full_name, version, type: "remove" }); mainWindowNotifier("pkg-modified", {
full_name,
version,
type: "remove"
});
} }
}) })
.on("error", (error) => log.error(`Watcher error: ${error}`)); .on("error", (error) => log.error(`Watcher error: ${error}`));

View file

Before

Width:  |  Height:  |  Size: 219 KiB

After

Width:  |  Height:  |  Size: 219 KiB

View file

@ -1 +0,0 @@
node-linker=hoisted

View file

@ -1,10 +0,0 @@
{
"tabWidth": 2,
"useTabs": false,
"singleQuote": false,
"trailingComma": "none",
"printWidth": 100,
"plugins": ["prettier-plugin-svelte", "prettier-plugin-tailwindcss"],
"pluginSearchDirs": ["../../node_modules"],
"overrides": [{ "files": "*.svelte", "options": { "parser": "svelte" } }]
}

View file

@ -1,140 +0,0 @@
{
"name": "tea",
"version": "0.2.34",
"private": true,
"description": "tea gui app",
"author": "tea.xyz",
"main": "electron/dist/electron.cjs",
"scripts": {
"prepare": "svelte-kit sync",
"dev": "cross-env NODE_ENV=dev npm run dev:all",
"dev:all": "concurrently -n=svelte,electron -c='#ff3e00',blue \"pnpm dev:main\" \"pnpm dev:svelte\" \"pnpm dev:electron\"",
"dev:svelte": "vite dev",
"dev:electron": "electron electron/dist/electron.cjs",
"dev:main": "cd ./electron && vite build --config ./vite.config.js --watch",
"build:main": "cp package.json electron && cd ./electron && vite --config ./vite.config.js build --base . && rm package.json",
"pack": "electron-builder --dir --config electron-builder.config.cjs",
"predist": "node ./scripts/predist.cjs",
"dist": "pnpm build && electron-builder --config electron-builder.config.cjs",
"package": "pnpm build && electron-builder --config electron-builder.config.cjs",
"dev:package": "pnpm build && electron-builder --config electron-builder.config.cjs --dir",
"electron": "concurrently --kill-others \"vite dev\" \"electron electron/dist/electron.cjs\"",
"olddev": "vite dev",
"build": "pnpm build:main && vite build && cp build/app.html build/index.html",
"preview": "vite preview",
"unit:test": "vitest",
"coverage": "vitest run --coverage",
"test": "playwright test",
"check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --compiler-warnings \"css-unused-selector:ignore\"",
"check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --compiler-warnings \"css-unused-selector:ignore\" --watch",
"lint": "prettier --check . && eslint .",
"format": "prettier --write .",
"e2e": "NODE_ENV=test wdio run ./wdio.conf.ts"
},
"devDependencies": {
"@electron/notarize": "^1.2.3",
"@playwright/experimental-ct-svelte": "^1.29.2",
"@playwright/test": "1.25.0",
"@sveltejs/adapter-auto": "^1.0.0",
"@sveltejs/adapter-node": "^1.0.0-next.101",
"@sveltejs/adapter-static": "^1.0.0-next.48",
"@sveltejs/kit": "^1.15.9",
"@tea/ui": "workspace:*",
"@testing-library/jest-dom": "^5.16.5",
"@testing-library/svelte": "^3.2.2",
"@testing-library/webdriverio": "^3.2.1",
"@types/bcryptjs": "^2.4.2",
"@types/canvas-confetti": "^1.6.0",
"@types/js-yaml": "^4.0.5",
"@types/mixpanel-browser": "^2.38.1",
"@types/testing-library__jest-dom": "^5.14.5",
"@typescript-eslint/eslint-plugin": "^5.27.0",
"@typescript-eslint/parser": "^5.27.0",
"@wdio/cli": "^8.10.1",
"@wdio/globals": "^8.10.1",
"@wdio/local-runner": "^8.10.1",
"@wdio/mocha-framework": "^8.10.1",
"@wdio/spec-reporter": "^8.10.1",
"autoprefixer": "^10.4.13",
"concurrently": "^7.6.0",
"cross-env": "^7.0.3",
"electron": "22.1.0",
"electron-builder": "^23.6.0",
"electron-reloader": "^1.2.3",
"eslint": "^8.16.0",
"eslint-config-prettier": "^8.3.0",
"eslint-plugin-svelte3": "^4.0.0",
"jsdom": "^21.0.0",
"postcss": "^8.4.19",
"prettier": "^2.8.8",
"prettier-plugin-svelte": "^2.10.0",
"prettier-plugin-tailwindcss": "^0.2.8",
"svelte": "^3.55.1",
"svelte-check": "^2.8.0",
"svelte-preprocess": "^5.0.1",
"svelte2tsx": "^0.5.20",
"tailwindcss": "^3.2.4",
"ts-node": "^10.9.1",
"tslib": "^2.3.1",
"typescript": "^4.7.4",
"vite": "^4.1.1",
"vitest": "^0.28.3",
"wdio-electron-service": "^4.0.2"
},
"type": "module",
"dependencies": {
"@deno/shim-crypto": "^0.3.1",
"@deno/shim-deno": "^0.16.1",
"@electron/asar": "^3.2.3",
"@sentry/browser": "^7.49.0",
"@sentry/electron": "^4.4.0",
"@sentry/svelte": "^7.47.0",
"@sentry/vite-plugin": "^0.7.2",
"@teaxyz/lib": "0.6.0",
"@types/electron": "^1.6.10",
"@types/mousetrap": "^1.6.11",
"@vitest/coverage-c8": "^0.27.1",
"axios": "^1.3.2",
"bcryptjs": "^2.4.3",
"buffer": "^6.0.3",
"canvas-confetti": "^1.6.0",
"chokidar": "^3.5.3",
"custom-electron-titlebar": "4.2.0-beta.0",
"dayjs": "^1.11.7",
"electron-context-menu": "^3.6.1",
"electron-is-packaged": "^1.0.2",
"electron-log": "^4.4.8",
"electron-serve": "^1.1.0",
"electron-updater": "^5.3.0",
"electron-vite": "^1.0.18",
"electron-window-state": "^5.0.3",
"fuse.js": "^6.6.2",
"is-what": "^4.1.15",
"js-yaml": "^4.1.0",
"koffi": "^2.4.2",
"lodash": "^4.17.21",
"lorem-ipsum": "^2.0.8",
"mixpanel-browser": "^2.45.0",
"mkdirp": "^2.1.3",
"moment": "^2.29.4",
"mousetrap": "^1.6.5",
"outdent": "^0.8.0",
"pushy-electron": "^1.0.11",
"renderer": "link:@types/electron/renderer",
"svelte-infinite-scroll": "^2.0.1",
"svelte-markdown": "^0.2.3",
"svelte-watch-resize": "^1.0.3",
"sveltekit-i18n": "^2.2.2",
"undici": "^5.22.1",
"upath": "^2.0.1",
"vite-plugin-static-copy": "^0.13.1",
"yaml": "^2.2.1"
},
"pnpm": {
"onlyBuiltDependencies": [
"@tea/ui"
]
},
"homepage": "https://tea.xyz",
"repository": "https://github.com/teaxyz/gui.git"
}

File diff suppressed because it is too large Load diff

View file

@ -1,12 +0,0 @@
const { theme, plugins } = require("@tea/ui/tailwind.config.cjs");
module.exports = {
plugins: {
tailwindcss: {
content: ["./src/**/*.{html,svelte,ts,js}", "../ui/src/**/*.{html,svelte,ts,js}"],
theme,
plugins: [...plugins]
},
autoprefixer: {}
}
};

View file

@ -1,6 +0,0 @@
<script lang="ts">
import "$appcss";
import Placeholder from "$components/placeholder/placeholder.svelte";
</script>
<Placeholder label="Badges" />

View file

@ -1,5 +0,0 @@
<script lang="ts">
import "$appcss";
</script>
<section class="h-56 border border-gray bg-black" />

View file

@ -1,25 +0,0 @@
<script lang="ts">
import "$appcss";
import { t } from "$libs/translations";
import type { AirtablePost } from "@tea/ui/types";
import Posts from "@tea/ui/posts/posts.svelte";
import PanelHeader from "@tea/ui/panel-header/panel-header.svelte";
import Preloader from "@tea/ui/Preloader/Preloader.svelte";
import { postsStore } from "$libs/stores";
export let title = "Workshops";
export let ctaLabel = "View all";
let courses: AirtablePost[] = [];
postsStore.subscribeByTag("course", (posts) => (courses = posts));
</script>
<PanelHeader {title} {ctaLabel} ctaLink="/" />
{#if courses.length}
<Posts posts={courses} linkTarget="_blank" />
{:else}
<section class="h-64 border border-gray bg-black p-4">
<Preloader />
</section>
{/if}

View file

@ -1,32 +0,0 @@
<script lang="ts">
import "$appcss";
import { t } from "$libs/translations";
import { postsStore } from "$libs/stores";
import type { Course } from "$libs/types";
import Gallery from "@tea/ui/gallery/gallery.svelte";
let courses: Course[] = [];
postsStore.subscribeByTag("featured_course", (posts) => {
courses = posts.map((post) => {
return {
title: post.title,
sub_title: post.sub_title,
banner_image_url: post.thumb_image_url,
link: post.link
} as Course;
});
});
</script>
<Gallery
title={$t("documentation.featured-courses-title").toUpperCase()}
items={courses.map((course) => ({
title: course.title,
subTitle: course.sub_title,
imageUrl: course.banner_image_url,
link: course.link
}))}
linkTarget="_blank"
/>

View file

@ -1,75 +0,0 @@
<script lang="ts">
import { t } from "$libs/translations";
import Button from "@tea/ui/button/button.svelte";
import * as pub from "$env/static/public";
</script>
<footer class="relative h-auto w-full bg-black">
<section class="p-4 px-16 py-16">
<h3 class="mb-5 text-2xl text-primary">{$t("footer.quick-links-title").toUpperCase()}</h3>
<menu class="flex gap-4">
<div class="flex-grow border border-l-0 border-r-0 border-gray">
<a href="/">
<Button>
<div class="flex justify-between text-primary hover:text-black">
<div class="uppercase">{$t("footer.about-tea-store").toUpperCase()}</div>
<div>&#8594</div>
</div>
</Button>
</a>
</div>
<div class="flex-grow border border-l-0 border-r-0 border-gray">
<a href="/">
<Button>
<div class="flex justify-between text-primary hover:text-black">
<div class="uppercase">{$t("footer.report-a-problem").toUpperCase()}</div>
<div>&#8594</div>
</div>
</Button>
</a>
</div>
<div class="flex-grow border border-l-0 border-r-0 border-gray">
<a href="https://tea.xyz" target="_blank" rel="noreferrer">
<Button>
<div class="flex justify-between text-primary hover:text-black">
<div class="uppercase">{$t("footer.visit-website").toUpperCase()}</div>
<div>&#8594</div>
</div>
</Button>
</a>
</div>
</menu>
</section>
<section class="flex h-16 justify-between border border-r-0 border-gray p-4 px-16">
<div class="flex gap-4 text-xs text-gray">
<a
href="https://tea.xyz/terms-of-use/"
target="_blank"
rel="noreferrer"
class="hover:text-white"
>
{$t("footer.terms-services").toUpperCase()}
</a>
<a
href="https://tea.xyz/privacy-policy/"
target="_blank"
rel="noreferrer"
class="hover:text-white"
>
{$t("footer.privacy-policy").toUpperCase()}
</a>
</div>
{#if pub.PUBLIC_VERSION}
<div class="flex gap-4 text-xs text-gray">
<span>v{pub.PUBLIC_VERSION}</span>
</div>
{/if}
</section>
</footer>
<style>
h3 {
color: #00ffd0;
}
</style>

View file

@ -1,45 +0,0 @@
<script lang="ts">
import "$appcss";
import ArticleCard from "@tea/ui/article-card/article-card.svelte";
const doStuff = () => {
console.log("do stuff!");
};
</script>
<header class="border border-gray bg-black p-4 text-primary">GETTING STARTED WITH TEA</header>
<section class="grid grid-cols-3 bg-black">
<div class="border border-gray p-4">
<ArticleCard
content={{
title: "installing tea",
copy: "It's time to take your first sip! Click below to visit our tea-cli documentation page.",
img_url: "/images/bored-ape.png",
cta_label: "Get Started",
link: "/cli"
}}
/>
</div>
<div class="border border-gray p-4">
<ArticleCard
content={{
title: "authenticating",
copy: "Using tea without authenticating is like playing a video game without the DLC. Join us today!",
img_url: "/images/bored-ape.png",
cta_label: "Get Started",
link: ""
}}
onClick={doStuff}
/>
</div>
<div class="border border-gray p-4">
<ArticleCard
content={{
title: "give us a star",
copy: "Revolutions are built on the will of the people. Show your support for a more equitable internet.",
img_url: "/images/bored-ape.png",
cta_label: "Get Started"
}}
/>
</div>
</section>

View file

@ -1,22 +0,0 @@
<script lang="ts">
import "$appcss";
import { t } from "$libs/translations";
import { postsStore } from "$libs/stores";
import type { AirtablePost } from "@tea/ui/types";
import Posts from "@tea/ui/posts/posts.svelte";
import PanelHeader from "@tea/ui/panel-header/panel-header.svelte";
import Preloader from "@tea/ui/Preloader/Preloader.svelte";
let news: AirtablePost[] = [];
postsStore.subscribeByTag("news", (posts) => (news = posts));
</script>
<PanelHeader title="OPEN-SOURCE NEWS" ctaLabel="Read more articles" ctaLink="/" />
{#if news.length}
<Posts posts={news} linkTarget="_blank" />
{:else}
<section class="h-64 border border-gray bg-black p-4">
<Preloader />
</section>
{/if}

View file

@ -1,56 +0,0 @@
<script lang="ts">
import "$appcss";
import { afterUpdate } from "svelte";
import ReviewCard from "@tea/ui/review-card/review-card.svelte";
import type { Review } from "@tea/ui/types";
export let reviews: Review[];
export let showLimit = 9;
let showMore = false;
const getColReviews = (n: number) => {
const showReviews = reviews.filter((_item, i) => (i - n) % 3 === 0);
return showMore ? showReviews : showReviews.slice(0, showLimit / 3);
};
let col1: Review[] = [];
let col2: Review[] = [];
let col3: Review[] = [];
afterUpdate(() => {
col1 = getColReviews(0);
col2 = getColReviews(1);
col3 = getColReviews(2);
});
// TODO: problem with reviews with differing heights
// ideally they should work like metro-ui to not have extreme height diff between columns
</script>
<header class="border border-gray bg-black p-4 text-primary">REVIEWS ({reviews.length})</header>
<section class="flex flex-row flex-wrap bg-black">
<div class="w-1/3 border-0 border-b-2 border-l-2 border-gray p-4">
{#each col1 as review}
<ReviewCard {review} />
<div class="mt-4" />
{/each}
</div>
<div class="w-1/3 border-0 border-b-2 border-l-2 border-gray p-4">
{#each col2 as review}
<ReviewCard {review} />
<div class="mt-4" />
{/each}
</div>
<div class="w-1/3 border-0 border-x-2 border-b-2 border-gray p-4">
{#each col3 as review}
<ReviewCard {review} />
<div class="mt-4" />
{/each}
</div>
</section>
{#if showLimit <= reviews.length && showMore === false}
<footer class="border border-gray bg-black p-4">
<button on:click={() => (showMore = true)}>SHOW MORE</button>
</footer>
{/if}

View file

@ -1,28 +0,0 @@
<script lang="ts">
import "$appcss";
import { PackageStates, type GUIPackage } from "$libs/types";
import { packagesStore } from "$libs/stores";
import PackageCard from "$components/package-card/package-card.svelte";
export let tab = "all";
export let pkg: GUIPackage;
export let layout: "bottom" | "left" | "right" = "bottom";
</script>
<PackageCard
{pkg}
{layout}
link="/packages/{pkg.slug}?tab={tab}"
progessLoading={pkg.install_progress_percentage}
onClickCTA={async () => {
if (
[PackageStates.INSTALLED, PackageStates.INSTALLING, PackageStates.UPDATING].includes(
pkg.state
)
) {
return;
}
packagesStore.installPkg(pkg);
}}
/>

View file

@ -1,35 +0,0 @@
<script lang="ts">
import "$appcss";
import { shellOpenExternal } from "@native";
const openGithub = () => {
shellOpenExternal("https://github.com/teaxyz");
};
</script>
<div class="card social-box" style="width: 100%; float:right;">
<header class="border-b border-gray pb-7 pl-5 pt-7 text-primary">PRE-FLIGHT</header>
<div class="listbox-item border-b border-gray p-6">
<a href="/cli">
<p>Install Tea</p>
</a>
</div>
<div class="listbox-item border-b border-gray p-6">
<div>
<p>Authenticate</p>
</div>
</div>
<div class="listbox-item p-6">
<button on:click={openGithub}>Give tea a star</button>
</div>
</div>
<style>
.card {
border: 2px solid #949494;
background-color: #1a1a1a;
}
.listbox-item {
height: 75px;
}
</style>

View file

@ -1,62 +0,0 @@
<script lang="ts">
export let value = 0;
export let max = 100;
$: progressPath = () => {
if (value <= 0) {
return "";
} else if (value >= max) {
return "M50,5A45 45 0 1 1 49.9999 5";
} else {
const angle = Math.PI * 2 * (value / max);
const x = 50 + Math.cos(angle - Math.PI / 2) * 45;
const y = 50 + Math.sin(angle - Math.PI / 2) * 45;
let path = "M50,5";
if (angle > Math.PI) {
path += "A45 45 0 0 1 50 95";
}
path += `A45 45 0 0 1 ${x} ${y}`;
return path;
}
};
</script>
<div>
<svg viewBox="0 0 100 100">
<path d="M50,5A45 45 0 1 1 49.9999 5" />
<path d={progressPath()} />
</svg>
<div>
<slot>
<span>{value}</span>
</slot>
</div>
</div>
<style>
svg {
fill: var(--progress-fill, transparent);
height: 100%;
position: absolute;
stroke-linecap: var(--progress-linecap, round);
width: 100%;
}
path:first-child {
stroke: var(--progress-trackcolor, grey);
stroke-width: var(--progress-trackwidth, 9px);
}
path:last-child {
stroke: var(--progress-color, lightgreen);
stroke-width: var(--progress-width, 10px);
}
div {
height: 100%;
position: relative;
width: 100%;
}
span {
left: 50%;
position: absolute;
top: 50%;
transform: translate(-50%, -50%);
}
</style>

View file

@ -1,40 +0,0 @@
<script lang="ts">
import "$appcss";
import type { GUIPackage } from "$libs/types";
import type { Package } from "@tea/ui/types";
import { PackageStates } from "$libs/types";
import Preloader from "@tea/ui/Preloader/Preloader.svelte";
import PackageCard from "$components/packages/package.svelte";
import { onMount } from "svelte";
import { packagesStore } from "$libs/stores";
export let pkg: Package;
let packages: GUIPackage[] = [];
onMount(async () => {
if (!packages.length) {
const matches = await packagesStore.search(pkg.short_description, 4);
packages = matches.filter((mp) => mp.full_name !== pkg.full_name).slice(0, 3);
}
});
</script>
<header class="flex items-center justify-between border border-gray bg-black p-4 text-primary">
<span>MORE LIKE THIS</span>
</header>
<ul class="grid grid-cols-3 bg-black">
{#if packages.length > 0}
{#each packages as pkg}
<div class={pkg.state === PackageStates.INSTALLING ? "animate-pulse" : ""}>
<PackageCard {pkg} />
</div>
{/each}
{:else}
{#each Array(9) as _}
<section class="h-50 border border-gray p-4">
<Preloader />
</section>
{/each}
{/if}
</ul>

View file

@ -1,96 +0,0 @@
// as much possible add types here that are unique to @tea/desktop use only
// else
// please use the package @tea/ui/src/types.ts
// things that go there are shared types/shapes like ie: Package
import type { Package, Developer } from "@tea/ui/types";
export enum PackageStates {
AVAILABLE = "AVAILABLE",
INSTALLED = "INSTALLED",
INSTALLING = "INSTALLING",
NEEDS_UPDATE = "NEEDS_UPDATE",
UPDATING = "UPDATING"
}
// PackageDisplayState is a TEMPORARY state for showing temporary UI elements when a package is
// installed or updated. It is not persisted.
export interface PackageDisplayState {
// INSTALLED -> The package was installed successfully. Let's show some confetti!
// UPDATED -> The package was updated successfully so change the badge temporarily
// ERROR -> The package failed to install so show an error overlay temporarily
state: "INSTALLED" | "UPDATED" | "ERROR";
errorMessage?: string;
version: string;
}
export type Packages = {
version: string;
packages: { [full_name: string]: GUIPackage };
};
export type GUIPackage = Package & {
state: PackageStates;
installed_versions?: string[];
synced?: boolean;
install_progress_percentage?: number;
isUninstalling?: boolean;
cached_image_url?: string;
image_512_url?: string;
image_128_url?: string;
displayState?: PackageDisplayState | null;
};
export type Course = {
title: string;
sub_title: string;
banner_image_url: string;
link: string;
};
export type Category = {
label: string;
cta_label: string;
packages: GUIPackage[];
};
export enum AuthStatus {
UNKNOWN = "UNKNOWN",
PENDING = "PENDING",
SUCCESS = "SUCCESS",
FAILED = "FAILED"
}
export type DeviceAuth = {
status: AuthStatus;
user?: Developer;
key: string;
};
export interface Session {
device_id?: string;
key?: string;
user?: Developer;
locale?: string;
teaVersion?: string;
}
export enum SideMenuOptions {
discover = "discover",
all = "all",
installed = "installed",
installed_updates_available = "installed_updates_available",
recently_updated = "recently_updated",
new_packages = "new_packages",
popular = "popular",
featured = "featured",
essentials = "essentials",
starstruck = "starstruck",
made_by_tea = "made_by_tea"
}
export type InstalledPackage = Required<Pick<GUIPackage, "full_name" | "installed_versions">>;
export type AutoUpdateStatus = {
status: "up-to-date" | "available" | "ready";
version?: string;
};

View file

@ -1,22 +0,0 @@
<script>
import "$appcss";
import { t } from "$libs/translations";
import PageHeader from "$components/page-header/page-header.svelte";
import FeaturedCourses from "$components/featured-courses/featured-courses.svelte";
import EssentialWorkshops from "$components/essential-workshops/essential-workshops.svelte";
</script>
<div>
<PageHeader>{$t("documentation.title").toUpperCase()}</PageHeader>
<section>
<FeaturedCourses />
</section>
<section class="mt-8">
<EssentialWorkshops
title={$t("documentation.workshops").toUpperCase()}
ctaLabel={$t("view-all")}
/>
</section>
</div>

View file

@ -1,6 +0,0 @@
import { theme, plugins } from "@tea/ui/tailwind.config.cjs";
module.exports = {
content: ["./src/**/*.{html,svelte,ts,js}", "../ui/src/**/*.{html,svelte,ts,js}"],
theme,
plugins: [...plugins]
};

View file

@ -1,3 +0,0 @@
declare module "electron-is-packaged" {
export let isPackaged: boolean;
}

View file

@ -1,13 +0,0 @@
.DS_Store
node_modules
/build
/.svelte-kit
/package
.env
.env.*
!.env.example
# Ignore files for PNPM, NPM and YARN
pnpm-lock.yaml
package-lock.json
yarn.lock

View file

@ -1,41 +0,0 @@
module.exports = {
root: true,
globals: {
NodeJS: true
},
parser: "@typescript-eslint/parser",
extends: [
"eslint:recommended",
"plugin:@typescript-eslint/recommended",
"prettier",
"plugin:storybook/recommended"
],
plugins: ["svelte3", "@typescript-eslint"],
ignorePatterns: ["*.cjs"],
overrides: [
{
files: ["*.svelte"],
processor: "svelte3/svelte3"
}
],
settings: {
"svelte3/typescript": () => require("typescript")
},
parserOptions: {
sourceType: "module",
ecmaVersion: 2020
},
env: {
browser: true,
es2017: true,
node: true
},
rules: {
"@typescript-eslint/no-unused-vars": [
"warn",
{
argsIgnorePattern: "^_"
}
]
}
};

12
modules/ui/.gitignore vendored
View file

@ -1,12 +0,0 @@
.DS_Store
node_modules
/build
/.svelte-kit
/package
.env
.env.*
!.env.example
vite.config.js.timestamp-*
vite.config.ts.timestamp-*
scripts/*.zip
scripts/*.css

View file

@ -1 +0,0 @@
engine-strict=true

View file

@ -1,13 +0,0 @@
.DS_Store
node_modules
/build
/.svelte-kit
/package
.env
.env.*
!.env.example
# Ignore files for PNPM, NPM and YARN
pnpm-lock.yaml
package-lock.json
yarn.lock

View file

@ -1,16 +0,0 @@
const path = require("path");
module.exports = {
stories: ["../src/**/*.stories.mdx", "../src/**/*.stories.@(js|jsx|ts|tsx|svelte)"],
addons: [
"@storybook/addon-links",
"@storybook/addon-essentials",
"@storybook/addon-interactions"
],
framework: {
name: "@storybook/svelte-vite",
options: {}
},
docs: {
docsPage: true
}
};

View file

@ -1,3 +0,0 @@
<script>
window.global = window;
</script>

View file

@ -1,9 +0,0 @@
export const parameters = {
actions: { argTypesRegex: "^on[A-Z].*" },
controls: {
matchers: {
color: /(background|color)$/i,
date: /Date$/
}
}
};

View file

@ -1,67 +0,0 @@
{
"name": "@tea/ui",
"version": "0.0.1",
"scripts": {
"prepare": "svelte-kit sync",
"vite:dev": "vite dev",
"build": "svelte-kit sync && svelte-package",
"prepublishOnly": "echo 'Did you mean to publish `./package/`, instead of `./`?' && exit 1",
"test": "playwright test",
"check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json",
"check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch",
"lint": "prettier --check . && eslint .",
"format": "prettier --write .",
"dev": "storybook dev -p 6006",
"build-storybook": "storybook build",
"update-icons": "node scripts/update-icons.js"
},
"files": [
"src/**/*",
"tsconfig.json",
"tailwind.config.cjs"
],
"devDependencies": {
"@playwright/test": "1.25.0",
"@storybook/addon-essentials": "^7.0.0-alpha.51",
"@storybook/addon-interactions": "^7.0.0-alpha.51",
"@storybook/addon-links": "^7.0.0-alpha.51",
"@storybook/svelte": "^7.0.0-alpha.51",
"@storybook/svelte-vite": "^7.0.0-alpha.51",
"@storybook/testing-library": "^0.0.13",
"@sveltejs/adapter-auto": "^1.0.0",
"@sveltejs/kit": "^1.0.0",
"@sveltejs/package": "^1.0.1",
"@typescript-eslint/eslint-plugin": "^5.27.0",
"@typescript-eslint/parser": "^5.27.0",
"autoprefixer": "^10.4.13",
"eslint": "^8.16.0",
"eslint-config-prettier": "^8.3.0",
"eslint-plugin-storybook": "^0.6.7",
"eslint-plugin-svelte3": "^4.0.0",
"postcss": "^8.4.19",
"prettier": "^2.8.8",
"prettier-plugin-svelte": "^2.10.0",
"prettier-plugin-tailwindcss": "^0.2.8",
"storybook": "^7.0.0-alpha.51",
"svelte": "^3.44.0",
"svelte-check": "^2.7.1",
"svelte-preprocess": "^4.10.7",
"tailwindcss": "^3.2.4",
"tslib": "^2.3.1",
"typescript": "^4.7.4",
"vite": "^4.1.1"
},
"type": "module",
"dependencies": {
"@magidoc/plugin-svelte-prismjs": "^3.0.6",
"@tailwindcss/line-clamp": "^0.4.2",
"@types/he": "^1.2.0",
"@types/prismjs": "^1.26.0",
"he": "^1.2.0",
"marked": "^5.0.4",
"prismjs": "^1.29.0",
"restructured": "0.0.11",
"svelte-markdown": "^0.2.3",
"svelte-watch-resize": "^1.0.3"
}
}

View file

@ -1,10 +0,0 @@
import type { PlaywrightTestConfig } from "@playwright/test";
const config: PlaywrightTestConfig = {
webServer: {
command: "npm run build && npm run preview",
port: 4173
}
};
export default config;

View file

@ -1,6 +0,0 @@
module.exports = {
plugins: {
tailwindcss: {},
autoprefixer: {}
}
};

View file

@ -1,18 +0,0 @@
import Button from "./button-view.svelte";
// More on how to set up stories at: https://storybook.js.org/docs/7.0/svelte/writing-stories/introduction
export default {
title: "Example/Button",
component: Button,
tags: ["docsPage"],
render: (args) => ({
Component: Button,
props: args
}),
argTypes: {
onClick: () => console.log("does nothing")
}
};
// More on writing stories with args: https://storybook.js.org/docs/7.0/svelte/writing-stories/args
export const Primary = {};

View file

@ -1,42 +0,0 @@
import Gallery from "./Gallery.svelte";
// More on how to set up stories at: https://storybook.js.org/docs/7.0/svelte/writing-stories/introduction
export default {
title: "Example/Gallery",
component: Gallery,
tags: ["docsPage"],
render: (args) => ({
Component: Gallery,
props: args
}),
argTypes: {
onClick: () => console.log("does nothing")
}
};
// More on writing stories with args: https://storybook.js.org/docs/7.0/svelte/writing-stories/args
export const Example = {
args: {
items: [
{
imageUrl:
"https://upload.wikimedia.org/wikipedia/commons/thumb/8/85/%22_Shot_From_The_Sky%22_Army_Show_1945_Oak_Ridge_%2824971013612%29.jpg/2732px-%22_Shot_From_The_Sky%22_Army_Show_1945_Oak_Ridge_%2824971013612%29.jpg",
title: "Item 1",
subTitle: "sub-title",
link: "#"
},
{
imageUrl: "https://tea.xyz/Images/packages/sqlite_org.jpg",
title: "Item 2",
subTitle: "sub-title 2",
link: "#"
},
{
imageUrl: "https://tea.xyz/Images/packages/gnu_org_libtool.jpg",
title: "Item 3",
subTitle: "sub-title 3",
link: "#"
}
]
}
};

View file

@ -1,36 +0,0 @@
import Header from "./Header.svelte";
export default {
title: "Example/Header",
component: Header,
// This component will have an automatically generated docsPage entry: https://storybook.js.org/docs/7.0/svelte/writing-docs/docs-page
tags: ["docsPage"],
render: (args) => ({
Component: Header,
props: args,
on: {
login: args.onLogin,
logout: args.onLogout,
createAccount: args.onCreateAccount
}
}),
parameters: {
// More on how to position stories at: https://storybook.js.org/docs/7.0/svelte/configure/story-layout
layout: "fullscreen"
},
argTypes: {
onLogin: { action: "onLogin" },
onLogout: { action: "onLogout" },
onCreateAccount: { action: "onCreateAccount" }
}
};
export const LoggedIn = {
args: {
user: {
name: "Jane Doe"
}
}
};
export const LoggedOut = {};

View file

@ -1,33 +0,0 @@
import Posts from "./Posts.svelte";
export default {
title: "Example/Posts",
component: Posts,
render: ({ posts }) => ({
Component: Posts,
props: {
posts
}
})
};
// More on interaction testing: https://storybook.js.org/docs/7.0/svelte/writing-tests/interaction-testing
export const Example = {
args: {
posts: [
{
airtable_record_id: "a",
link: "https://google.com",
title: "Tea Inc releases game changing api!",
sub_title: "lorem ipsum dolor sit amet",
short_description: "lorem ipsum dolor sit amet",
thumb_image_url: "/images/bored-ape.png",
thumb_image_name: "borred-api.png",
created_at: new Date(),
updated_at: new Date(),
published_at: new Date(),
tags: ["news"]
}
]
}
};

View file

@ -1,14 +0,0 @@
import Preloader from "./Preloader.svelte";
// More on how to set up stories at: https://storybook.js.org/docs/7.0/svelte/writing-stories/introduction
export default {
title: "Example/Preloader",
component: Preloader,
tags: ["docsPage"],
render: () => ({
Component: Preloader
})
};
// More on writing stories with args: https://storybook.js.org/docs/7.0/svelte/writing-stories/args
export const Example = {};

View file

@ -1,15 +0,0 @@
@import url(./icons/icons.css);
@tailwind base;
@tailwind components;
@tailwind utilities;
@font-face {
font-family: "mona-sans";
src: url("/fonts/mona-sans-bold.woff2");
}
@font-face {
font-family: "inter";
src: url("/fonts/inter-regular.woff2");
}

View file

@ -1,20 +0,0 @@
/// <reference types="@sveltejs/kit" />
// See https://kit.svelte.dev/docs/types#app
// for information about these interfaces
// and what to do when importing types
declare namespace App {
// interface Locals {}
// interface PageData {}
// interface Error {}
// interface Platform {}
}
// Declare custom event handlers here to make typscript happy.
declare namespace svelte.JSX {
// eslint-disable-next-line @typescript-eslint/no-unused-vars
interface HTMLAttributes<T> {
onclick_outside: () => void;
onleave_delay: () => void;
}
}

View file

@ -1,12 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<link rel="icon" href="%sveltekit.assets%/favicon.png" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
%sveltekit.head%
</head>
<body>
<div>%sveltekit.body%</div>
</body>
</html>

View file

@ -1,35 +0,0 @@
import ArticleCard from "./ArticleCard.svelte";
// More on how to set up stories at: https://storybook.js.org/docs/7.0/svelte/writing-stories/introduction
export default {
title: "Example/ArticleCard",
component: ArticleCard,
tags: ["docsPage"],
render: ({ content }) => ({
Component: ArticleCard,
props: { content }
}),
argTypes: {
content: {
name: "content",
description: "this is type Article"
},
onClick: {
name: "onClick",
description: "this is optional function"
}
}
};
// More on writing stories with args: https://storybook.js.org/docs/7.0/svelte/writing-stories/args
export const Example = {
args: {
content: {
title: "installing tea",
copy: "Lorem ipsum dolor sit amet consectetur adipisicing elit. Voluptas, voluptatum molestiae esse quisquam earum debitis.",
img_url: "https://tea.xyz/Images/packages/unicode_org.jpg",
cta_label: "Get Started",
link: "/cli"
}
}
};

View file

@ -1,33 +0,0 @@
<script lang="ts">
import "../app.css";
type Article = {
title: string;
img_url: string;
copy: string;
cta_label: string;
link?: string;
};
export let content: Article;
export let onClick: undefined | (() => void) = undefined;
</script>
<section class="border border-gray">
<header class="bg-accent p-2 uppercase text-white">{content.title}</header>
<figure class="h-24">
<img class="h-24 w-full object-cover" src={content.img_url} alt={content.title} />
</figure>
<article class="p-4">
<p class="text-xs line-clamp-3">{content.copy}</p>
{#if content.link}
<a href={content.link || "#"}>
<button class="mt-2 text-primary">{content.cta_label}</button>
</a>
{:else if onClick}
<button on:click={onClick} class="mt-2 text-primary">{content.cta_label}</button>
{:else}
<button disabled class="mt-2 text-gray">{content.cta_label}</button>
{/if}
</article>
</section>

View file

@ -1,5 +0,0 @@
<script lang="ts">
import Button from "./Button.svelte";
</script>
<Button>Click Me</Button>

View file

@ -1,80 +0,0 @@
<script lang="ts">
export let label: string;
export let checked: boolean;
</script>
<label class="flex justify-between text-sm">
<div>{label}</div>
<div class="checkbox">
<input type="checkbox" bind:checked />
<span class="checkmark" />
</div>
</label>
<style>
label {
position: relative;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
}
/* Hide the browser's default checkbox */
label .checkbox {
position: relative;
width: 25px;
height: 25px;
}
label input {
opacity: 0;
cursor: auto;
height: 0;
width: 0;
}
/* Create a custom checkbox */
.checkmark {
position: absolute;
top: 2px;
left: 0;
height: 14px;
width: 14px;
background-color: #eee;
}
/* On mouse-over, add a grey background color */
label:hover input ~ .checkmark {
background-color: #ccc;
}
/* When the checkbox is checked, add a blue background */
label input:checked ~ .checkmark {
background-color: #00ffd0;
}
/* Create the checkmark/indicator (hidden when not checked) */
.checkmark:after {
content: "";
position: absolute;
display: none;
}
/* Show the checkmark when checked */
label input:checked ~ .checkmark:after {
display: block;
}
/* Style the checkmark/indicator */
label .checkmark:after {
left: 5px;
top: 2px;
width: 5px;
height: 10px;
border: solid white;
border-width: 0 3px 3px 0;
-webkit-transform: rotate(45deg);
-ms-transform: rotate(45deg);
transform: rotate(45deg);
}
</style>

View file

@ -1,60 +0,0 @@
<script lang="ts">
import "../app.css";
import ImgLoader from "../img-loader/img-loader.svelte";
export let width = 0;
export let imageUrl = "";
export let title = "";
export let subTitle = "";
</script>
<figure class="gallery-item relative h-full w-full" style={`width:${width}px`}>
<ImgLoader
class="featured-img"
src={!imageUrl.includes("https://tea.xyz") ? "/images/default-thumb.jpg" : imageUrl}
alt={title}
/>
<article class="card-thumb-label">
<i class="icon-tea-logo-iconasset-1">
<!-- TODO: replace with icon.svg -->
</i>
<h3 class="text-3xl">{title}</h3>
{#if subTitle}
<h4 class="mt-2 text-lg">&#x2022;&nbsp;{subTitle}</h4>
{/if}
</article>
</figure>
<style>
.gallery-item :global(.featured-img) {
box-shadow: 0px 0px 12px #0c0c0c !important;
object-fit: cover;
}
.card-thumb-label i {
font-size: 1.5vw;
color: black;
}
.card-thumb-label h3 {
color: black;
line-height: 1.8vw;
margin: 0px 0px 0.5vw 0vw;
padding: 0px;
}
.card-thumb-label {
position: absolute;
background: rgba(255, 255, 255, 0.9);
left: 0;
bottom: 20px;
padding: 1.116vw;
text-align: left;
min-width: 40%;
height: 40%;
}
.card-thumb-label h4 {
color: black;
}
</style>

View file

@ -1,91 +0,0 @@
<script lang="ts">
import "../app.css";
import { onDestroy, onMount } from "svelte";
import { watchResize } from "svelte-watch-resize";
import Preloader from "../Preloader/Preloader.svelte";
import GalleryItem from "./gallery-item.svelte";
export let title = "";
export let linkTarget = "";
interface GalleryItemShape {
imageUrl: string;
title: string;
subTitle: string;
link: string;
}
export let items: GalleryItemShape[] = [];
let focus = 0;
let width = 0;
let styleFeaturedPackages: string;
function resetFeaturedStyle() {
const position = focus * width;
styleFeaturedPackages = `
width: ${items.length * width}px;
left: -${position}px;
transition: left 0.6s ease-in;
`;
}
function handleContainerResize(node: HTMLElement) {
width = node.clientWidth;
resetFeaturedStyle();
}
let loop: NodeJS.Timer;
function resetLoop() {
if (loop) clearInterval(loop);
loop = setInterval(() => {
focus++;
if (focus === items.length) {
focus = 0;
}
resetFeaturedStyle();
}, 3000);
resetFeaturedStyle();
}
onDestroy(() => clearInterval(loop));
onMount(() => {
resetLoop();
});
</script>
<section class="h-96 w-full bg-black" use:watchResize={handleContainerResize}>
<!-- <Placeholder label="FeaturedPackages" /> -->
<header class="flex h-12 items-center justify-between bg-accent px-2">
<p>{title}</p>
<ul class="flex gap-2">
{#each items as _item, i}
<button
on:click={() => {
focus = i;
resetLoop();
}}
class={`bg-purple h-3 w-3 rounded-lg border border-white transition-colors ${
i === focus ? "bg-purple-900" : ""
}`}
/>
{/each}
</ul>
</header>
<figure class="absolute bottom-0 left-0 right-0 top-12 overflow-hidden">
{#if items.length}
<section class="absolute top-0 flex h-full" style={styleFeaturedPackages}>
{#each items as item}
<div class="h-full" style={`width:${width}px`}>
<a href={item.link} target={linkTarget} rel="noopener">
<GalleryItem {...item} {width} />
</a>
</div>
{/each}
</section>
{:else}
<Preloader />
{/if}
</figure>
</section>

View file

@ -1,25 +0,0 @@
<script lang="ts">
import "../app.css";
export let title: string;
export let imgUrl: string;
export let ctaUrl: string;
export let ctaLabel: string;
export let articleTitle: string;
export let description: string;
</script>
<section class="border border-gray bg-black">
<header class="flex justify-between p-4 text-primary">
<h1 class="uppercase">{title}</h1>
<a href={ctaUrl} class="text-sm">{ctaLabel}</a>
</header>
<figure class="h-40">
<img class="h-40 w-full object-cover" src={imgUrl} alt={title} />
</figure>
<article class="m-4 border border-gray p-4">
<h2 class="uppercase text-primary">{articleTitle}</h2>
<p class="text-gray">{description}</p>
</article>
</section>

View file

@ -1,34 +0,0 @@
@import "../app.css";
.wrapper {
font-family: "Nunito Sans", "Helvetica Neue", Helvetica, Arial, sans-serif;
border-bottom: 1px solid rgba(0, 0, 0, 0.1);
padding: 15px 20px;
display: flex;
align-items: center;
justify-content: space-between;
}
svg {
display: inline-block;
vertical-align: top;
}
h1 {
font-weight: 900;
font-size: 20px;
line-height: 1;
margin: 6px 0 6px 10px;
display: inline-block;
vertical-align: top;
}
button + button {
margin-left: 10px;
}
.welcome {
color: #333;
font-size: 14px;
margin-right: 10px;
}

View file

@ -1,53 +0,0 @@
<script lang="ts">
import "./header.css";
import Button from "../button/button.svelte";
import { createEventDispatcher } from "svelte";
export let user = null;
const dispatch = createEventDispatcher();
function onLogin(event) {
dispatch("login", event);
}
function onLogout(event) {
dispatch("logout", event);
}
function onCreateAccount(event) {
dispatch("createAccount", event);
}
</script>
<header>
<div class="wrapper">
<div>
<svg width="32" height="32" viewBox="0 0 32 32" xmlns="http://www.w3.org/2000/svg">
<g fill="none" fill-rule="evenodd">
<path
d="M10 0h12a10 10 0 0110 10v12a10 10 0 01-10 10H10A10 10 0 010 22V10A10 10 0 0110 0z"
fill="#FFF"
/>
<path
d="M5.3 10.6l10.4 6v11.1l-10.4-6v-11zm11.4-6.2l9.7 5.5-9.7 5.6V4.4z"
fill="#555AB9"
/>
<path d="M27.2 10.6v11.2l-10.5 6V16.5l10.5-6zM15.7 4.4v11L6 10l9.7-5.5z" fill="#91BAF8" />
</g>
</svg>
<h1>Acme</h1>
</div>
<div>
{#if user}
<span class="welcome">
Welcome, <b>{user.name}</b>!
</span>
<Button size="small" on:click={onLogout} label="Log out" />
{/if}
{#if !user}
<Button size="small" on:click={onLogin} label="Log in" />
<Button primary size="small" on:click={onCreateAccount} label="Sign up" />
{/if}
</div>
</div>
</header>

View file

@ -1,28 +0,0 @@
import ImgLoader from "./ImgLoader.svelte";
// More on how to set up stories at: https://storybook.js.org/docs/7.0/svelte/writing-stories/introduction
interface Props {
alt: string;
src: string;
class: string;
}
export default {
title: "Example/ImgLoader",
component: ImgLoader,
tags: ["docsPage"],
render: (props: Props) => ({
Component: ImgLoader,
props
}),
argTypes: {}
};
// More on writing stories with args: https://storybook.js.org/docs/7.0/svelte/writing-stories/args
export const Example = {
args: {
class: "w-1/2",
alt: "sample",
src: "https://upload.wikimedia.org/wikipedia/commons/thumb/8/85/%22_Shot_From_The_Sky%22_Army_Show_1945_Oak_Ridge_%2824971013612%29.jpg/2732px-%22_Shot_From_The_Sky%22_Army_Show_1945_Oak_Ridge_%2824971013612%29.jpg"
}
};

View file

@ -1,53 +0,0 @@
<script lang="ts">
import Button from "../button/button.svelte";
import type { ListActionItem } from "../types";
export let title: string;
export let mainCtaTitle: string;
export let mainCtaLink = "/";
export let items: ListActionItem[];
export let onSelectItem = (item: ListActionItem) => console.log(item);
const onSelect = (item: ListActionItem) => {
if (onSelectItem) {
onSelectItem(item);
}
};
</script>
<section class="bg-black">
<header class="w-full border border-gray p-2 text-primary">{title}</header>
<ul class="border border-b-0 border-l-0 border-r-0 border-gray">
{#each items as item}
<li class="flex content-center border border-t-0 border-gray">
<figure class="m-2 w-10 bg-gray">
<img src={item.image_url} alt={item.title} />
</figure>
<div class="flex flex-grow pt-4 leading-10">
<div class="text-sm">{item.title}</div>
<div class="pl-2 text-sm text-gray">{item.sub_title}</div>
</div>
<div class="m-2 w-28 border border-gray">
{#if item.detail_url}
<a href={item.detail_url}>
<Button>{item.action_label}</Button>
</a>
{:else}
<Button onClick={() => onSelect(item)}>{item.action_label}</Button>
{/if}
</div>
</li>
{/each}
</ul>
<footer class="w-full border border-t-0 border-gray text-gray">
<a href={mainCtaLink} class="flex w-full">
<Button>
<div class="flex w-full justify-between p-2">
<button>{mainCtaTitle}</button>
<i class="icon-right-arrow" />
</div>
</Button>
</a>
</footer>
</section>

View file

@ -1,46 +0,0 @@
import MiniPackageCard from "./MiniPackageCard.svelte";
import type { Package } from "../types";
const SamplePkg: Package = {
slug: "mesonbuild_com",
homepage: "https://mesonbuild.com",
name: "mesonbuild.com",
version: "0.63.3",
last_modified: "2022-10-06T15:45:08.000Z",
full_name: "mesonbuild.com",
dl_count: 270745,
thumb_image_name: "mesonbuild_com_option 1.jpg ",
maintainer: "neilm",
desc: "Fast and user friendly build system",
thumb_image_url: "https://tea.xyz/Images/packages/mesonbuild_com.jpg",
installs: 0,
bottles: 23
};
// More on how to set up stories at: https://storybook.js.org/docs/7.0/svelte/writing-stories/introduction
export default {
title: "Example/MiniPackageCard",
component: MiniPackageCard,
tags: ["docsPage"],
render: ({ pkg, link }: { pkg: Package; link: string }) => ({
Component: MiniPackageCard,
props: { pkg, link }
}),
argTypes: {
pkg: {
name: "pkg",
description: "type Package"
},
link: {
name: "link"
}
}
};
// More on writing stories with args: https://storybook.js.org/docs/7.0/svelte/writing-stories/args
export const Example = {
args: {
pkg: SamplePkg,
link: "#"
}
};

View file

@ -1,77 +0,0 @@
<script lang="ts">
import "../app.css";
import type { Package } from "../types";
import ImgLoader from "../img-loader/img-loader.svelte";
export let pkg: Package;
export let ctaLabel: string;
export let link = "";
export let onClickCTA = () => {
console.log("do nothing");
};
</script>
<section class="box-content flex h-24 w-full border border-gray">
<figure class="relative w-24">
<ImgLoader
class="pkg-image object-contain"
src={!pkg.thumb_image_url.includes("https://tea.xyz")
? "/images/default-thumb.jpg"
: pkg.thumb_image_url}
alt={pkg.name}
/>
<div class="absolute top-0 h-8 w-8 bg-accent text-center text-xs text-white">
<span class="leading-8">&#8249;/&#8250;</span>
</div>
</figure>
<footer class="flex-grow px-2 text-white">
<h3 class="text-base uppercase">{pkg.name}</h3>
{#if pkg.maintainer}
<h4 class="text-xs">&#x2022;&nbsp;{pkg.maintainer}</h4>
{/if}
<div>
<p>
<span class="text-xs text-gray"
>V&NonBreakingSpace;{pkg.version}
{pkg?.bottles?.length ? `| ${pkg.bottles.length} bottles` : ""}</span
>
</p>
</div>
{#if link}
<a href={link}>
<button class="h-6 w-full text-xs">{ctaLabel}</button>
</a>
{:else}
<button class="h-6 w-full text-xs" on:click={onClickCTA}>{ctaLabel}</button>
{/if}
</footer>
</section>
<style>
section {
background-color: #1a1a1a;
transition: all 0.3s;
width: 100%;
}
figure {
position: relative;
}
button {
background-color: #1a1a1a;
border: 0.5px solid #ffffff;
color: #fff;
text-decoration: none;
text-transform: uppercase;
min-width: 120px;
transition: 0.1s linear;
}
button:hover {
background-color: #8000ff;
box-shadow: inset 0vw 0vw 0vw 0.223vw #1a1a1a !important;
}
</style>

View file

@ -1,9 +0,0 @@
<script lang="ts">
import Prism from "@magidoc/plugin-svelte-prismjs";
export let text: string;
export let language = "shell";
</script>
<article class="py-1 text-sm font-thin">
<Prism {language} source={text} showLineNumbers showCopyButton />
</article>

View file

@ -1,49 +0,0 @@
<script lang="ts">
import "../app.css";
import { onMount } from "svelte";
import type { Snippet, Tab } from "../types";
import Tabs from "../tabs/tabs.svelte";
import Code from "./code.svelte";
export let snippet: Snippet;
let active = false;
let tabs: Tab[] = [];
onMount(() => {
tabs = snippet.files.map((file) => ({
label: file.name,
component: Code,
props: {
text: file.data,
language: file.language
}
}));
});
</script>
<header class="flex items-center gap-4 px-4">
<button class={active ? "rotate-90" : "hover:rorate-90"} on:click={() => (active = !active)}>
<i class="icon-enter-arrow" />
</button>
<figure class="h-8 w-8 overflow-clip rounded-full bg-gray">
{#if snippet.avatar_url}
<img src={snippet.avatar_url} alt={snippet.user} />
{/if}
</figure>
<article class="flex-grow text-primary">
<h3>{snippet.user}/{snippet.files[0].name}</h3>
<date class="text-xs">{snippet.created_at}</date>
</article>
<p class="text-xs text-primary">{snippet.files.length} file/s</p>
<p class="text-xs text-primary">{snippet.forks.length} forks</p>
<p class="text-xs text-primary">{snippet.comments.length} comments</p>
<p class="text-xs text-primary">{snippet.stars} stars</p>
</header>
{#if active}
<section class="mt-4">
{#if tabs.length}
<Tabs {tabs} />
{/if}
</section>
{/if}

View file

@ -1,13 +0,0 @@
<script lang="ts">
import { snippets } from "./sample";
import PackageSnippet from "./package-snippet.svelte";
</script>
<ul class="bg-black">
{#each snippets as snippet}
<li class="border border-gray p-4">
<PackageSnippet {snippet} />
</li>
{/each}
</ul>
<section />

View file

@ -1,57 +0,0 @@
import type { Snippet } from "../types";
export const snippets: Snippet[] = [
{
snippet_id: "a1",
created_at: new Date(),
user: "xxxavier",
avatar_url: "/images/bored-ape.png",
stars: 123,
files: [
{
name: "sample.js",
language: "javscript",
data: `import name from './name';
console.log('hello world');`
},
{
name: "name.js",
language: "javscript",
data: `export const name = 'onamaiwa';`
}
],
forks: [],
comments: [
{
user: "denise",
comment: "noice!"
}
]
},
{
snippet_id: "a2",
created_at: new Date(),
user: "aaaron",
avatar_url: "/images/bored-ape.png",
stars: 3,
files: [
{
name: "example.py",
language: "python",
data: `import name from './name';
console.log('hello world');`
}
],
forks: [],
comments: [
{
user: "denise",
comment: "noice!"
},
{
user: "denice",
comment: "doesnt work!"
}
]
}
];

View file

@ -1,19 +0,0 @@
import PanelHeader from "./PanelHeader.svelte";
export default {
title: "Example/PanelHeader",
component: PanelHeader,
render: (props) => ({
Component: PanelHeader,
props
})
};
// More on interaction testing: https://storybook.js.org/docs/7.0/svelte/writing-tests/interaction-testing
export const Example = {
args: {
title: "Open-Source News",
ctaLabel: "Read More News >",
ctaLink: "/"
}
};

View file

@ -1,10 +0,0 @@
<script lang="ts">
export let title: string;
export let ctaLabel: string;
export let ctaLink: string;
</script>
<header class="flex items-center justify-between border border-gray bg-black p-4 text-primary">
<span class="uppercase">{title}</span>
<a href={ctaLink} class="text-sm underline">{ctaLabel}</a>
</header>

View file

@ -1,44 +0,0 @@
<script lang="ts">
import "../app.css";
import type { AirtablePost } from "../types";
import ImgLoader from "../img-loader/img-loader.svelte";
export let posts: AirtablePost[] = [];
export let linkTarget = "_blank";
const tagColorDict: { [key: string]: string } = {
ARTICLE: "#FF00FF",
WORKSHOP: "#2675F5"
};
</script>
<ul class="flex flex-col bg-black">
{#each posts as article}
<a href={article.link} target={linkTarget}>
<li class="border border-t-0 border-gray p-4">
<article class="flex border border-gray transition-all hover:bg-gray">
<ImgLoader
style="height: 232px; width: 194px"
class="pkg-image p-2"
src={article.thumb_image_url}
alt={article.title}
/>
<section class="flex-grow p-4">
<ul class="mb-4 flex">
{#each article.tags as tag}
<li
class="rounded-sm px-2 text-xs"
style={`background-color: ${tagColorDict[tag]}`}
>
{tag.toLowerCase()}
</li>
{/each}
</ul>
<h1 class="text-2xl text-primary">{article.title}</h1>
<p class="my-4 text-sm line-clamp-4">{article.short_description}</p>
</section>
</article>
</li>
</a>
{/each}
</ul>

View file

@ -1,12 +0,0 @@
<script lang="ts">
export let width = 0;
</script>
<div class="dark:bg-gray-700 h-2.5 w-full rounded-full bg-gray">
<div
class="h-2.5 rounded-full bg-secondary transition-all"
class:animate-pulse={width < 100 && width > 0}
class:bg-green={width == 100}
style="width: {width}%"
/>
</div>

View file

@ -1,30 +0,0 @@
import ReviewCard from "./ReviewCard.svelte";
// More on how to set up stories at: https://storybook.js.org/docs/7.0/svelte/writing-stories/introduction
export default {
title: "Example/ReviewCard",
component: ReviewCard,
tags: ["docsPage"],
render: ({ review }) => ({
Component: ReviewCard,
props: { review }
}),
argTypes: {
review: {
name: "review",
description: "this is type Review"
}
}
};
// More on writing stories with args: https://storybook.js.org/docs/7.0/svelte/writing-stories/args
export const Example = {
args: {
review: {
title: "installing tea",
comment:
"Lorem ipsum dolor sit amet consectetur adipisicing elit. Voluptas, voluptatum molestiae esse quisquam earum debitis.",
rating: 2
}
}
};

View file

@ -1,35 +0,0 @@
<script lang="ts">
import "../app.css";
import type { Review } from "../types";
export let review: Review;
const getStarType = () => {
let star = "full";
if (review.rating < 3) {
star = "empty";
} else if (review.rating < 4) {
star = "half";
}
return `icon-star-${star}`;
};
const getStarLabel = () => {
let label = "DELIGHTFUL";
if (review.rating < 3) {
label = "NOT DELIGHTFUL";
} else if (review.rating < 4) {
label = "DELIGHTFUL WITH NOTES";
}
return label;
};
</script>
<section class="border border-gray p-4">
<header class=" text-lg text-primary">{review.title}</header>
<div class="mt-2 flex text-xs">
<i class="{getStarType()} text-primary" />
<span class="pl-2 text-gray">{getStarLabel()}</span>
</div>
<p class="mt-2 text-sm">{review.comment}</p>
</section>

Some files were not shown because too many files have changed in this diff Show more