mirror of
https://github.com/ivabus/gui
synced 2025-06-07 15:50:27 +03:00
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:
parent
9fe5a2b825
commit
6ad452331b
252 changed files with 14089 additions and 20380 deletions
|
@ -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/*
|
24
.github/create-correct-release-yaml.js
vendored
24
.github/create-correct-release-yaml.js
vendored
|
@ -3,20 +3,21 @@ 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() {
|
||||||
|
@ -27,12 +28,9 @@ async function main() {
|
||||||
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;
|
||||||
|
|
||||||
|
|
17
.github/notify-slack.js
vendored
17
.github/notify-slack.js
vendored
|
@ -1,23 +1,24 @@
|
||||||
#!/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);
|
||||||
|
|
10
.github/template.json
vendored
10
.github/template.json
vendored
|
@ -18,9 +18,7 @@
|
||||||
"OriginProtocolPolicy": "http-only",
|
"OriginProtocolPolicy": "http-only",
|
||||||
"OriginSslProtocols": {
|
"OriginSslProtocols": {
|
||||||
"Quantity": 1,
|
"Quantity": 1,
|
||||||
"Items": [
|
"Items": ["TLSv1.2"]
|
||||||
"TLSv1.2"
|
|
||||||
]
|
|
||||||
},
|
},
|
||||||
"OriginReadTimeout": 30,
|
"OriginReadTimeout": 30,
|
||||||
"OriginKeepaliveTimeout": 5
|
"OriginKeepaliveTimeout": 5
|
||||||
|
@ -55,10 +53,7 @@
|
||||||
},
|
},
|
||||||
"SmoothStreaming": false,
|
"SmoothStreaming": false,
|
||||||
"AllowedMethods": {
|
"AllowedMethods": {
|
||||||
"Items": [
|
"Items": ["GET", "HEAD"],
|
||||||
"GET",
|
|
||||||
"HEAD"
|
|
||||||
],
|
|
||||||
"Quantity": 2
|
"Quantity": 2
|
||||||
},
|
},
|
||||||
"MinTTL": 0
|
"MinTTL": 0
|
||||||
|
@ -80,4 +75,3 @@
|
||||||
"Quantity": 0
|
"Quantity": 0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
239
.github/workflows/build-sign-notarize.yml
vendored
239
.github/workflows/build-sign-notarize.yml
vendored
|
@ -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
|
|
||||||
|
|
102
.github/workflows/ci.yml
vendored
102
.github/workflows/ci.yml
vendored
|
@ -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:
|
||||||
|
@ -32,17 +32,6 @@ jobs:
|
||||||
run: |
|
run: |
|
||||||
echo "is-fork=$(if [ \"${{ github.event.pull_request.head.repo.full_name }}\" != \"${{ github.repository }}\" ]; then echo true; else echo false; fi)" >> $GITHUB_OUTPUT
|
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
|
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:
|
|
||||||
message-id: preview-comment-${{needs.changes.outputs.preview_folder}}
|
|
||||||
message: |
|
|
||||||
no preview or changes related to UI
|
|
||||||
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:
|
||||||
|
|
1
.github/workflows/cleanup.yml
vendored
1
.github/workflows/cleanup.yml
vendored
|
@ -28,4 +28,3 @@ jobs:
|
||||||
# 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 }}/*"
|
||||||
|
|
||||||
|
|
25
.github/workflows/main.yml
vendored
25
.github/workflows/main.yml
vendored
|
@ -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:
|
||||||
|
@ -131,8 +109,7 @@ jobs:
|
||||||
- name: get version
|
- name: get version
|
||||||
id: get-version
|
id: get-version
|
||||||
run: |
|
run: |
|
||||||
echo "version=$(node -p "require('./modules/desktop/package.json').version")" >> $GITHUB_OUTPUT
|
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
|
||||||
|
|
4
.github/workflows/release.yml
vendored
4
.github/workflows/release.yml
vendored
|
@ -1,7 +1,7 @@
|
||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
tags:
|
tags:
|
||||||
- 'v*.*.*'
|
- "v*.*.*"
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
build_desktop:
|
build_desktop:
|
||||||
|
@ -87,7 +87,6 @@ jobs:
|
||||||
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
|
# update and replace latest release bin in s3
|
||||||
- name: Set tag
|
- name: Set tag
|
||||||
id: tag
|
id: tag
|
||||||
|
@ -151,4 +150,3 @@ jobs:
|
||||||
files: |
|
files: |
|
||||||
dist/${{ steps.app_files.outputs.dmg_arm64 }}
|
dist/${{ steps.app_files.outputs.dmg_arm64 }}
|
||||||
dist/${{ steps.app_files.outputs.dmg_x86 }}
|
dist/${{ steps.app_files.outputs.dmg_x86 }}
|
||||||
|
|
||||||
|
|
4
.gitignore
vendored
4
.gitignore
vendored
|
@ -4,3 +4,7 @@ yarn-error.log
|
||||||
.pnpm-store
|
.pnpm-store
|
||||||
target
|
target
|
||||||
copy.json
|
copy.json
|
||||||
|
electron/dist
|
||||||
|
electrin/config.json
|
||||||
|
dist
|
||||||
|
.env
|
|
@ -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/*
|
|
@ -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" } }]
|
||||||
}
|
}
|
72
README.md
72
README.md
|
@ -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.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# 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,13 +170,10 @@ 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"
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# Dependencies
|
# Dependencies
|
||||||
|
@ -185,9 +181,9 @@ tea gh release create "v$V"
|
||||||
[`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 |
|
||||||
|
|
||||||
|
|
|
@ -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,8 +10,8 @@ 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:
|
||||||
|
|
|
@ -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
|
|
@ -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);
|
Before Width: | Height: | Size: 1 MiB After Width: | Height: | Size: 1 MiB |
3
electron/config.json
Normal file
3
electron/config.json
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
{
|
||||||
|
"PUSHY_APP_ID": "643647948f3b62fb34b29989"
|
||||||
|
}
|
|
@ -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";
|
|
@ -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 = "";
|
|
@ -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;
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
|
@ -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
8
electron/libs/pantry.ts
Normal 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 };
|
||||||
|
}
|
|
@ -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);
|
|
@ -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,
|
dir,
|
||||||
continueDeeper,
|
continueDeeper,
|
||||||
filter
|
filter,
|
||||||
}: {
|
maxDepth
|
||||||
|
}: {
|
||||||
dir: string;
|
dir: string;
|
||||||
continueDeeper?: (name: string) => boolean;
|
continueDeeper?: (name: string, path: string) => boolean;
|
||||||
filter?: (name: 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}`));
|
Before Width: | Height: | Size: 219 KiB After Width: | Height: | Size: 219 KiB |
|
@ -1 +0,0 @@
|
||||||
node-linker=hoisted
|
|
|
@ -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" } }]
|
|
||||||
}
|
|
|
@ -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
|
@ -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: {}
|
|
||||||
}
|
|
||||||
};
|
|
|
@ -1,6 +0,0 @@
|
||||||
<script lang="ts">
|
|
||||||
import "$appcss";
|
|
||||||
import Placeholder from "$components/placeholder/placeholder.svelte";
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<Placeholder label="Badges" />
|
|
|
@ -1,5 +0,0 @@
|
||||||
<script lang="ts">
|
|
||||||
import "$appcss";
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<section class="h-56 border border-gray bg-black" />
|
|
|
@ -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}
|
|
|
@ -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"
|
|
||||||
/>
|
|
|
@ -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>→</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>→</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>→</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>
|
|
|
@ -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>
|
|
|
@ -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}
|
|
|
@ -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}
|
|
|
@ -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);
|
|
||||||
}}
|
|
||||||
/>
|
|
|
@ -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>
|
|
|
@ -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>
|
|
|
@ -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>
|
|
|
@ -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;
|
|
||||||
};
|
|
|
@ -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>
|
|
|
@ -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]
|
|
||||||
};
|
|
|
@ -1,3 +0,0 @@
|
||||||
declare module "electron-is-packaged" {
|
|
||||||
export let isPackaged: boolean;
|
|
||||||
}
|
|
|
@ -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
|
|
|
@ -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
12
modules/ui/.gitignore
vendored
|
@ -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
|
|
|
@ -1 +0,0 @@
|
||||||
engine-strict=true
|
|
|
@ -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
|
|
|
@ -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
|
|
||||||
}
|
|
||||||
};
|
|
|
@ -1,3 +0,0 @@
|
||||||
<script>
|
|
||||||
window.global = window;
|
|
||||||
</script>
|
|
|
@ -1,9 +0,0 @@
|
||||||
export const parameters = {
|
|
||||||
actions: { argTypesRegex: "^on[A-Z].*" },
|
|
||||||
controls: {
|
|
||||||
matchers: {
|
|
||||||
color: /(background|color)$/i,
|
|
||||||
date: /Date$/
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
|
@ -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"
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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;
|
|
|
@ -1,6 +0,0 @@
|
||||||
module.exports = {
|
|
||||||
plugins: {
|
|
||||||
tailwindcss: {},
|
|
||||||
autoprefixer: {}
|
|
||||||
}
|
|
||||||
};
|
|
|
@ -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 = {};
|
|
|
@ -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: "#"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
};
|
|
|
@ -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 = {};
|
|
|
@ -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"]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
};
|
|
|
@ -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 = {};
|
|
|
@ -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");
|
|
||||||
}
|
|
20
modules/ui/src/app.d.ts
vendored
20
modules/ui/src/app.d.ts
vendored
|
@ -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;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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>
|
|
|
@ -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"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
|
@ -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>
|
|
|
@ -1,5 +0,0 @@
|
||||||
<script lang="ts">
|
|
||||||
import Button from "./Button.svelte";
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<Button>Click Me</Button>
|
|
|
@ -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>
|
|
|
@ -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">• {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>
|
|
|
@ -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>
|
|
|
@ -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>
|
|
|
@ -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;
|
|
||||||
}
|
|
|
@ -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>
|
|
|
@ -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"
|
|
||||||
}
|
|
||||||
};
|
|
|
@ -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>
|
|
|
@ -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: "#"
|
|
||||||
}
|
|
||||||
};
|
|
|
@ -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">‹/›</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">• {pkg.maintainer}</h4>
|
|
||||||
{/if}
|
|
||||||
<div>
|
|
||||||
<p>
|
|
||||||
<span class="text-xs text-gray"
|
|
||||||
>V {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>
|
|
|
@ -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>
|
|
|
@ -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}
|
|
|
@ -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 />
|
|
|
@ -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!"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
];
|
|
|
@ -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: "/"
|
|
||||||
}
|
|
||||||
};
|
|
|
@ -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>
|
|
|
@ -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>
|
|
|
@ -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>
|
|
|
@ -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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
|
@ -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
Loading…
Reference in a new issue