mirror of
https://github.com/Eugeny/tabby.git
synced 2025-07-29 21:54:37 +00:00
Compare commits
365 Commits
dependabot
...
commands
Author | SHA1 | Date | |
---|---|---|---|
![]() |
c12b445ccd | ||
![]() |
5d8ff72850 | ||
![]() |
e247ff73b2 | ||
![]() |
ed5ff1113c | ||
![]() |
a5fcb83ad0 | ||
![]() |
da5342b4a7 | ||
![]() |
3c7f1079dd | ||
![]() |
c7e01eab0f | ||
![]() |
ffddc36ee0 | ||
![]() |
b2671826c6 | ||
![]() |
fec5d809b7 | ||
![]() |
cf09d95602 | ||
![]() |
266dfe15a3 | ||
![]() |
868f7ba70e | ||
![]() |
b7f8652f5f | ||
![]() |
1f06800c39 | ||
![]() |
7239193a4b | ||
![]() |
35cb81c854 | ||
![]() |
614c1adf96 | ||
![]() |
eb15fe6aa6 | ||
![]() |
afe716fcf4 | ||
![]() |
2e50c18dba | ||
![]() |
209d3a9c5b | ||
![]() |
efc462ee4e | ||
![]() |
7b4af46bd4 | ||
![]() |
c9339ea76a | ||
![]() |
ac95f550d9 | ||
![]() |
cc3af1aa03 | ||
![]() |
a6ac5a2898 | ||
![]() |
353e5a9550 | ||
![]() |
2507317d6b | ||
![]() |
78a64a9025 | ||
![]() |
1369b5b299 | ||
![]() |
76931e69ad | ||
![]() |
e4ceb3ee6a | ||
![]() |
86196c9f7d | ||
![]() |
62e54cbf6e | ||
![]() |
cd8e414fc0 | ||
![]() |
60be3722a2 | ||
![]() |
4e4ee4fc98 | ||
![]() |
d3b5a53179 | ||
![]() |
2a51ce556f | ||
![]() |
62dc3e04d0 | ||
![]() |
db9d90e9b0 | ||
![]() |
86469334a0 | ||
![]() |
eec294fa2e | ||
![]() |
aac1976baa | ||
![]() |
a4aa07c1f1 | ||
![]() |
2437dc5bdc | ||
![]() |
a8ef5963c3 | ||
![]() |
2dc64ae51b | ||
![]() |
0ba5517a31 | ||
![]() |
9f6263f3d4 | ||
![]() |
f80db81857 | ||
![]() |
3794081cef | ||
![]() |
38c9714c75 | ||
![]() |
3823efc82a | ||
![]() |
977deea2a0 | ||
![]() |
0153bdf490 | ||
![]() |
0b608bdb24 | ||
![]() |
8180530892 | ||
![]() |
0e58bb28f9 | ||
![]() |
7908de9634 | ||
![]() |
2743c332d5 | ||
![]() |
1e8693a47d | ||
![]() |
c97f88fde6 | ||
![]() |
b97d73e912 | ||
![]() |
e16cc34b4e | ||
![]() |
a2b87ea8cb | ||
![]() |
fda98f7434 | ||
![]() |
aae0147d7d | ||
![]() |
c59e9c1d82 | ||
![]() |
b4abe29c51 | ||
![]() |
1e096ede77 | ||
![]() |
2be079a51b | ||
![]() |
be0d129c28 | ||
![]() |
191807c09a | ||
![]() |
f4af21bf71 | ||
![]() |
845d6c6373 | ||
![]() |
066a1a6bac | ||
![]() |
b4777fd4a8 | ||
![]() |
3d83bc6e4e | ||
![]() |
102c0f5ce7 | ||
![]() |
345e90c1f6 | ||
![]() |
787936babd | ||
![]() |
6c1b0c3ae7 | ||
![]() |
efe1772e8d | ||
![]() |
d1311ba53f | ||
![]() |
5a6911f928 | ||
![]() |
2254436365 | ||
![]() |
2c70c0fff5 | ||
![]() |
ff450527ab | ||
![]() |
3ba6ce889e | ||
![]() |
4ca425c2a8 | ||
![]() |
70fb882e4d | ||
![]() |
86664c4eba | ||
![]() |
72149d2cb0 | ||
![]() |
04a1b0fb44 | ||
![]() |
f8614dffbc | ||
![]() |
37ccba5c90 | ||
![]() |
98719aafdc | ||
![]() |
860ee3eaa9 | ||
![]() |
454391d31e | ||
![]() |
4c0231cd67 | ||
![]() |
31b063a964 | ||
![]() |
26a2a0c44e | ||
![]() |
f0a84d4d76 | ||
![]() |
ae6c1308a8 | ||
![]() |
c3a9f35953 | ||
![]() |
dc6c0357c2 | ||
![]() |
f706d7d6cb | ||
![]() |
56d5d34bfd | ||
![]() |
40246a409d | ||
![]() |
0f6561e859 | ||
![]() |
72c0692843 | ||
![]() |
26d6d14703 | ||
![]() |
6a458d8b9b | ||
![]() |
3e9ee5b235 | ||
![]() |
4740824dd1 | ||
![]() |
51d48f07d7 | ||
![]() |
a8d7fa33b5 | ||
![]() |
34fee58a7d | ||
![]() |
f276c50326 | ||
![]() |
ca1241ee52 | ||
![]() |
000bdde0cd | ||
![]() |
34daa4c412 | ||
![]() |
39596588bb | ||
![]() |
1228b1a29a | ||
![]() |
f0636623ae | ||
![]() |
4057e0cf59 | ||
![]() |
0e8164fe4c | ||
![]() |
2b8fed164f | ||
![]() |
e68bd6c746 | ||
![]() |
f3196ac045 | ||
![]() |
57f20eca4f | ||
![]() |
5d1a35a285 | ||
![]() |
642db6a14a | ||
![]() |
e739883840 | ||
![]() |
bb27314696 | ||
![]() |
adeb6031dd | ||
![]() |
34aeb797f3 | ||
![]() |
7d5128a8ce | ||
![]() |
83c0892546 | ||
![]() |
9e705fb273 | ||
![]() |
c2b349de8f | ||
![]() |
3176a7744b | ||
![]() |
98dd4a0017 | ||
![]() |
cfce2687bd | ||
![]() |
2af7ad85f8 | ||
![]() |
8616bdbea3 | ||
![]() |
0505e5615d | ||
![]() |
8c2820056a | ||
![]() |
b1108a7b32 | ||
![]() |
bfe3430e9a | ||
![]() |
612d6ef089 | ||
![]() |
bd31db9c56 | ||
![]() |
d1a837b11d | ||
![]() |
d70be3abf9 | ||
![]() |
422df52fea | ||
![]() |
140d7e9f96 | ||
![]() |
9a3bb1ae4b | ||
![]() |
169adedc48 | ||
![]() |
90ccd969f2 | ||
![]() |
6ebfccda28 | ||
![]() |
27bf7c4ad6 | ||
![]() |
651861cd4a | ||
![]() |
3ce2bb68c6 | ||
![]() |
e4169a54aa | ||
![]() |
0d0bde82a0 | ||
![]() |
04b53ab366 | ||
![]() |
7cde5c0807 | ||
![]() |
cb71c79ecc | ||
![]() |
6843b87493 | ||
![]() |
a17da4b4af | ||
![]() |
5d5c545b4e | ||
![]() |
f7299ee321 | ||
![]() |
d1e97bf737 | ||
![]() |
f9f1a809a1 | ||
![]() |
d881da94de | ||
![]() |
3aaa68fe09 | ||
![]() |
ea84612788 | ||
![]() |
16fcf3d7f8 | ||
![]() |
4a02abdcc3 | ||
![]() |
98a5bfd338 | ||
![]() |
2dbc43f828 | ||
![]() |
0c93010da7 | ||
![]() |
0329e7a8b6 | ||
![]() |
26ac6b0aa3 | ||
![]() |
8bc2375aab | ||
![]() |
dc9a7d8fac | ||
![]() |
0becf8cc76 | ||
![]() |
6042a5290c | ||
![]() |
344244297c | ||
![]() |
75eedafbc9 | ||
![]() |
1b0ce6d684 | ||
![]() |
4684b0d6f5 | ||
![]() |
eddb50b529 | ||
![]() |
96eee51590 | ||
![]() |
f963167b70 | ||
![]() |
0128013308 | ||
![]() |
5e5c80832d | ||
![]() |
06859de2de | ||
![]() |
49f9a10372 | ||
![]() |
85d988f6b3 | ||
![]() |
7bc549b555 | ||
![]() |
d6bdecb9c4 | ||
![]() |
7687972e65 | ||
![]() |
34786b1459 | ||
![]() |
634d88d220 | ||
![]() |
ad3b03cb83 | ||
![]() |
d354520910 | ||
![]() |
a9c63b5305 | ||
![]() |
d21282501f | ||
![]() |
d2752382aa | ||
![]() |
5eeaef954c | ||
![]() |
ef6b8a4eaa | ||
![]() |
7be6fca493 | ||
![]() |
21e38c8453 | ||
![]() |
2262d59866 | ||
![]() |
9b0fbcfc56 | ||
![]() |
8adb9a6806 | ||
![]() |
164d34c543 | ||
![]() |
f369b140c6 | ||
![]() |
c108476262 | ||
![]() |
695c5ba670 | ||
![]() |
e23765045c | ||
![]() |
d6705c20ad | ||
![]() |
79cabb6eda | ||
![]() |
3024e633a9 | ||
![]() |
743ea04d0b | ||
![]() |
6d0a84c94e | ||
![]() |
0ef24ddf1d | ||
![]() |
935c981d2b | ||
![]() |
951c69b31a | ||
![]() |
30936b739e | ||
![]() |
44c449bd4c | ||
![]() |
2cfc64911b | ||
![]() |
240c542665 | ||
![]() |
555d3c8478 | ||
![]() |
aafe510803 | ||
![]() |
217ab641b5 | ||
![]() |
7572f3c26f | ||
![]() |
326d8b3fb1 | ||
![]() |
9b4f1a3a0d | ||
![]() |
0d275595cf | ||
![]() |
7860c73e49 | ||
![]() |
fa9dea0f64 | ||
![]() |
6813fd54cd | ||
![]() |
1c06a510bd | ||
![]() |
a0804cc564 | ||
![]() |
b751e10082 | ||
![]() |
48d4b8e8f8 | ||
![]() |
ef040ee342 | ||
![]() |
8e9156e250 | ||
![]() |
1903ec5995 | ||
![]() |
21df033012 | ||
![]() |
4d146941f4 | ||
![]() |
5ba6bfbd7d | ||
![]() |
f0e2482dd6 | ||
![]() |
5763919d85 | ||
![]() |
c1e03ed532 | ||
![]() |
8a85fcac21 | ||
![]() |
ee4487a517 | ||
![]() |
272b9ee5dc | ||
![]() |
d57757c66c | ||
![]() |
4dedbbc25a | ||
![]() |
0101ffddb6 | ||
![]() |
726ad23a32 | ||
![]() |
4fe2a45664 | ||
![]() |
6f8d687529 | ||
![]() |
9d05fbeb90 | ||
![]() |
299be86498 | ||
![]() |
bd337a4197 | ||
![]() |
a1cb0ff223 | ||
![]() |
ae2f3f162e | ||
![]() |
91cb9e5c63 | ||
![]() |
e2cc9b98ee | ||
![]() |
b8f2204d4f | ||
![]() |
35bca545f8 | ||
![]() |
8b89db41d2 | ||
![]() |
d36b2b21c9 | ||
![]() |
a585cf306c | ||
![]() |
2d8a0aff61 | ||
![]() |
db916c922a | ||
![]() |
dfc438258d | ||
![]() |
6a714a746f | ||
![]() |
54284741e0 | ||
![]() |
e4b545f231 | ||
![]() |
c27566a561 | ||
![]() |
43121c33f2 | ||
![]() |
4b34f76997 | ||
![]() |
24db1cb99a | ||
![]() |
147d22f386 | ||
![]() |
c04b93c56c | ||
![]() |
ddab79d3ac | ||
![]() |
c501f541c8 | ||
![]() |
8af3c95212 | ||
![]() |
2fa612fe2c | ||
![]() |
725bc225f1 | ||
![]() |
8451848ba6 | ||
![]() |
186a4afa1c | ||
![]() |
1d1b149ea8 | ||
![]() |
b217aaf03b | ||
![]() |
c7471f737f | ||
![]() |
124d600bfd | ||
![]() |
a3f2405092 | ||
![]() |
a92f8956d4 | ||
![]() |
22fb2dbda2 | ||
![]() |
303eab2f0e | ||
![]() |
8a12e7c6d1 | ||
![]() |
821dcbff69 | ||
![]() |
44d8c3f04b | ||
![]() |
af515e01cf | ||
![]() |
aba773b546 | ||
![]() |
9ac5286017 | ||
![]() |
555c7f7b20 | ||
![]() |
3857beb46b | ||
![]() |
fcac52a844 | ||
![]() |
4736b11c62 | ||
![]() |
a128a647d9 | ||
![]() |
9638be5349 | ||
![]() |
9c863762c3 | ||
![]() |
539c213ef6 | ||
![]() |
d2bdb55c6d | ||
![]() |
4edc0be280 | ||
![]() |
f10b8c0f35 | ||
![]() |
e38b826fd6 | ||
![]() |
2f1c388a8b | ||
![]() |
e7f7d9b024 | ||
![]() |
47a6e81998 | ||
![]() |
eea3ab9c74 | ||
![]() |
0313e872fd | ||
![]() |
84422d4453 | ||
![]() |
32696cc047 | ||
![]() |
78485617e9 | ||
![]() |
56f6b88ac2 | ||
![]() |
50fac29c5e | ||
![]() |
c13effeadc | ||
![]() |
f0f0bbedf9 | ||
![]() |
897d6167a9 | ||
![]() |
a63011ca15 | ||
![]() |
eae2095787 | ||
![]() |
3efe6ce4cd | ||
![]() |
4966397fca | ||
![]() |
57da067727 | ||
![]() |
fa50c7d9fa | ||
![]() |
9a82c4c5c0 | ||
![]() |
a4136bec6e | ||
![]() |
82a262026f | ||
![]() |
6709217a86 | ||
![]() |
4bbf86a7a7 | ||
![]() |
d98fbe8b44 | ||
![]() |
3d9b15a82d | ||
![]() |
77b74ad659 | ||
![]() |
8de26cfeb8 | ||
![]() |
87a893480c | ||
![]() |
d6d6ec39c8 | ||
![]() |
1579356d54 | ||
![]() |
60a63d9c65 | ||
![]() |
5e673106e9 | ||
![]() |
27c8b920ea | ||
![]() |
bc8ac12aef | ||
![]() |
7f2340e701 | ||
![]() |
b0350b6a35 | ||
![]() |
cea5cc73ff |
@@ -635,10 +635,10 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "X-0x01",
|
||||
"name": "X-0x01",
|
||||
"login": "0x973",
|
||||
"name": "0x973",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/19320096?v=4",
|
||||
"profile": "http://pingbase.cn",
|
||||
"profile": "https://github.com/0x973",
|
||||
"contributions": [
|
||||
"code"
|
||||
]
|
||||
@@ -1184,6 +1184,105 @@
|
||||
"contributions": [
|
||||
"code"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "qyecst",
|
||||
"name": "qyecst",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/13901864?v=4",
|
||||
"profile": "https://github.com/qyecst",
|
||||
"contributions": [
|
||||
"code"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "DehanLUO",
|
||||
"name": "Han",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/53093688?v=4",
|
||||
"profile": "https://github.com/DehanLUO",
|
||||
"contributions": [
|
||||
"code"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "wljince007",
|
||||
"name": "wljince007",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/88243938?v=4",
|
||||
"profile": "https://github.com/wljince007",
|
||||
"contributions": [
|
||||
"code"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "FeroTheFox",
|
||||
"name": "fero",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/52982404?v=4",
|
||||
"profile": "https://github.com/FeroTheFox",
|
||||
"contributions": [
|
||||
"code"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "siebsie23",
|
||||
"name": "Sibren",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/25083973?v=4",
|
||||
"profile": "https://siebsie23.nl/",
|
||||
"contributions": [
|
||||
"code"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "nwalser",
|
||||
"name": "Nathaniel Walser",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/33339996?v=4",
|
||||
"profile": "https://www.nathaniel-walser.com",
|
||||
"contributions": [
|
||||
"code"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "aaronhuggins",
|
||||
"name": "Aaron Huggins",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/16567111?v=4",
|
||||
"profile": "https://github.com/aaronhuggins",
|
||||
"contributions": [
|
||||
"design"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "zKXDEX",
|
||||
"name": "KDex",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/66271780?v=4",
|
||||
"profile": "https://zkxdex.github.io/",
|
||||
"contributions": [
|
||||
"code"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "kimbob13",
|
||||
"name": "ChangHwan Kim",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/26755098?v=4",
|
||||
"profile": "https://github.com/kimbob13",
|
||||
"contributions": [
|
||||
"code"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "ashneilson",
|
||||
"name": "Ash Neilson",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/35913512?v=4",
|
||||
"profile": "https://github.com/ashneilson",
|
||||
"contributions": [
|
||||
"code"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "cfs4819",
|
||||
"name": "Chen Fansong",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/53071761?v=4",
|
||||
"profile": "https://github.com/cfs4819",
|
||||
"contributions": [
|
||||
"code"
|
||||
]
|
||||
}
|
||||
],
|
||||
"contributorsPerLine": 7,
|
||||
@@ -1192,5 +1291,6 @@
|
||||
"repoType": "github",
|
||||
"repoHost": "https://github.com",
|
||||
"commitConvention": "none",
|
||||
"skipCi": true
|
||||
"skipCi": true,
|
||||
"commitType": "docs"
|
||||
}
|
||||
|
@@ -1,7 +1,13 @@
|
||||
settings:
|
||||
import/parsers:
|
||||
'@typescript-eslint/parser': ['.ts']
|
||||
import/resolver:
|
||||
typescript: true
|
||||
typescript:
|
||||
project:
|
||||
- tsconfig.json
|
||||
- tabby-*/tsconfig.json
|
||||
node: true
|
||||
|
||||
env:
|
||||
browser: true
|
||||
es6: true
|
||||
@@ -28,7 +34,7 @@ overrides:
|
||||
- plugin:import/typescript
|
||||
plugins:
|
||||
- '@typescript-eslint'
|
||||
- 'import'
|
||||
- import
|
||||
rules:
|
||||
'@typescript-eslint/semi':
|
||||
- error
|
||||
@@ -130,6 +136,7 @@ overrides:
|
||||
'@typescript-eslint/naming-convention': off
|
||||
'@typescript-eslint/lines-between-class-members':
|
||||
- error
|
||||
- always
|
||||
- exceptAfterSingleLine: true
|
||||
'@typescript-eslint/dot-notation': off
|
||||
'@typescript-eslint/no-implicit-any-catch': off
|
||||
@@ -152,3 +159,6 @@ overrides:
|
||||
'@typescript-eslint/consistent-generic-constructors': off
|
||||
'keyword-spacing': off
|
||||
'@typescript-eslint/keyword-spacing': off
|
||||
'@typescript-eslint/class-methods-use-this': off
|
||||
'@typescript-eslint/lines-around-comment': off
|
||||
'@typescript-eslint/no-redundant-type-constituents': off # broken
|
||||
|
220
.github/workflows/build.yml
vendored
220
.github/workflows/build.yml
vendored
@@ -2,7 +2,7 @@ name: Package-Build
|
||||
on: [push, pull_request]
|
||||
jobs:
|
||||
Lint:
|
||||
runs-on: macos-11
|
||||
runs-on: ubuntu-20.04
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
@@ -11,7 +11,7 @@ jobs:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Installing Node
|
||||
uses: actions/setup-node@v3.6.0
|
||||
uses: actions/setup-node@v3.7.0
|
||||
with:
|
||||
node-version: 16
|
||||
|
||||
@@ -31,7 +31,7 @@ jobs:
|
||||
run: yarn run lint
|
||||
|
||||
macOS-Build:
|
||||
runs-on: macos-11
|
||||
runs-on: macos-12
|
||||
needs: Lint
|
||||
strategy:
|
||||
matrix:
|
||||
@@ -47,12 +47,14 @@ jobs:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Installing Node
|
||||
uses: actions/setup-node@v3.6.0
|
||||
uses: actions/setup-node@v3.7.0
|
||||
with:
|
||||
node-version: 16
|
||||
|
||||
- name: Install deps
|
||||
run: |
|
||||
sudo -H pip3 install setuptools
|
||||
npm config set python python3
|
||||
sudo npm i -g yarn@1.22.1
|
||||
yarn --network-timeout 1000000
|
||||
env:
|
||||
@@ -86,6 +88,7 @@ jobs:
|
||||
KEYGEN_TOKEN: ${{ secrets.KEYGEN_TOKEN }}
|
||||
CSC_LINK: ${{ secrets.CSC_LINK }}
|
||||
CSC_KEY_PASSWORD: ${{ secrets.CSC_KEY_PASSWORD }}
|
||||
APPLE_TEAM_ID: ${{ secrets.APPLE_TEAM_ID }}
|
||||
APPSTORE_USERNAME: ${{ secrets.APPSTORE_USERNAME }}
|
||||
APPSTORE_PASSWORD: ${{ secrets.APPSTORE_PASSWORD }}
|
||||
USE_HARD_LINKS: false
|
||||
@@ -109,16 +112,16 @@ jobs:
|
||||
|
||||
- name: Package artifacts
|
||||
run: |
|
||||
mkdir artifact-pkg
|
||||
mv dist/*.pkg artifact-pkg/
|
||||
mkdir artifact-dmg
|
||||
mv dist/*.dmg artifact-dmg/
|
||||
mkdir artifact-zip
|
||||
mv dist/*.zip artifact-zip/
|
||||
|
||||
- uses: actions/upload-artifact@master
|
||||
name: Upload PKG
|
||||
name: Upload DMG
|
||||
with:
|
||||
name: macOS .pkg (${{matrix.arch}})
|
||||
path: artifact-pkg
|
||||
name: macOS .dmg (${{matrix.arch}})
|
||||
path: artifact-dmg
|
||||
|
||||
- uses: actions/upload-artifact@master
|
||||
name: Upload ZIP
|
||||
@@ -131,7 +134,21 @@ jobs:
|
||||
needs: Lint
|
||||
strategy:
|
||||
matrix:
|
||||
build-arch: [ x64, arm64, armv7l ]
|
||||
include:
|
||||
- build-arch: x64
|
||||
arch: amd64
|
||||
- build-arch: arm64
|
||||
arch: arm64
|
||||
triplet: aarch64-linux-gnu-
|
||||
- build-arch: arm
|
||||
arch: armhf
|
||||
triplet: arm-linux-gnueabihf-
|
||||
env:
|
||||
CC: ${{matrix.triplet}}gcc
|
||||
CXX: ${{matrix.triplet}}g++
|
||||
ARCH: ${{matrix.build-arch}}
|
||||
npm_config_arch: ${{matrix.build-arch}}
|
||||
npm_config_target_arch: ${{matrix.build-arch}}
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
@@ -139,35 +156,66 @@ jobs:
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Set up multiarch/qemu-user-static
|
||||
run: docker run --rm --privileged multiarch/qemu-user-static:register --reset
|
||||
if: matrix.build-arch != 'x64'
|
||||
|
||||
- name: Install Node (x64)
|
||||
uses: actions/setup-node@v3.6.0
|
||||
- name: Install Node
|
||||
uses: actions/setup-node@v3.7.0
|
||||
with:
|
||||
node-version: 16
|
||||
if: matrix.build-arch == 'x64'
|
||||
node-version: 18
|
||||
|
||||
- name: Install deps (x64)
|
||||
- name: Install deps (amd64)
|
||||
run: |
|
||||
sudo apt-get update
|
||||
sudo apt-get install libarchive-tools zsh
|
||||
sudo apt-get install libarchive-tools zsh python3-distutils
|
||||
|
||||
- name: Install npm_modules (amd64)
|
||||
run: |
|
||||
npm i -g yarn
|
||||
yarn --network-timeout 1000000
|
||||
if: matrix.build-arch == 'x64'
|
||||
|
||||
- name: Webpack (x64)
|
||||
run: yarn run build
|
||||
if: matrix.build-arch == 'x64'
|
||||
- name: Setup Crossbuild (${{matrix.arch}})
|
||||
run: |
|
||||
sudo apt-get update -y && sudo apt-get install schroot sbuild debootstrap -y
|
||||
sudo debootstrap --include=git,curl,gnupg,ca-certificates,crossbuild-essential-${{matrix.arch}},python-dev,python3-dev,libarchive-tools,cmake --variant=buildd --exclude=snapd --components=main,restricted,universe,multiverse --extractor=dpkg-deb bionic /build-chroot/
|
||||
echo 'deb [arch=amd64,i386] http://archive.ubuntu.com/ubuntu bionic main restricted universe multiverse' | sudo tee /build-chroot/etc/apt/sources.list >/dev/null
|
||||
echo 'deb [arch=arm64,armhf] http://ports.ubuntu.com/ubuntu-ports bionic main restricted universe multiverse' | sudo tee -a /build-chroot/etc/apt/sources.list >/dev/null
|
||||
curl -s https://deb.nodesource.com/gpgkey/nodesource.gpg.key | gpg --dearmor | sudo tee /build-chroot/etc/apt/trusted.gpg.d/nodesource.gpg >/dev/null
|
||||
echo 'deb http://deb.nodesource.com/node_16.x bionic main' | sudo tee /build-chroot/etc/apt/sources.list.d/nodesource.list >/dev/null
|
||||
echo "[build-chroot]
|
||||
description=Ubuntu 18.04 Build chroot
|
||||
type=directory
|
||||
directory=/build-chroot
|
||||
root-groups=root,sudo
|
||||
profile=buildd
|
||||
personality=linux
|
||||
union-type=overlay" | sudo tee /etc/schroot/chroot.d/build-chroot.pref >/dev/null
|
||||
echo "/home /home none rw,bind 0 0" | sudo tee -a /etc/schroot/buildd/fstab >/dev/null
|
||||
|
||||
- name: Prepackage plugins (x64)
|
||||
if: matrix.build-arch != 'x64'
|
||||
|
||||
- name: Install node_modules & CrossBuild native modules for ${{matrix.arch}}
|
||||
run: |
|
||||
sudo schroot -c build-chroot -u root -- bash -c "apt-get update -y
|
||||
dpkg --add-architecture ${{matrix.arch}}
|
||||
apt-get install -y nodejs libfontconfig-dev:${{matrix.arch}} libsecret-1-dev:${{matrix.arch}} libnss3:${{matrix.arch}} libatk1.0-0:${{matrix.arch}} libatk-bridge2.0-0:${{matrix.arch}} libgdk-pixbuf2.0-0:${{matrix.arch}} libgtk-3-0:${{matrix.arch}} libgbm1:${{matrix.arch}}
|
||||
export CC=${{matrix.triplet}}gcc CXX=${{matrix.triplet}}g++ LD=${{matrix.triplet}}ld
|
||||
if [[ ${{matrix.arch}} == 'arm64' ]]; then
|
||||
export PKG_CONFIG_PATH=$PKG_CONFIG_PATH:/usr/lib/aarch64-linux-gnu/pkgconfig/
|
||||
elif [[ ${{matrix.arch}} == 'armhf' ]]; then
|
||||
export PKG_CONFIG_PATH=$PKG_CONFIG_PATH:/usr/lib/arm-linux-gnueabihf/pkgconfig/
|
||||
fi
|
||||
export ARCH=${{matrix.build-arch}} npm_config_arch=${{matrix.build-arch}} npm_config_target_arch=${{matrix.build-arch}}
|
||||
npm i -g yarn
|
||||
yarn --network-timeout 1000000 --arch=${{matrix.build-arch}} --target_arch=${{matrix.build-arch}}"
|
||||
if: matrix.build-arch != 'x64'
|
||||
|
||||
- name: Webpack (${{matrix.arch}})
|
||||
run: yarn run build --arch=${{matrix.build-arch}} --target_arch=${{matrix.build-arch}}
|
||||
|
||||
- name: Prepackage plugins (${{matrix.arch}})
|
||||
run: scripts/prepackage-plugins.mjs
|
||||
if: ${{matrix.build-arch == 'x64'}}
|
||||
|
||||
- name: Build packages (x64)
|
||||
- name: Build packages (${{matrix.arch}})
|
||||
run: scripts/build-linux.mjs
|
||||
if: ${{matrix.build-arch == 'x64'}}
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
KEYGEN_TOKEN: ${{ secrets.KEYGEN_TOKEN }}
|
||||
@@ -178,54 +226,54 @@ jobs:
|
||||
run: zsh -c 'tar czf tabby-web.tar.gz (tabby-*|web)/dist'
|
||||
if: matrix.build-arch == 'x64'
|
||||
|
||||
- name: Install deps and Build (arm64)
|
||||
uses: docker://multiarch/ubuntu-core:arm64-bionic
|
||||
with:
|
||||
args: >
|
||||
bash -c
|
||||
"apt update && apt install curl lsb-release gnupg -y &&
|
||||
curl -fsSL https://deb.nodesource.com/setup_16.x | bash - &&
|
||||
apt install make build-essential git ruby libarchive-tools nodejs rpm libsecret-1-dev libfontconfig1-dev -y &&
|
||||
git config --global --add safe.directory /github/workspace &&
|
||||
gem install public_suffix -v 4.0.7 &&
|
||||
gem install fpm --no-document &&
|
||||
npm i -g yarn &&
|
||||
cd /github/workspace &&
|
||||
yarn --network-timeout 1000000 &&
|
||||
yarn run build &&
|
||||
scripts/prepackage-plugins.mjs &&
|
||||
USE_SYSTEM_FPM=true scripts/build-linux.mjs"
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
KEYGEN_TOKEN: ${{ secrets.KEYGEN_TOKEN }}
|
||||
USE_HARD_LINKS: false
|
||||
if: matrix.build-arch == 'arm64' && github.repository == 'Eugeny/tabby' && startsWith(github.ref, 'refs/tags')
|
||||
# - name: Install deps and Build (arm64)
|
||||
# uses: docker://multiarch/ubuntu-core:arm64-bionic
|
||||
# with:
|
||||
# args: >
|
||||
# bash -c
|
||||
# "apt update && apt install curl lsb-release gnupg -y &&
|
||||
# curl -fsSL https://deb.nodesource.com/setup_16.x | bash - &&
|
||||
# apt install make build-essential git ruby libarchive-tools nodejs rpm libsecret-1-dev libfontconfig1-dev -y &&
|
||||
# git config --global --add safe.directory /github/workspace &&
|
||||
# gem install public_suffix -v 4.0.7 &&
|
||||
# gem install fpm --no-document &&
|
||||
# npm i -g yarn &&
|
||||
# cd /github/workspace &&
|
||||
# yarn --network-timeout 1000000 &&
|
||||
# yarn run build &&
|
||||
# scripts/prepackage-plugins.mjs &&
|
||||
# USE_SYSTEM_FPM=true scripts/build-linux.mjs"
|
||||
# env:
|
||||
# GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
# KEYGEN_TOKEN: ${{ secrets.KEYGEN_TOKEN }}
|
||||
# USE_HARD_LINKS: false
|
||||
# if: matrix.build-arch == 'arm64' && github.repository == 'Eugeny/tabby' && startsWith(github.ref, 'refs/tags')
|
||||
|
||||
- name: Install deps and Build (armv7l)
|
||||
uses: docker://multiarch/ubuntu-core:armhf-bionic
|
||||
with:
|
||||
args: >
|
||||
bash -c
|
||||
"apt update && apt install curl lsb-release gnupg -y &&
|
||||
curl -fsSL https://deb.nodesource.com/setup_16.x | bash - &&
|
||||
apt install make build-essential git ruby libarchive-tools nodejs rpm libsecret-1-dev libfontconfig1-dev -y &&
|
||||
git config --global --add safe.directory /github/workspace &&
|
||||
gem install public_suffix -v 4.0.7 &&
|
||||
gem install fpm --no-document &&
|
||||
npm i -g yarn &&
|
||||
cd /github/workspace &&
|
||||
sed -i '/ \"electron\":/c\ \"electron\": \"17.0.0\",' package.json &&
|
||||
yarn --network-timeout 1000000 &&
|
||||
yarn run build &&
|
||||
scripts/prepackage-plugins.mjs &&
|
||||
USE_SYSTEM_FPM=true scripts/build-linux.mjs"
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
KEYGEN_TOKEN: ${{ secrets.KEYGEN_TOKEN }}
|
||||
USE_HARD_LINKS: false
|
||||
if: matrix.build-arch == 'armv7l' && github.repository == 'Eugeny/tabby' && startsWith(github.ref, 'refs/tags')
|
||||
# - name: Install deps and Build (armv7l)
|
||||
# uses: docker://multiarch/ubuntu-core:armhf-bionic
|
||||
# with:
|
||||
# args: >
|
||||
# bash -c
|
||||
# "apt update && apt install curl lsb-release gnupg -y &&
|
||||
# curl -fsSL https://deb.nodesource.com/setup_16.x | bash - &&
|
||||
# apt install make build-essential git ruby libarchive-tools nodejs rpm libsecret-1-dev libfontconfig1-dev -y &&
|
||||
# git config --global --add safe.directory /github/workspace &&
|
||||
# gem install public_suffix -v 4.0.7 &&
|
||||
# gem install fpm --no-document &&
|
||||
# npm i -g yarn &&
|
||||
# cd /github/workspace &&
|
||||
# sed -i '/ \"electron\":/c\ \"electron\": \"17.0.0\",' package.json &&
|
||||
# yarn --network-timeout 1000000 &&
|
||||
# yarn run build &&
|
||||
# scripts/prepackage-plugins.mjs &&
|
||||
# USE_SYSTEM_FPM=true scripts/build-linux.mjs"
|
||||
# env:
|
||||
# GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
# KEYGEN_TOKEN: ${{ secrets.KEYGEN_TOKEN }}
|
||||
# USE_HARD_LINKS: false
|
||||
# if: matrix.build-arch == 'arm' && github.repository == 'Eugeny/tabby' && startsWith(github.ref, 'refs/tags')
|
||||
|
||||
- name: Upload symbols
|
||||
- name: Upload symbols (amd64 only)
|
||||
run: |
|
||||
sudo npm install -g @sentry/cli --unsafe-perm
|
||||
./scripts/sentry-upload.mjs
|
||||
@@ -245,31 +293,37 @@ jobs:
|
||||
dir: 'dist'
|
||||
|
||||
- uses: actions/upload-artifact@master
|
||||
name: Upload DEB
|
||||
name: Upload AppImage (${{matrix.arch}})
|
||||
with:
|
||||
name: Linux DEB (${{matrix.build-arch}})
|
||||
name: Linux AppImage (${{matrix.arch}})
|
||||
path: dist/*.AppImage
|
||||
|
||||
- uses: actions/upload-artifact@master
|
||||
name: Upload DEB (${{matrix.arch}})
|
||||
with:
|
||||
name: Linux DEB (${{matrix.arch}})
|
||||
path: dist/*.deb
|
||||
|
||||
- uses: actions/upload-artifact@master
|
||||
name: Upload RPM
|
||||
name: Upload RPM (${{matrix.arch}})
|
||||
with:
|
||||
name: Linux RPM (${{matrix.build-arch}})
|
||||
name: Linux RPM (${{matrix.arch}})
|
||||
path: dist/*.rpm
|
||||
|
||||
- uses: actions/upload-artifact@master
|
||||
name: Upload Pacman Package
|
||||
name: Upload Pacman Package (${{matrix.arch}})
|
||||
with:
|
||||
name: Linux Pacman (${{matrix.build-arch}})
|
||||
name: Linux Pacman (${{matrix.arch}})
|
||||
path: dist/*.pacman
|
||||
|
||||
- uses: actions/upload-artifact@master
|
||||
name: Upload Linux tarball
|
||||
name: Upload Linux tarball (${{matrix.arch}})
|
||||
with:
|
||||
name: Linux tarball (${{matrix.build-arch}})
|
||||
name: Linux tarball (${{matrix.arch}})
|
||||
path: dist/*.tar.gz
|
||||
|
||||
- uses: actions/upload-artifact@master
|
||||
name: Upload web tarball
|
||||
name: Upload web tarball (amd64 only)
|
||||
with:
|
||||
name: Web tarball
|
||||
path: tabby-web.tar.gz
|
||||
@@ -293,7 +347,7 @@ jobs:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Installing Node
|
||||
uses: actions/setup-node@v3.6.0
|
||||
uses: actions/setup-node@v3.7.0
|
||||
with:
|
||||
node-version: 16
|
||||
|
||||
|
2
.github/workflows/docs.yml
vendored
2
.github/workflows/docs.yml
vendored
@@ -12,7 +12,7 @@ jobs:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Installing Node
|
||||
uses: actions/setup-node@v3.6.0
|
||||
uses: actions/setup-node@v3.7.0
|
||||
with:
|
||||
node-version: 16
|
||||
|
||||
|
15
.github/workflows/issue-translator.yml
vendored
15
.github/workflows/issue-translator.yml
vendored
@@ -1,15 +0,0 @@
|
||||
name: 'issue-translator'
|
||||
on:
|
||||
issue_comment:
|
||||
types: [created]
|
||||
issues:
|
||||
types: [opened]
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: tomsun28/issues-translate-action@v2.7
|
||||
with:
|
||||
IS_MODIFY_TITLE: true
|
||||
CUSTOM_BOT_NOTE: The translator bot has detected that this issue body's language is not English, and has translated it automatically.
|
@@ -17,8 +17,6 @@ First, from within the `tabby` directory install the dependencies via yarn:
|
||||
yarn
|
||||
```
|
||||
|
||||
**Note: For compiling for Linux armv7l, you need to downgrade electron to 17.0.0 in package.json present in root directory of tabby source**
|
||||
|
||||
```
|
||||
# Linux (Debian/Ubuntu here as an example)
|
||||
sudo apt install libfontconfig-dev libsecret-1-dev libarchive-tools libnss3 libatk1.0-0 libatk-bridge2.0-0 libgdk-pixbuf2.0-0 libgtk-3-0 libgbm1 cmake
|
||||
|
@@ -20,7 +20,7 @@
|
||||
|
||||
<br/>
|
||||
<p align="center">
|
||||
Diese README ist auch verfügbar in: <a href="./README.md">:gb: English</a> · <a href="./README.es-ES.md">:es: Spanish</a> · <a href="./README.ru-RU.md">:ru: Русский</a> · <a href="./README.ko-KR.md">:kr: 한국어</a> · <a href="./README.zh-CN.md">:cn: 简体中文</a> · <a href="./README.it-IT.md">:it: Italiano</a> · <a href="./README.ja-JP.md">:jp: 日本語</a> · <a href="./README.id-ID.md">:id: Bahasa Indonesia</a> · <a href="./README.pt-BR.md">:br: Português</a>
|
||||
Diese README ist auch verfügbar in: <a href="./README.md">:gb: English</a> · <a href="./README.es-ES.md">:es: Spanish</a> · <a href="./README.ru-RU.md">:ru: Русский</a> · <a href="./README.ko-KR.md">:kr: 한국어</a> · <a href="./README.zh-CN.md">:cn: 简体中文</a> · <a href="./README.it-IT.md">:it: Italiano</a> · <a href="./README.ja-JP.md">:jp: 日本語</a> · <a href="./README.id-ID.md">:id: Bahasa Indonesia</a> · <a href="./README.pt-BR.md">:brazil: Português</a> · <a href="./README.pl-PL.md">:poland: Polski</a>
|
||||
</p>
|
||||
|
||||
----
|
||||
@@ -119,6 +119,7 @@ Plugins und Themen können direkt aus der Ansicht "Einstellungen" in Tabby insta
|
||||
* [clippy](https://github.com/Eugeny/tabby-clippy) - ein Beispiel-Plugin, das einen die ganze Zeit nervt
|
||||
* [workspace-manager](https://github.com/composer404/tabby-workspace-manager) - ermöglicht das Erstellen eigener Workspace-Profile auf Basis der angegebenen Konfiguration
|
||||
* [search-in-browser](https://github.com/composer404/tabby-search-in-browser) - öffnet den Standard-Systembrowser mit einem Text, der aus dem Tabby Tab ausgewählt wurde
|
||||
* [sftp-tab](https://github.com/wljince007/tabby-sftp-tab) - open sftp tab for ssh connection like SecureCRT
|
||||
|
||||
<a name="themes"></a>
|
||||
|
||||
@@ -242,7 +243,7 @@ Dank geht an diese wunderbaren Menschen ([emoji key](https://allcontributors.org
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/mwz"><img src="https://avatars.githubusercontent.com/u/1190768?v=4?s=100" width="100px;" alt="Michael Wizner"/><br /><sub><b>Michael Wizner</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=mwz" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/mgrulich"><img src="https://avatars.githubusercontent.com/u/781036?v=4?s=100" width="100px;" alt="Martin"/><br /><sub><b>Martin</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=mgrulich" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/piersandro"><img src="https://avatars.githubusercontent.com/u/19996309?v=4?s=100" width="100px;" alt="Piersandro Guerrera"/><br /><sub><b>Piersandro Guerrera</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=piersandro" title="Documentation">📖</a> <a href="#translation-piersandro" title="Translation">🌍</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="http://pingbase.cn"><img src="https://avatars.githubusercontent.com/u/19320096?v=4?s=100" width="100px;" alt="X-0x01"/><br /><sub><b>X-0x01</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=X-0x01" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/0x973"><img src="https://avatars.githubusercontent.com/u/19320096?v=4?s=100" width="100px;" alt="0x973"/><br /><sub><b>0x973</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=0x973" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/Allenator"><img src="https://avatars.githubusercontent.com/u/11794943?v=4?s=100" width="100px;" alt="Allenator"/><br /><sub><b>Allenator</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=Allenator" title="Documentation">📖</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
@@ -321,6 +322,19 @@ Dank geht an diese wunderbaren Menschen ([emoji key](https://allcontributors.org
|
||||
<td align="center" valign="top" width="14.28%"><a href="http://kapocsi.ca"><img src="https://avatars.githubusercontent.com/u/84490604?v=4?s=100" width="100px;" alt="Thomas Kapocsi"/><br /><sub><b>Thomas Kapocsi</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=Kapocsi" title="Documentation">📖</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://dylhack.dev/"><img src="https://avatars.githubusercontent.com/u/27179786?v=4?s=100" width="100px;" alt="Dylan Hackworth"/><br /><sub><b>Dylan Hackworth</b></sub></a><br /><a href="#financial-dylhack" title="Financial">💵</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/echo304"><img src="https://avatars.githubusercontent.com/u/16456651?v=4?s=100" width="100px;" alt="Sangboak Lee"/><br /><sub><b>Sangboak Lee</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=echo304" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/qyecst"><img src="https://avatars.githubusercontent.com/u/13901864?v=4?s=100" width="100px;" alt="qyecst"/><br /><sub><b>qyecst</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=qyecst" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/DehanLUO"><img src="https://avatars.githubusercontent.com/u/53093688?v=4?s=100" width="100px;" alt="Han"/><br /><sub><b>Han</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=DehanLUO" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/wljince007"><img src="https://avatars.githubusercontent.com/u/88243938?v=4?s=100" width="100px;" alt="wljince007"/><br /><sub><b>wljince007</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=wljince007" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/FeroTheFox"><img src="https://avatars.githubusercontent.com/u/52982404?v=4?s=100" width="100px;" alt="fero"/><br /><sub><b>fero</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=FeroTheFox" title="Code">💻</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://siebsie23.nl/"><img src="https://avatars.githubusercontent.com/u/25083973?v=4?s=100" width="100px;" alt="Sibren"/><br /><sub><b>Sibren</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=siebsie23" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://www.nathaniel-walser.com"><img src="https://avatars.githubusercontent.com/u/33339996?v=4?s=100" width="100px;" alt="Nathaniel Walser"/><br /><sub><b>Nathaniel Walser</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=nwalser" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/aaronhuggins"><img src="https://avatars.githubusercontent.com/u/16567111?v=4?s=100" width="100px;" alt="Aaron Huggins"/><br /><sub><b>Aaron Huggins</b></sub></a><br /><a href="#design-aaronhuggins" title="Design">🎨</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://zkxdex.github.io/"><img src="https://avatars.githubusercontent.com/u/66271780?v=4?s=100" width="100px;" alt="KDex"/><br /><sub><b>KDex</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=zKXDEX" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/kimbob13"><img src="https://avatars.githubusercontent.com/u/26755098?v=4?s=100" width="100px;" alt="ChangHwan Kim"/><br /><sub><b>ChangHwan Kim</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=kimbob13" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/ashneilson"><img src="https://avatars.githubusercontent.com/u/35913512?v=4?s=100" width="100px;" alt="Ash Neilson"/><br /><sub><b>Ash Neilson</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=ashneilson" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/cfs4819"><img src="https://avatars.githubusercontent.com/u/53071761?v=4?s=100" width="100px;" alt="Chen Fansong"/><br /><sub><b>Chen Fansong</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=cfs4819" title="Code">💻</a></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
@@ -21,7 +21,7 @@
|
||||
|
||||
<br/>
|
||||
<p align="center">
|
||||
Este fichero README está disponible en: <a href="./README.md">:gb: English</a> · <a href="./README.ru-RU.md">:ru: Русский</a> · <a href="./README.ko-KR.md">:kr: 한국어</a> · <a href="./README.zh-CN.md">:cn: 简体中文</a> · <a href="./README.it-IT.md">:it: Italiano</a> · <a href="./README.de-DE.md">:de: Deutsch</a> · <a href="./README.ja-JP.md">:jp: 日本語</a> · <a href="./README.id-ID.md">:id: Bahasa Indonesia</a> · <a href="./README.pt-BR.md">:br: Português</a>
|
||||
Este fichero README está disponible en: <a href="./README.md">:gb: English</a> · <a href="./README.ru-RU.md">:ru: Русский</a> · <a href="./README.ko-KR.md">:kr: 한국어</a> · <a href="./README.zh-CN.md">:cn: 简体中文</a> · <a href="./README.it-IT.md">:it: Italiano</a> · <a href="./README.de-DE.md">:de: Deutsch</a> · <a href="./README.ja-JP.md">:jp: 日本語</a> · <a href="./README.id-ID.md">:id: Bahasa Indonesia</a> · <a href="./README.pt-BR.md">:brazil: Português</a> · <a href="./README.pl-PL.md">:poland: Polski</a>
|
||||
</p>
|
||||
|
||||
----
|
||||
@@ -120,6 +120,7 @@ Los plugins y los temas se pueden instalar directamente desde la vista de Config
|
||||
* [clippy](https://github.com/Eugeny/tabby-clippy) - un ejemplo de plugin que te molesta todo el tiempo
|
||||
* [workspace-manager](https://github.com/composer404/tabby-workspace-manager) - permite crear perfiles de espacio de trabajo personalizados basados en la configuración dada
|
||||
* [search-in-browser](https://github.com/composer404/tabby-search-in-browser) - abre el navegador del sistema por defecto con un texto seleccionado en la pestaña de Tabby's
|
||||
* [sftp-tab](https://github.com/wljince007/tabby-sftp-tab) - open sftp tab for ssh connection like SecureCRT
|
||||
<a name="themes"></a>
|
||||
|
||||
# Temas
|
||||
@@ -244,7 +245,7 @@ Gracias a estas maravillosas personas ([emoji key](https://allcontributors.org/d
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/mwz"><img src="https://avatars.githubusercontent.com/u/1190768?v=4?s=100" width="100px;" alt="Michael Wizner"/><br /><sub><b>Michael Wizner</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=mwz" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/mgrulich"><img src="https://avatars.githubusercontent.com/u/781036?v=4?s=100" width="100px;" alt="Martin"/><br /><sub><b>Martin</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=mgrulich" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/piersandro"><img src="https://avatars.githubusercontent.com/u/19996309?v=4?s=100" width="100px;" alt="Piersandro Guerrera"/><br /><sub><b>Piersandro Guerrera</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=piersandro" title="Documentation">📖</a> <a href="#translation-piersandro" title="Translation">🌍</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="http://pingbase.cn"><img src="https://avatars.githubusercontent.com/u/19320096?v=4?s=100" width="100px;" alt="X-0x01"/><br /><sub><b>X-0x01</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=X-0x01" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/0x973"><img src="https://avatars.githubusercontent.com/u/19320096?v=4?s=100" width="100px;" alt="0x973"/><br /><sub><b>0x973</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=0x973" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/Allenator"><img src="https://avatars.githubusercontent.com/u/11794943?v=4?s=100" width="100px;" alt="Allenator"/><br /><sub><b>Allenator</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=Allenator" title="Documentation">📖</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
@@ -323,6 +324,19 @@ Gracias a estas maravillosas personas ([emoji key](https://allcontributors.org/d
|
||||
<td align="center" valign="top" width="14.28%"><a href="http://kapocsi.ca"><img src="https://avatars.githubusercontent.com/u/84490604?v=4?s=100" width="100px;" alt="Thomas Kapocsi"/><br /><sub><b>Thomas Kapocsi</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=Kapocsi" title="Documentation">📖</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://dylhack.dev/"><img src="https://avatars.githubusercontent.com/u/27179786?v=4?s=100" width="100px;" alt="Dylan Hackworth"/><br /><sub><b>Dylan Hackworth</b></sub></a><br /><a href="#financial-dylhack" title="Financial">💵</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/echo304"><img src="https://avatars.githubusercontent.com/u/16456651?v=4?s=100" width="100px;" alt="Sangboak Lee"/><br /><sub><b>Sangboak Lee</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=echo304" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/qyecst"><img src="https://avatars.githubusercontent.com/u/13901864?v=4?s=100" width="100px;" alt="qyecst"/><br /><sub><b>qyecst</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=qyecst" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/DehanLUO"><img src="https://avatars.githubusercontent.com/u/53093688?v=4?s=100" width="100px;" alt="Han"/><br /><sub><b>Han</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=DehanLUO" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/wljince007"><img src="https://avatars.githubusercontent.com/u/88243938?v=4?s=100" width="100px;" alt="wljince007"/><br /><sub><b>wljince007</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=wljince007" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/FeroTheFox"><img src="https://avatars.githubusercontent.com/u/52982404?v=4?s=100" width="100px;" alt="fero"/><br /><sub><b>fero</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=FeroTheFox" title="Code">💻</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://siebsie23.nl/"><img src="https://avatars.githubusercontent.com/u/25083973?v=4?s=100" width="100px;" alt="Sibren"/><br /><sub><b>Sibren</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=siebsie23" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://www.nathaniel-walser.com"><img src="https://avatars.githubusercontent.com/u/33339996?v=4?s=100" width="100px;" alt="Nathaniel Walser"/><br /><sub><b>Nathaniel Walser</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=nwalser" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/aaronhuggins"><img src="https://avatars.githubusercontent.com/u/16567111?v=4?s=100" width="100px;" alt="Aaron Huggins"/><br /><sub><b>Aaron Huggins</b></sub></a><br /><a href="#design-aaronhuggins" title="Design">🎨</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://zkxdex.github.io/"><img src="https://avatars.githubusercontent.com/u/66271780?v=4?s=100" width="100px;" alt="KDex"/><br /><sub><b>KDex</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=zKXDEX" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/kimbob13"><img src="https://avatars.githubusercontent.com/u/26755098?v=4?s=100" width="100px;" alt="ChangHwan Kim"/><br /><sub><b>ChangHwan Kim</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=kimbob13" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/ashneilson"><img src="https://avatars.githubusercontent.com/u/35913512?v=4?s=100" width="100px;" alt="Ash Neilson"/><br /><sub><b>Ash Neilson</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=ashneilson" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/cfs4819"><img src="https://avatars.githubusercontent.com/u/53071761?v=4?s=100" width="100px;" alt="Chen Fansong"/><br /><sub><b>Chen Fansong</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=cfs4819" title="Code">💻</a></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
@@ -21,7 +21,7 @@
|
||||
|
||||
<br/>
|
||||
<p align="center">
|
||||
This README is also available in: <a href="./README.md">:gb: English</a> · <a href="./README.es-ES.md">:es: Spanish</a> · <a href="./README.ru-RU.md">:ru: Русский</a> · <a href="./README.ko-KR.md">:kr: 한국어</a> · <a href="./README.zh-CN.md">:cn: 简体中文</a> · <a href="./README.it-IT.md">:it: Italiano</a> · <a href="./README.de-DE.md">:de: Deutsch</a> · <a href="./README.ja-JP.md">:jp: 日本語</a> · <a href="./README.pt-BR.md">:br: Português</a>
|
||||
This README is also available in: <a href="./README.md">:gb: English</a> · <a href="./README.es-ES.md">:es: Spanish</a> · <a href="./README.ru-RU.md">:ru: Русский</a> · <a href="./README.ko-KR.md">:kr: 한국어</a> · <a href="./README.zh-CN.md">:cn: 简体中文</a> · <a href="./README.it-IT.md">:it: Italiano</a> · <a href="./README.de-DE.md">:de: Deutsch</a> · <a href="./README.ja-JP.md">:jp: 日本語</a> · <a href="./README.pt-BR.md">:brazil: Português</a> · <a href="./README.pl-PL.md">:poland: Polski</a>
|
||||
</p>
|
||||
|
||||
----
|
||||
@@ -120,6 +120,7 @@ Tema dan Plugin bisa langsung di install dari Pengaturan di dalam Tabby.
|
||||
* [clippy](https://github.com/Eugeny/tabby-clippy) - suatu contoh plugin yang akan mengganggu anda setiap saat
|
||||
* [workspace-manager](https://github.com/composer404/tabby-workspace-manager) - memperbolehkan membuat kustom profil workspace dari konfigurasi yang diberikan
|
||||
* [search-in-browser](https://github.com/composer404/tabby-search-in-browser) - membuka browser default dengan text yang dipilih dari Tab Tabby
|
||||
* [sftp-tab](https://github.com/wljince007/tabby-sftp-tab) - open sftp tab for ssh connection like SecureCRT
|
||||
|
||||
<a name="themes"></a>
|
||||
|
||||
@@ -241,7 +242,7 @@ Terima kasih kepada mereka yang telah membantu ([emoji key](https://allcontribut
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/mwz"><img src="https://avatars.githubusercontent.com/u/1190768?v=4?s=100" width="100px;" alt="Michael Wizner"/><br /><sub><b>Michael Wizner</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=mwz" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/mgrulich"><img src="https://avatars.githubusercontent.com/u/781036?v=4?s=100" width="100px;" alt="Martin"/><br /><sub><b>Martin</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=mgrulich" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/piersandro"><img src="https://avatars.githubusercontent.com/u/19996309?v=4?s=100" width="100px;" alt="Piersandro Guerrera"/><br /><sub><b>Piersandro Guerrera</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=piersandro" title="Documentation">📖</a> <a href="#translation-piersandro" title="Translation">🌍</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="http://pingbase.cn"><img src="https://avatars.githubusercontent.com/u/19320096?v=4?s=100" width="100px;" alt="X-0x01"/><br /><sub><b>X-0x01</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=X-0x01" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/0x973"><img src="https://avatars.githubusercontent.com/u/19320096?v=4?s=100" width="100px;" alt="0x973"/><br /><sub><b>0x973</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=0x973" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/Allenator"><img src="https://avatars.githubusercontent.com/u/11794943?v=4?s=100" width="100px;" alt="Allenator"/><br /><sub><b>Allenator</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=Allenator" title="Documentation">📖</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
@@ -320,6 +321,19 @@ Terima kasih kepada mereka yang telah membantu ([emoji key](https://allcontribut
|
||||
<td align="center" valign="top" width="14.28%"><a href="http://kapocsi.ca"><img src="https://avatars.githubusercontent.com/u/84490604?v=4?s=100" width="100px;" alt="Thomas Kapocsi"/><br /><sub><b>Thomas Kapocsi</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=Kapocsi" title="Documentation">📖</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://dylhack.dev/"><img src="https://avatars.githubusercontent.com/u/27179786?v=4?s=100" width="100px;" alt="Dylan Hackworth"/><br /><sub><b>Dylan Hackworth</b></sub></a><br /><a href="#financial-dylhack" title="Financial">💵</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/echo304"><img src="https://avatars.githubusercontent.com/u/16456651?v=4?s=100" width="100px;" alt="Sangboak Lee"/><br /><sub><b>Sangboak Lee</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=echo304" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/qyecst"><img src="https://avatars.githubusercontent.com/u/13901864?v=4?s=100" width="100px;" alt="qyecst"/><br /><sub><b>qyecst</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=qyecst" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/DehanLUO"><img src="https://avatars.githubusercontent.com/u/53093688?v=4?s=100" width="100px;" alt="Han"/><br /><sub><b>Han</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=DehanLUO" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/wljince007"><img src="https://avatars.githubusercontent.com/u/88243938?v=4?s=100" width="100px;" alt="wljince007"/><br /><sub><b>wljince007</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=wljince007" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/FeroTheFox"><img src="https://avatars.githubusercontent.com/u/52982404?v=4?s=100" width="100px;" alt="fero"/><br /><sub><b>fero</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=FeroTheFox" title="Code">💻</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://siebsie23.nl/"><img src="https://avatars.githubusercontent.com/u/25083973?v=4?s=100" width="100px;" alt="Sibren"/><br /><sub><b>Sibren</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=siebsie23" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://www.nathaniel-walser.com"><img src="https://avatars.githubusercontent.com/u/33339996?v=4?s=100" width="100px;" alt="Nathaniel Walser"/><br /><sub><b>Nathaniel Walser</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=nwalser" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/aaronhuggins"><img src="https://avatars.githubusercontent.com/u/16567111?v=4?s=100" width="100px;" alt="Aaron Huggins"/><br /><sub><b>Aaron Huggins</b></sub></a><br /><a href="#design-aaronhuggins" title="Design">🎨</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://zkxdex.github.io/"><img src="https://avatars.githubusercontent.com/u/66271780?v=4?s=100" width="100px;" alt="KDex"/><br /><sub><b>KDex</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=zKXDEX" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/kimbob13"><img src="https://avatars.githubusercontent.com/u/26755098?v=4?s=100" width="100px;" alt="ChangHwan Kim"/><br /><sub><b>ChangHwan Kim</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=kimbob13" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/ashneilson"><img src="https://avatars.githubusercontent.com/u/35913512?v=4?s=100" width="100px;" alt="Ash Neilson"/><br /><sub><b>Ash Neilson</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=ashneilson" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/cfs4819"><img src="https://avatars.githubusercontent.com/u/53071761?v=4?s=100" width="100px;" alt="Chen Fansong"/><br /><sub><b>Chen Fansong</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=cfs4819" title="Code">💻</a></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
@@ -21,7 +21,7 @@
|
||||
|
||||
<br/>
|
||||
<p align="center">
|
||||
Questo README è disponibile anche in: <a href="./README.md">:gb: English</a> · <a href="./README.es-ES.md">:es: Spanish</a> · <a href="./README.ru-RU.md">:ru: Русский</a> · <a href="./README.ko-KR.md">:kr: 한국어</a> · <a href="./README.zh-CN.md">:cn: 简体中文</a> · <a href="./README.de-DE.md">:de: Deutsch</a> · <a href="./README.ja-JP.md">:jp: 日本語</a> · <a href="./README.id-ID.md">:id: Bahasa Indonesia</a> · <a href="./README.pt-BR.md">:br: Português</a>
|
||||
Questo README è disponibile anche in: <a href="./README.md">:gb: English</a> · <a href="./README.es-ES.md">:es: Spanish</a> · <a href="./README.ru-RU.md">:ru: Русский</a> · <a href="./README.ko-KR.md">:kr: 한국어</a> · <a href="./README.zh-CN.md">:cn: 简体中文</a> · <a href="./README.de-DE.md">:de: Deutsch</a> · <a href="./README.ja-JP.md">:jp: 日本語</a> · <a href="./README.id-ID.md">:id: Bahasa Indonesia</a> · <a href="./README.pt-BR.md">:brazil: Português</a> · <a href="./README.pl-PL.md">:poland: Polski</a>
|
||||
|
||||
----
|
||||
|
||||
@@ -117,6 +117,7 @@ Plugins and themes can be installed directly from the Settings view inside Tabby
|
||||
* [clippy](https://github.com/Eugeny/tabby-clippy) - an example plugin which annoys you all the time
|
||||
* [workspace-manager](https://github.com/composer404/tabby-workspace-manager) - allows creating custom workspace profiles based on the given config
|
||||
* [search-in-browser](https://github.com/composer404/tabby-search-in-browser) - opens default system browser with a text selected from the Tabby's tab
|
||||
* [sftp-tab](https://github.com/wljince007/tabby-sftp-tab) - open sftp tab for ssh connection like SecureCRT
|
||||
|
||||
<a name="themes"></a>
|
||||
# Temi
|
||||
@@ -237,7 +238,7 @@ Grazie a queste persone meravigliose ([emoji key](https://allcontributors.org/do
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/mwz"><img src="https://avatars.githubusercontent.com/u/1190768?v=4?s=100" width="100px;" alt="Michael Wizner"/><br /><sub><b>Michael Wizner</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=mwz" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/mgrulich"><img src="https://avatars.githubusercontent.com/u/781036?v=4?s=100" width="100px;" alt="Martin"/><br /><sub><b>Martin</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=mgrulich" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/piersandro"><img src="https://avatars.githubusercontent.com/u/19996309?v=4?s=100" width="100px;" alt="Piersandro Guerrera"/><br /><sub><b>Piersandro Guerrera</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=piersandro" title="Documentation">📖</a> <a href="#translation-piersandro" title="Translation">🌍</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="http://pingbase.cn"><img src="https://avatars.githubusercontent.com/u/19320096?v=4?s=100" width="100px;" alt="X-0x01"/><br /><sub><b>X-0x01</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=X-0x01" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/0x973"><img src="https://avatars.githubusercontent.com/u/19320096?v=4?s=100" width="100px;" alt="0x973"/><br /><sub><b>0x973</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=0x973" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/Allenator"><img src="https://avatars.githubusercontent.com/u/11794943?v=4?s=100" width="100px;" alt="Allenator"/><br /><sub><b>Allenator</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=Allenator" title="Documentation">📖</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
@@ -316,6 +317,19 @@ Grazie a queste persone meravigliose ([emoji key](https://allcontributors.org/do
|
||||
<td align="center" valign="top" width="14.28%"><a href="http://kapocsi.ca"><img src="https://avatars.githubusercontent.com/u/84490604?v=4?s=100" width="100px;" alt="Thomas Kapocsi"/><br /><sub><b>Thomas Kapocsi</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=Kapocsi" title="Documentation">📖</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://dylhack.dev/"><img src="https://avatars.githubusercontent.com/u/27179786?v=4?s=100" width="100px;" alt="Dylan Hackworth"/><br /><sub><b>Dylan Hackworth</b></sub></a><br /><a href="#financial-dylhack" title="Financial">💵</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/echo304"><img src="https://avatars.githubusercontent.com/u/16456651?v=4?s=100" width="100px;" alt="Sangboak Lee"/><br /><sub><b>Sangboak Lee</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=echo304" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/qyecst"><img src="https://avatars.githubusercontent.com/u/13901864?v=4?s=100" width="100px;" alt="qyecst"/><br /><sub><b>qyecst</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=qyecst" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/DehanLUO"><img src="https://avatars.githubusercontent.com/u/53093688?v=4?s=100" width="100px;" alt="Han"/><br /><sub><b>Han</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=DehanLUO" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/wljince007"><img src="https://avatars.githubusercontent.com/u/88243938?v=4?s=100" width="100px;" alt="wljince007"/><br /><sub><b>wljince007</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=wljince007" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/FeroTheFox"><img src="https://avatars.githubusercontent.com/u/52982404?v=4?s=100" width="100px;" alt="fero"/><br /><sub><b>fero</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=FeroTheFox" title="Code">💻</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://siebsie23.nl/"><img src="https://avatars.githubusercontent.com/u/25083973?v=4?s=100" width="100px;" alt="Sibren"/><br /><sub><b>Sibren</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=siebsie23" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://www.nathaniel-walser.com"><img src="https://avatars.githubusercontent.com/u/33339996?v=4?s=100" width="100px;" alt="Nathaniel Walser"/><br /><sub><b>Nathaniel Walser</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=nwalser" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/aaronhuggins"><img src="https://avatars.githubusercontent.com/u/16567111?v=4?s=100" width="100px;" alt="Aaron Huggins"/><br /><sub><b>Aaron Huggins</b></sub></a><br /><a href="#design-aaronhuggins" title="Design">🎨</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://zkxdex.github.io/"><img src="https://avatars.githubusercontent.com/u/66271780?v=4?s=100" width="100px;" alt="KDex"/><br /><sub><b>KDex</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=zKXDEX" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/kimbob13"><img src="https://avatars.githubusercontent.com/u/26755098?v=4?s=100" width="100px;" alt="ChangHwan Kim"/><br /><sub><b>ChangHwan Kim</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=kimbob13" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/ashneilson"><img src="https://avatars.githubusercontent.com/u/35913512?v=4?s=100" width="100px;" alt="Ash Neilson"/><br /><sub><b>Ash Neilson</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=ashneilson" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/cfs4819"><img src="https://avatars.githubusercontent.com/u/53071761?v=4?s=100" width="100px;" alt="Chen Fansong"/><br /><sub><b>Chen Fansong</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=cfs4819" title="Code">💻</a></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
@@ -28,7 +28,7 @@
|
||||
|
||||
<br/>
|
||||
<p align="center">
|
||||
このREADMEは次の言語でもご覧いただけます: <a href="./README.md">:gb: English</a> · <a href="./README.es-ES.md">:es: Spanish</a> · <a href="./README.ru-RU.md">:ru: Русский</a> · <a href="./README.ko-KR.md">:kr: 한국어</a> · <a href="./README.zh-CN.md">:cn: 简体中文</a> · <a href="./README.it-IT.md">:it: Italiano</a> · <a href="./README.de-DE.md">:de: Deutsch</a> · <a href="./README.id-ID.md">:id: Bahasa Indonesia</a> · <a href="./README.pt-BR.md">:br: Português</a>
|
||||
このREADMEは次の言語でもご覧いただけます: <a href="./README.md">:gb: English</a> · <a href="./README.es-ES.md">:es: Spanish</a> · <a href="./README.ru-RU.md">:ru: Русский</a> · <a href="./README.ko-KR.md">:kr: 한국어</a> · <a href="./README.zh-CN.md">:cn: 简体中文</a> · <a href="./README.it-IT.md">:it: Italiano</a> · <a href="./README.de-DE.md">:de: Deutsch</a> · <a href="./README.id-ID.md">:id: Bahasa Indonesia</a> · <a href="./README.pt-BR.md">:brazil: Português</a> · <a href="./README.pl-PL.md">:poland: Polski</a>
|
||||
</p>
|
||||
|
||||
----
|
||||
@@ -127,6 +127,7 @@ Windows上では、`Tabby.exe`がある場所と同じ場所に`data`フォル
|
||||
* [clippy](https://github.com/Eugeny/tabby-clippy) - プラグインの作例として、いつも厄介なあいつが出てくるプラグイン
|
||||
* [workspace-manager](https://github.com/composer404/tabby-workspace-manager) - 指定された設定からカスタマイズされたワークスペースを作成することができます
|
||||
* [search-in-browser](https://github.com/composer404/tabby-search-in-browser) - Tabby内の端末で選択したテキストを既定ブラウザで開くことができます。
|
||||
* [sftp-tab](https://github.com/wljince007/tabby-sftp-tab) - open sftp tab for ssh connection like SecureCRT
|
||||
|
||||
<a name="themes"></a>
|
||||
|
||||
@@ -252,7 +253,7 @@ Windows上では、`Tabby.exe`がある場所と同じ場所に`data`フォル
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/mwz"><img src="https://avatars.githubusercontent.com/u/1190768?v=4?s=100" width="100px;" alt="Michael Wizner"/><br /><sub><b>Michael Wizner</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=mwz" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/mgrulich"><img src="https://avatars.githubusercontent.com/u/781036?v=4?s=100" width="100px;" alt="Martin"/><br /><sub><b>Martin</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=mgrulich" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/piersandro"><img src="https://avatars.githubusercontent.com/u/19996309?v=4?s=100" width="100px;" alt="Piersandro Guerrera"/><br /><sub><b>Piersandro Guerrera</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=piersandro" title="Documentation">📖</a> <a href="#translation-piersandro" title="Translation">🌍</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="http://pingbase.cn"><img src="https://avatars.githubusercontent.com/u/19320096?v=4?s=100" width="100px;" alt="X-0x01"/><br /><sub><b>X-0x01</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=X-0x01" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/0x973"><img src="https://avatars.githubusercontent.com/u/19320096?v=4?s=100" width="100px;" alt="0x973"/><br /><sub><b>0x973</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=0x973" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/Allenator"><img src="https://avatars.githubusercontent.com/u/11794943?v=4?s=100" width="100px;" alt="Allenator"/><br /><sub><b>Allenator</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=Allenator" title="Documentation">📖</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
@@ -331,6 +332,19 @@ Windows上では、`Tabby.exe`がある場所と同じ場所に`data`フォル
|
||||
<td align="center" valign="top" width="14.28%"><a href="http://kapocsi.ca"><img src="https://avatars.githubusercontent.com/u/84490604?v=4?s=100" width="100px;" alt="Thomas Kapocsi"/><br /><sub><b>Thomas Kapocsi</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=Kapocsi" title="Documentation">📖</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://dylhack.dev/"><img src="https://avatars.githubusercontent.com/u/27179786?v=4?s=100" width="100px;" alt="Dylan Hackworth"/><br /><sub><b>Dylan Hackworth</b></sub></a><br /><a href="#financial-dylhack" title="Financial">💵</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/echo304"><img src="https://avatars.githubusercontent.com/u/16456651?v=4?s=100" width="100px;" alt="Sangboak Lee"/><br /><sub><b>Sangboak Lee</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=echo304" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/qyecst"><img src="https://avatars.githubusercontent.com/u/13901864?v=4?s=100" width="100px;" alt="qyecst"/><br /><sub><b>qyecst</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=qyecst" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/DehanLUO"><img src="https://avatars.githubusercontent.com/u/53093688?v=4?s=100" width="100px;" alt="Han"/><br /><sub><b>Han</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=DehanLUO" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/wljince007"><img src="https://avatars.githubusercontent.com/u/88243938?v=4?s=100" width="100px;" alt="wljince007"/><br /><sub><b>wljince007</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=wljince007" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/FeroTheFox"><img src="https://avatars.githubusercontent.com/u/52982404?v=4?s=100" width="100px;" alt="fero"/><br /><sub><b>fero</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=FeroTheFox" title="Code">💻</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://siebsie23.nl/"><img src="https://avatars.githubusercontent.com/u/25083973?v=4?s=100" width="100px;" alt="Sibren"/><br /><sub><b>Sibren</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=siebsie23" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://www.nathaniel-walser.com"><img src="https://avatars.githubusercontent.com/u/33339996?v=4?s=100" width="100px;" alt="Nathaniel Walser"/><br /><sub><b>Nathaniel Walser</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=nwalser" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/aaronhuggins"><img src="https://avatars.githubusercontent.com/u/16567111?v=4?s=100" width="100px;" alt="Aaron Huggins"/><br /><sub><b>Aaron Huggins</b></sub></a><br /><a href="#design-aaronhuggins" title="Design">🎨</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://zkxdex.github.io/"><img src="https://avatars.githubusercontent.com/u/66271780?v=4?s=100" width="100px;" alt="KDex"/><br /><sub><b>KDex</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=zKXDEX" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/kimbob13"><img src="https://avatars.githubusercontent.com/u/26755098?v=4?s=100" width="100px;" alt="ChangHwan Kim"/><br /><sub><b>ChangHwan Kim</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=kimbob13" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/ashneilson"><img src="https://avatars.githubusercontent.com/u/35913512?v=4?s=100" width="100px;" alt="Ash Neilson"/><br /><sub><b>Ash Neilson</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=ashneilson" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/cfs4819"><img src="https://avatars.githubusercontent.com/u/53071761?v=4?s=100" width="100px;" alt="Chen Fansong"/><br /><sub><b>Chen Fansong</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=cfs4819" title="Code">💻</a></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
@@ -19,6 +19,11 @@
|
||||
* [Repositories](https://packagecloud.io/eugeny/tabby): [Debian/Ubuntu-based](https://packagecloud.io/eugeny/tabby/install#bash-deb), [RPM-based](https://packagecloud.io/eugeny/tabby/install#bash-rpm)
|
||||
* [Latest nightly build](https://nightly.link/Eugeny/tabby/workflows/build/master)
|
||||
|
||||
<br/>
|
||||
<p align="center">
|
||||
This README is also available in: <a href="./README.md">:gb: English</a> · <a href="./README.es-ES.md">:es: Spanish</a> · <a href="./README.ru-RU.md">:ru: Русский</a> · <a href="./README.zh-CN.md">:cn: 简体中文</a> · <a href="./README.it-IT.md">:it: Italiano</a> · <a href="./README.de-DE.md">:de: Deutsch</a> · <a href="./README.ja-JP.md">:jp: 日本語</a> · <a href="./README.id-ID.md">:id: Bahasa Indonesia</a> · <a href="./README.pt-BR.md">:brazil: Português</a> · <a href="./README.pl-PL.md">:poland: Polski</a>
|
||||
</p>
|
||||
|
||||
----
|
||||
|
||||
**Tabby** (구 **Terminus**)는 Windows, macOS 및 Linux용으로 뛰어난 구성의 터미널 에뮬레이터, SSH 및 시리얼 클라이언트입니다.
|
||||
@@ -111,6 +116,7 @@
|
||||
* [clippy](https://github.com/Eugeny/tabby-clippy) - 항상 당신을 귀찮게 하는 예제 플러그인
|
||||
* [workspace-manager](https://github.com/composer404/tabby-workspace-manager) - 주어진 구성을 기반으로 사용자 정의 작업 공간 프로필을 생성할 수 있습니다
|
||||
* [search-in-browser](https://github.com/composer404/tabby-search-in-browser) - Tabby의 탭에서 선택한 텍스트로 기본 시스템 브라우저를 엽니다
|
||||
* [sftp-tab](https://github.com/wljince007/tabby-sftp-tab) - open sftp tab for ssh connection like SecureCRT
|
||||
|
||||
<a name="themes"></a>
|
||||
# 테마
|
||||
@@ -231,7 +237,7 @@ Pull requests and plugins are welcome!
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/mwz"><img src="https://avatars.githubusercontent.com/u/1190768?v=4?s=100" width="100px;" alt="Michael Wizner"/><br /><sub><b>Michael Wizner</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=mwz" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/mgrulich"><img src="https://avatars.githubusercontent.com/u/781036?v=4?s=100" width="100px;" alt="Martin"/><br /><sub><b>Martin</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=mgrulich" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/piersandro"><img src="https://avatars.githubusercontent.com/u/19996309?v=4?s=100" width="100px;" alt="Piersandro Guerrera"/><br /><sub><b>Piersandro Guerrera</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=piersandro" title="Documentation">📖</a> <a href="#translation-piersandro" title="Translation">🌍</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="http://pingbase.cn"><img src="https://avatars.githubusercontent.com/u/19320096?v=4?s=100" width="100px;" alt="X-0x01"/><br /><sub><b>X-0x01</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=X-0x01" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/0x973"><img src="https://avatars.githubusercontent.com/u/19320096?v=4?s=100" width="100px;" alt="0x973"/><br /><sub><b>0x973</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=0x973" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/Allenator"><img src="https://avatars.githubusercontent.com/u/11794943?v=4?s=100" width="100px;" alt="Allenator"/><br /><sub><b>Allenator</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=Allenator" title="Documentation">📖</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
@@ -310,6 +316,19 @@ Pull requests and plugins are welcome!
|
||||
<td align="center" valign="top" width="14.28%"><a href="http://kapocsi.ca"><img src="https://avatars.githubusercontent.com/u/84490604?v=4?s=100" width="100px;" alt="Thomas Kapocsi"/><br /><sub><b>Thomas Kapocsi</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=Kapocsi" title="Documentation">📖</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://dylhack.dev/"><img src="https://avatars.githubusercontent.com/u/27179786?v=4?s=100" width="100px;" alt="Dylan Hackworth"/><br /><sub><b>Dylan Hackworth</b></sub></a><br /><a href="#financial-dylhack" title="Financial">💵</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/echo304"><img src="https://avatars.githubusercontent.com/u/16456651?v=4?s=100" width="100px;" alt="Sangboak Lee"/><br /><sub><b>Sangboak Lee</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=echo304" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/qyecst"><img src="https://avatars.githubusercontent.com/u/13901864?v=4?s=100" width="100px;" alt="qyecst"/><br /><sub><b>qyecst</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=qyecst" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/DehanLUO"><img src="https://avatars.githubusercontent.com/u/53093688?v=4?s=100" width="100px;" alt="Han"/><br /><sub><b>Han</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=DehanLUO" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/wljince007"><img src="https://avatars.githubusercontent.com/u/88243938?v=4?s=100" width="100px;" alt="wljince007"/><br /><sub><b>wljince007</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=wljince007" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/FeroTheFox"><img src="https://avatars.githubusercontent.com/u/52982404?v=4?s=100" width="100px;" alt="fero"/><br /><sub><b>fero</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=FeroTheFox" title="Code">💻</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://siebsie23.nl/"><img src="https://avatars.githubusercontent.com/u/25083973?v=4?s=100" width="100px;" alt="Sibren"/><br /><sub><b>Sibren</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=siebsie23" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://www.nathaniel-walser.com"><img src="https://avatars.githubusercontent.com/u/33339996?v=4?s=100" width="100px;" alt="Nathaniel Walser"/><br /><sub><b>Nathaniel Walser</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=nwalser" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/aaronhuggins"><img src="https://avatars.githubusercontent.com/u/16567111?v=4?s=100" width="100px;" alt="Aaron Huggins"/><br /><sub><b>Aaron Huggins</b></sub></a><br /><a href="#design-aaronhuggins" title="Design">🎨</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://zkxdex.github.io/"><img src="https://avatars.githubusercontent.com/u/66271780?v=4?s=100" width="100px;" alt="KDex"/><br /><sub><b>KDex</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=zKXDEX" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/kimbob13"><img src="https://avatars.githubusercontent.com/u/26755098?v=4?s=100" width="100px;" alt="ChangHwan Kim"/><br /><sub><b>ChangHwan Kim</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=kimbob13" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/ashneilson"><img src="https://avatars.githubusercontent.com/u/35913512?v=4?s=100" width="100px;" alt="Ash Neilson"/><br /><sub><b>Ash Neilson</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=ashneilson" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/cfs4819"><img src="https://avatars.githubusercontent.com/u/53071761?v=4?s=100" width="100px;" alt="Chen Fansong"/><br /><sub><b>Chen Fansong</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=cfs4819" title="Code">💻</a></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
25
README.md
25
README.md
@@ -29,12 +29,12 @@
|
||||
|
||||
<br/>
|
||||
<p align="center">
|
||||
This README is also available in: <a href="./README.es-ES.md">:es: Spanish</a> · <a href="./README.ru-RU.md">:ru: Русский</a> · <a href="./README.ko-KR.md">:kr: 한국어</a> · <a href="./README.zh-CN.md">:cn: 简体中文</a> · <a href="./README.it-IT.md">:it: Italiano</a> · <a href="./README.de-DE.md">:de: Deutsch</a> · <a href="./README.ja-JP.md">:jp: 日本語</a> · <a href="./README.id-ID.md">:id: Bahasa Indonesia</a> · <a href="./README.pt-BR.md">🇧🇷 Português</a>
|
||||
This README is also available in: <a href="./README.es-ES.md">:es: Spanish</a> · <a href="./README.ru-RU.md">:ru: Русский</a> · <a href="./README.ko-KR.md">:kr: 한국어</a> · <a href="./README.zh-CN.md">:cn: 简体中文</a> · <a href="./README.it-IT.md">:it: Italiano</a> · <a href="./README.de-DE.md">:de: Deutsch</a> · <a href="./README.ja-JP.md">:jp: 日本語</a> · <a href="./README.id-ID.md">:id: Bahasa Indonesia</a> · <a href="./README.pt-BR.md">:brazil: Português</a> · <a href="./README.pl-PL.md">:poland: Polski</a>
|
||||
</p>
|
||||
|
||||
----
|
||||
|
||||
[**Tabby**](https://tabby.sh) (formerly **Terminus**) is a highly configurable terminal emulator, SSH and serial client for Windows, macOS and Linux
|
||||
[**Tabby**](https://tabby.sh) (formerly **Terminus**) is a highly configurable terminal emulator, SSH and serial client for Windows 10, macOS and Linux
|
||||
|
||||
* Integrated SSH and Telnet client and connection manager
|
||||
* Integrated serial terminal
|
||||
@@ -128,6 +128,10 @@ Plugins and themes can be installed directly from the Settings view inside Tabby
|
||||
* [clippy](https://github.com/Eugeny/tabby-clippy) - an example plugin which annoys you all the time
|
||||
* [workspace-manager](https://github.com/composer404/tabby-workspace-manager) - allows creating custom workspace profiles based on the given config
|
||||
* [search-in-browser](https://github.com/composer404/tabby-search-in-browser) - opens default system browser with a text selected from the Tabby's tab
|
||||
* [sftp-tab](https://github.com/wljince007/tabby-sftp-tab) - open sftp tab for ssh connection like SecureCRT
|
||||
* [background](https://github.com/moemoechu/tabby-background) - change Tabby background image and more...
|
||||
* [highlight](https://github.com/moemoechu/tabby-highlight) - Tabby terminal keyword highlight plugin
|
||||
* [web-auth-handler](https://github.com/Jazzmoon/tabby-web-auth-handler) - In-app web authentication popups (Built primarily for warpgate in-browser auth)
|
||||
|
||||
<a name="themes"></a>
|
||||
|
||||
@@ -138,6 +142,8 @@ Plugins and themes can be installed directly from the Settings view inside Tabby
|
||||
* [gruvbox](https://github.com/porkloin/terminus-theme-gruvbox)
|
||||
* [windows10](https://www.npmjs.com/package/terminus-theme-windows10)
|
||||
* [altair](https://github.com/yxuko/terminus-altair)
|
||||
* [catppuccin](https://github.com/catppuccin/tabby) - Soothing pastel theme for Tabby
|
||||
* [noctis](https://github.com/aaronhuggins/tabby-colors-noctis) - color themes inspired by Noctis VS Code theme
|
||||
|
||||
# Sponsors <!-- omit in toc -->
|
||||
|
||||
@@ -253,7 +259,7 @@ Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/d
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/mwz"><img src="https://avatars.githubusercontent.com/u/1190768?v=4?s=100" width="100px;" alt="Michael Wizner"/><br /><sub><b>Michael Wizner</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=mwz" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/mgrulich"><img src="https://avatars.githubusercontent.com/u/781036?v=4?s=100" width="100px;" alt="Martin"/><br /><sub><b>Martin</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=mgrulich" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/piersandro"><img src="https://avatars.githubusercontent.com/u/19996309?v=4?s=100" width="100px;" alt="Piersandro Guerrera"/><br /><sub><b>Piersandro Guerrera</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=piersandro" title="Documentation">📖</a> <a href="#translation-piersandro" title="Translation">🌍</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="http://pingbase.cn"><img src="https://avatars.githubusercontent.com/u/19320096?v=4?s=100" width="100px;" alt="X-0x01"/><br /><sub><b>X-0x01</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=X-0x01" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/0x973"><img src="https://avatars.githubusercontent.com/u/19320096?v=4?s=100" width="100px;" alt="0x973"/><br /><sub><b>0x973</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=0x973" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/Allenator"><img src="https://avatars.githubusercontent.com/u/11794943?v=4?s=100" width="100px;" alt="Allenator"/><br /><sub><b>Allenator</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=Allenator" title="Documentation">📖</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
@@ -332,6 +338,19 @@ Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/d
|
||||
<td align="center" valign="top" width="14.28%"><a href="http://kapocsi.ca"><img src="https://avatars.githubusercontent.com/u/84490604?v=4?s=100" width="100px;" alt="Thomas Kapocsi"/><br /><sub><b>Thomas Kapocsi</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=Kapocsi" title="Documentation">📖</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://dylhack.dev/"><img src="https://avatars.githubusercontent.com/u/27179786?v=4?s=100" width="100px;" alt="Dylan Hackworth"/><br /><sub><b>Dylan Hackworth</b></sub></a><br /><a href="#financial-dylhack" title="Financial">💵</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/echo304"><img src="https://avatars.githubusercontent.com/u/16456651?v=4?s=100" width="100px;" alt="Sangboak Lee"/><br /><sub><b>Sangboak Lee</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=echo304" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/qyecst"><img src="https://avatars.githubusercontent.com/u/13901864?v=4?s=100" width="100px;" alt="qyecst"/><br /><sub><b>qyecst</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=qyecst" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/DehanLUO"><img src="https://avatars.githubusercontent.com/u/53093688?v=4?s=100" width="100px;" alt="Han"/><br /><sub><b>Han</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=DehanLUO" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/wljince007"><img src="https://avatars.githubusercontent.com/u/88243938?v=4?s=100" width="100px;" alt="wljince007"/><br /><sub><b>wljince007</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=wljince007" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/FeroTheFox"><img src="https://avatars.githubusercontent.com/u/52982404?v=4?s=100" width="100px;" alt="fero"/><br /><sub><b>fero</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=FeroTheFox" title="Code">💻</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://siebsie23.nl/"><img src="https://avatars.githubusercontent.com/u/25083973?v=4?s=100" width="100px;" alt="Sibren"/><br /><sub><b>Sibren</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=siebsie23" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://www.nathaniel-walser.com"><img src="https://avatars.githubusercontent.com/u/33339996?v=4?s=100" width="100px;" alt="Nathaniel Walser"/><br /><sub><b>Nathaniel Walser</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=nwalser" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/aaronhuggins"><img src="https://avatars.githubusercontent.com/u/16567111?v=4?s=100" width="100px;" alt="Aaron Huggins"/><br /><sub><b>Aaron Huggins</b></sub></a><br /><a href="#design-aaronhuggins" title="Design">🎨</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://zkxdex.github.io/"><img src="https://avatars.githubusercontent.com/u/66271780?v=4?s=100" width="100px;" alt="KDex"/><br /><sub><b>KDex</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=zKXDEX" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/kimbob13"><img src="https://avatars.githubusercontent.com/u/26755098?v=4?s=100" width="100px;" alt="ChangHwan Kim"/><br /><sub><b>ChangHwan Kim</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=kimbob13" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/ashneilson"><img src="https://avatars.githubusercontent.com/u/35913512?v=4?s=100" width="100px;" alt="Ash Neilson"/><br /><sub><b>Ash Neilson</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=ashneilson" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/cfs4819"><img src="https://avatars.githubusercontent.com/u/53071761?v=4?s=100" width="100px;" alt="Chen Fansong"/><br /><sub><b>Chen Fansong</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=cfs4819" title="Code">💻</a></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
363
README.pl-PL.md
Normal file
363
README.pl-PL.md
Normal file
@@ -0,0 +1,363 @@
|
||||
[](https://tabby.sh)
|
||||
|
||||
|
||||
<p align="center">
|
||||
<a href="https://github.com/Eugeny/tabby/releases/latest"><img alt="Wszystkie wydania na GitHubie" src="https://img.shields.io/github/downloads/eugeny/tabby/total.svg?label=POBRANIA&logo=github&style=for-the-badge"></a> <a href="https://nightly.link/Eugeny/tabby/workflows/build/master"><img src="https://shields.io/badge/-Nightly%20Builds-orange?logo=hackthebox&logoColor=fff&style=for-the-badge"/></a> <a href="https://matrix.to/#/#tabby-general:matrix.org"><img alt="Matrix" src="https://img.shields.io/matrix/tabby-general:matrix.org?logo=matrix&style=for-the-badge&color=magenta"></a>   <a href="https://translate.tabby.sh/"><img alt="Przetłumacz" src="https://shields.io/badge/Translate-UI-white?logo=googletranslate&style=for-the-badge&color=white&logoColor=fff"></a> <a href="https://twitter.com/eugeeeeny"><img alt="Twitter" src="https://shields.io/badge/Subscribe-News-blue?logo=twitter&style=for-the-badge&color=blue"></a>
|
||||
</p>
|
||||
|
||||
<p align="center">
|
||||
<a href="https://ko-fi.com/J3J8KWTF">
|
||||
<img src="https://cdn.ko-fi.com/cdn/kofi3.png?v=2" width="150">
|
||||
</a>
|
||||
</p>
|
||||
|
||||
---
|
||||
|
||||
|
||||
> 👋 Zarządzasz zdalnymi środowiskami? Rzuć okiem na [WarpGate, inteligentny serwer typu bastion SSH/HTTP/MySQL](https://github.com/warp-tech/warpgate), świetnie współdziała z Tabby, pokochasz go!
|
||||
|
||||
> 👋 [Tabby-Web](https://github.com/Eugeny/tabby-web) poszukuje sponsorów. Nie jestem w stanie pokryć kosztów hostowania całej infrastruktury, jeśli jesteś zainteresowany wsparciem, proszę [skontakuj się ze mną!](https://twitter.com/eugeeeeny)
|
||||
|
||||
|
||||
----
|
||||
|
||||
### Pobieranie:
|
||||
|
||||
* [Ostatnie wydania](https://github.com/Eugeny/tabby/releases/latest)
|
||||
* [Repozytoria](https://packagecloud.io/eugeny/tabby): [Systemy Debian/Ubuntu](https://packagecloud.io/eugeny/tabby/install#bash-deb), [Środowiska RPM](https://packagecloud.io/eugeny/tabby/install#bash-rpm)
|
||||
* [Ostatnie wydania developerskie](https://nightly.link/Eugeny/tabby/workflows/build/master)
|
||||
|
||||
<br/>
|
||||
<p align="center">
|
||||
Ten plik README jest również dostępny w językach: <a href="./README.md">:gb: English</a> · <a href="./README.es-ES.md">:es: Spanish</a> · <a href="./README.ru-RU.md">:ru: Русский</a> · <a href="./README.ko-KR.md">:kr: 한국어</a> · <a href="./README.zh-CN.md">:cn: 简体中文</a> · <a href="./README.it-IT.md">:it: Italiano</a> · <a href="./README.de-DE.md">:de: Deutsch</a> · <a href="./README.ja-JP.md">:jp: 日本語</a> · <a href="./README.id-ID.md">:id: Bahasa Indonesia</a> · <a href="./README.pt-BR.md">🇧🇷 Português</a>
|
||||
</p>
|
||||
|
||||
----
|
||||
|
||||
[**Tabby**](https://tabby.sh) (formalnie **Terminus**) to wysoce konfigurowalny emulator konsoli, SSH oraz klienta konsoli szeregowej na systemy Windows 10, macOS oraz Linux
|
||||
|
||||
* Zintegrowany klient SSH i Telnet oraz menedżer sesji
|
||||
* Zintegrowany klient terminala szeregowego
|
||||
* Motywy and palety kolorów
|
||||
* W pełni konfigurowalne skróty klawiszowe
|
||||
* Dzielenie ekranu
|
||||
* Zapamiętywanie okien z poprzednich sesji
|
||||
* PowerShell (oraz PS Core), WSL, Git-Bash, Cygwin, MSYS2, Cmder i wsparcie dla CMD
|
||||
* Bezpośredni transfer plików sesji SSH przez Zmodem
|
||||
* Pełne wsparcie dla znaków Unicode wraz z podwójnymi znakami
|
||||
* Nie zawieszanie się przy szybko wyświetlanych wynikach
|
||||
* Pełne doświadczenie powłoki na systemie Windows zawierającej podpowiedzi (przez Clink)
|
||||
* Zintegrowany zaszyfrowany kontener na klucze SSH i jego konfigurację
|
||||
* Klient SSH, SFTP oraz Telnet dostępny jako [aplikacja webowa](https://tabby.sh/app) (również jako [własna instacja](https://github.com/Eugeny/tabby-web)).
|
||||
|
||||
# Spis treści <!-- omit in toc -->
|
||||
|
||||
- [Czym jest, a czym nie jest Tabby](#what-tabby-is-and-isnt)
|
||||
- [Funkcje konsoli](#terminal-features)
|
||||
- [Klient SSH](#ssh-client)
|
||||
- [Konsola szeregowa](#serial-terminal)
|
||||
- [Wersja przenośna](#portable)
|
||||
- [Wtyczki](#plugins)
|
||||
- [Motywy i palety kolorów](#themes)
|
||||
- [Współtworzenie](#contributing)
|
||||
|
||||
<a name="about"></a>
|
||||
|
||||
# Czym jest, a czym nie jest Tabby
|
||||
|
||||
* **Tabby jest** alternatywą dla standardowej konsoli Windows (conhost), PowerShell ISE, PuTTY, Terminal.app oraz iTerm z macOS
|
||||
|
||||
* **Tabby nie jest** nową powłoką lub zamiennikiem dla MinGW czy Cygwin. Nie jest również zatrważająco szybki - jeśli ważne jest dla Ciebie użycie pamięci RAM, rozważ użycie [Conemu](https://conemu.github.io) lub [Alacritty](https://github.com/jwilm/alacritty)
|
||||
|
||||
<a name="terminal"></a>
|
||||
|
||||
# Funkcje konsoli
|
||||
|
||||

|
||||
|
||||
* Konsola V220 + wiele rozszerzeń
|
||||
* Wiele nakładających się podzielonych okien
|
||||
* Okna na każdej stronie ekranu
|
||||
* Opcjonalne dokowanie okna za pomocą skrótu ("Quake console")
|
||||
* Wykrywanie postępu (Pasek)
|
||||
* Powiadomienia przy ukończeniu procesu podczas postępu
|
||||
* Wklejanie z nawiasami, ostrzeżenie przy wielu liniach
|
||||
* Wsparcie różnych czcionek
|
||||
* Niestandardowe profile powłoki
|
||||
* Opcjonalne wklejanie PPM oraz kopiowanie na zaznaczeniu (Styl PuTTY)
|
||||
|
||||
<a name="ssh"></a>
|
||||
|
||||
# Klient SSH
|
||||
|
||||

|
||||
|
||||
* Klient SSH2 z zarządzaniem połączeń
|
||||
* X11 oraz przekierowywanie portów
|
||||
* Automatyczne przejście między hostami
|
||||
* Przekierowanie agenta (Pageant oraz Windowsowy natywny "OpenSSH Agent")
|
||||
* Skrypty logowania
|
||||
|
||||
<a name="serial"></a>
|
||||
|
||||
# Konsola Szeregowa
|
||||
|
||||
* Zapisane połączenia
|
||||
* Wczytywanie danych wejścia linii
|
||||
* Opcjonalna konwersja danych wejścia i wyjścia na szesnastkowe "byte-by-byte"
|
||||
* Konwersja na nową linię
|
||||
* Automatyczne połączenie po rozłączeniu
|
||||
|
||||
<a name="portable"></a>
|
||||
|
||||
# Wersja przenośna
|
||||
|
||||
Tabby będzie uruchamiał się jako aplikacja przenośna, tylko wtedy, kiedy utworzysz folder `data` w tej samej lokacji, w której znajduje się `Tabby.exe`.
|
||||
|
||||
<a name="plugins"></a>
|
||||
|
||||
# Wtyczki
|
||||
|
||||
Wtyczki (jak i motywy) mogą być instalowane bezpośrednio z widoku ustawień w środku aplikacji Tabby.
|
||||
|
||||
* [docker](https://github.com/Eugeny/tabby-docker) - połączenie z kontenerami Docker
|
||||
* [title-control](https://github.com/kbjr/terminus-title-control) - pozwala na zmienianie tytułu konsoli jako prefiks, sufiks lub/albo tekst do usunięcia
|
||||
* [quick-cmds](https://github.com/Domain/terminus-quick-cmds) - szybko wysyłaj komendy z jednej konsoli do wielu
|
||||
* [save-output](https://github.com/Eugeny/tabby-save-output) - zapisuj dane wyjściowe do pliku
|
||||
* [sync-config](https://github.com/starxg/terminus-sync-config) - synchronizuj konfigurację przez Gista lub Gitee
|
||||
* [clippy](https://github.com/Eugeny/tabby-clippy) - przykładowa wtyczka, która zwyczajnie denerwuje
|
||||
* [workspace-manager](https://github.com/composer404/tabby-workspace-manager) - pozwala na utworzenie niestandardowego profilu pracy w aplikacji odpowiednio do konfiguracji
|
||||
* [search-in-browser](https://github.com/composer404/tabby-search-in-browser) - otwiera domyślną przeglądarkę z zaznaczonym tekstem w oknie Tabby
|
||||
* [sftp-tab](https://github.com/wljince007/tabby-sftp-tab) - otwiera okno z połączeniem SFTP dla połączeń SSH jak SecureCRT
|
||||
* [background](https://github.com/moemoechu/tabby-background) - zmień tło Tabby oraz wiele więcej
|
||||
* [highlight](https://github.com/moemoechu/tabby-highlight) - Tabby terminal keyword highlight plugin
|
||||
* [web-auth-handler](https://github.com/Jazzmoon/tabby-web-auth-handler) - okienka autoryzacji wewnątrz konsoli (Zbudowany głównie pod autoryzację projektu Warpgate w przeglądarce)
|
||||
|
||||
<a name="themes"></a>
|
||||
|
||||
# Motywy i palety kolorów
|
||||
|
||||
* [hype](https://github.com/Eugeny/tabby-theme-hype) - Motyw zainspirowany konsolą "Hyper"
|
||||
* [relaxed](https://github.com/Relaxed-Theme/relaxed-terminal-themes#terminus) - Motyw "pełnej relaksacji"
|
||||
* [gruvbox](https://github.com/porkloin/terminus-theme-gruvbox) - Motyw zainspirowany konsolą "Hyper" (kolejny)
|
||||
* [windows10](https://www.npmjs.com/package/terminus-theme-windows10) - Motyw zainspirowany Microsoftem
|
||||
* [altair](https://github.com/yxuko/terminus-altair) - Motwy autorstwa Yacine Kanzari
|
||||
* [catppuccin](https://github.com/catppuccin/tabby) - Paleta pastelowa dla Tabby
|
||||
* [noctis](https://github.com/aaronhuggins/tabby-colors-noctis) - Paleta kolorów zainspirowana motywem Noctis z VS Code
|
||||
|
||||
# Sponsorzy <!-- omit in toc -->
|
||||
|
||||
[](https://packagecloud.io)
|
||||
|
||||
[**packagecloud**](https://packagecloud.io) zapewnia darmowe utrzymanie repozytorium Debian/RPM
|
||||
|
||||
[](https://keygen.sh/?via=eugene)
|
||||
|
||||
[**keygen**](https://keygen.sh/?via=eugene) zapewnia darmowe wydawanie oraz automatycznie utrzymywanie strony
|
||||
|
||||
<a name="contributing"></a>
|
||||
# Współtworzenie
|
||||
|
||||
Pull requesty and dodawanie nowych wtyczek jest mile widziane!
|
||||
|
||||
Zobacz plik [HAKOWANIE.md](https://github.com/Eugeny/tabby/blob/master/HACKING.md) oraz [Dokumentację API](https://docs.tabby.sh/), aby poznać, jak projekt jest prowadzony wraz ze wstępnym poradnikiem jak tworzyć wtyczki.
|
||||
|
||||
---
|
||||
<a name="contributors"></a>
|
||||
|
||||
Dziękujemy wszystkim osobom współtworzącym ten projekt ([emotki są specjalizacją](https://allcontributors.org/docs/en/emoji-key)):
|
||||
|
||||
<!-- ALL-CONTRIBUTORS-LIST:START - Do not remove or modify this section -->
|
||||
<!-- prettier-ignore-start -->
|
||||
<!-- markdownlint-disable -->
|
||||
<table>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td align="center" valign="top" width="14.28%"><a href="http://www.russellmyers.com"><img src="https://avatars2.githubusercontent.com/u/184085?v=4?s=100" width="100px;" alt="Russell Myers"/><br /><sub><b>Russell Myers</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=mezner" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="http://www.morwire.com"><img src="https://avatars1.githubusercontent.com/u/3991658?v=4?s=100" width="100px;" alt="Austin Warren"/><br /><sub><b>Austin Warren</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=ehwarren" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/Drachenkaetzchen"><img src="https://avatars1.githubusercontent.com/u/162974?v=4?s=100" width="100px;" alt="Felicia Hummel"/><br /><sub><b>Felicia Hummel</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=Drachenkaetzchen" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/mikemaccana"><img src="https://avatars2.githubusercontent.com/u/172594?v=4?s=100" width="100px;" alt="Mike MacCana"/><br /><sub><b>Mike MacCana</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=mikemaccana" title="Tests">⚠️</a> <a href="#design-mikemaccana" title="Design">🎨</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/yxuko"><img src="https://avatars1.githubusercontent.com/u/1786317?v=4?s=100" width="100px;" alt="Yacine Kanzari"/><br /><sub><b>Yacine Kanzari</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=yxuko" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/BBJip"><img src="https://avatars2.githubusercontent.com/u/32908927?v=4?s=100" width="100px;" alt="BBJip"/><br /><sub><b>BBJip</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=BBJip" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/Futagirl"><img src="https://avatars2.githubusercontent.com/u/33533958?v=4?s=100" width="100px;" alt="Futagirl"/><br /><sub><b>Futagirl</b></sub></a><br /><a href="#design-Futagirl" title="Design">🎨</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://www.levrik.io"><img src="https://avatars3.githubusercontent.com/u/9491603?v=4?s=100" width="100px;" alt="Levin Rickert"/><br /><sub><b>Levin Rickert</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=levrik" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://kwonoj.github.io"><img src="https://avatars2.githubusercontent.com/u/1210596?v=4?s=100" width="100px;" alt="OJ Kwon"/><br /><sub><b>OJ Kwon</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=kwonoj" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/Domain"><img src="https://avatars2.githubusercontent.com/u/903197?v=4?s=100" width="100px;" alt="domain"/><br /><sub><b>domain</b></sub></a><br /><a href="#plugin-Domain" title="Plugin/utility libraries">🔌</a> <a href="https://github.com/Eugeny/tabby/commits?author=Domain" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="http://www.jbrumond.me"><img src="https://avatars1.githubusercontent.com/u/195127?v=4?s=100" width="100px;" alt="James Brumond"/><br /><sub><b>James Brumond</b></sub></a><br /><a href="#plugin-kbjr" title="Plugin/utility libraries">🔌</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="http://www.growingwiththeweb.com"><img src="https://avatars0.githubusercontent.com/u/2193314?v=4?s=100" width="100px;" alt="Daniel Imms"/><br /><sub><b>Daniel Imms</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=Tyriar" title="Code">💻</a> <a href="#plugin-Tyriar" title="Plugin/utility libraries">🔌</a> <a href="https://github.com/Eugeny/tabby/commits?author=Tyriar" title="Tests">⚠️</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/baflo"><img src="https://avatars2.githubusercontent.com/u/834350?v=4?s=100" width="100px;" alt="Florian Bachmann"/><br /><sub><b>Florian Bachmann</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=baflo" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="http://michael-kuehnel.de"><img src="https://avatars2.githubusercontent.com/u/441011?v=4?s=100" width="100px;" alt="Michael Kühnel"/><br /><sub><b>Michael Kühnel</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=mischah" title="Code">💻</a> <a href="#design-mischah" title="Design">🎨</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/NieLeben"><img src="https://avatars3.githubusercontent.com/u/47182955?v=4?s=100" width="100px;" alt="Tilmann Meyer"/><br /><sub><b>Tilmann Meyer</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=NieLeben" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="http://www.jubeat.net"><img src="https://avatars3.githubusercontent.com/u/11289158?v=4?s=100" width="100px;" alt="PM Extra"/><br /><sub><b>PM Extra</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/issues?q=author%3APMExtra" title="Bug reports">🐛</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://jjuhas.keybase.pub//"><img src="https://avatars1.githubusercontent.com/u/6438760?v=4?s=100" width="100px;" alt="Jonathan"/><br /><sub><b>Jonathan</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=IgnusG" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://hans-koch.me"><img src="https://avatars0.githubusercontent.com/u/1093709?v=4?s=100" width="100px;" alt="Hans Koch"/><br /><sub><b>Hans Koch</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=hammster" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="http://thepuzzlemaker.info"><img src="https://avatars3.githubusercontent.com/u/12666617?v=4?s=100" width="100px;" alt="Dak Smyth"/><br /><sub><b>Dak Smyth</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=ThePuzzlemaker" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="http://yfwz100.github.io"><img src="https://avatars2.githubusercontent.com/u/983211?v=4?s=100" width="100px;" alt="Wang Zhi"/><br /><sub><b>Wang Zhi</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=yfwz100" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/jack1142"><img src="https://avatars0.githubusercontent.com/u/6032823?v=4?s=100" width="100px;" alt="jack1142"/><br /><sub><b>jack1142</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=jack1142" title="Code">💻</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/hdougie"><img src="https://avatars1.githubusercontent.com/u/450799?v=4?s=100" width="100px;" alt="Howie Douglas"/><br /><sub><b>Howie Douglas</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=hdougie" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://chriskaczor.com"><img src="https://avatars2.githubusercontent.com/u/180906?v=4?s=100" width="100px;" alt="Chris Kaczor"/><br /><sub><b>Chris Kaczor</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=ckaczor" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://www.boxmein.net"><img src="https://avatars1.githubusercontent.com/u/358714?v=4?s=100" width="100px;" alt="Johannes Kadak"/><br /><sub><b>Johannes Kadak</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=boxmein" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/LeSeulArtichaut"><img src="https://avatars1.githubusercontent.com/u/38361244?v=4?s=100" width="100px;" alt="LeSeulArtichaut"/><br /><sub><b>LeSeulArtichaut</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=LeSeulArtichaut" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/CyrilTaylor"><img src="https://avatars0.githubusercontent.com/u/12631466?v=4?s=100" width="100px;" alt="Cyril Taylor"/><br /><sub><b>Cyril Taylor</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=CyrilTaylor" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/nstefanou"><img src="https://avatars3.githubusercontent.com/u/51129173?v=4?s=100" width="100px;" alt="nstefanou"/><br /><sub><b>nstefanou</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=nstefanou" title="Code">💻</a> <a href="#plugin-nstefanou" title="Plugin/utility libraries">🔌</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/orin220444"><img src="https://avatars3.githubusercontent.com/u/30747229?v=4?s=100" width="100px;" alt="orin220444"/><br /><sub><b>orin220444</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=orin220444" title="Code">💻</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/Goobles"><img src="https://avatars3.githubusercontent.com/u/8776771?v=4?s=100" width="100px;" alt="Gobius Dolhain"/><br /><sub><b>Gobius Dolhain</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=Goobles" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/3l0w"><img src="https://avatars2.githubusercontent.com/u/37798980?v=4?s=100" width="100px;" alt="Gwilherm Folliot"/><br /><sub><b>Gwilherm Folliot</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=3l0w" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/Dimitory"><img src="https://avatars0.githubusercontent.com/u/475955?v=4?s=100" width="100px;" alt="Dmitry Pronin"/><br /><sub><b>Dmitry Pronin</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=dimitory" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/JonathanBeverley"><img src="https://avatars1.githubusercontent.com/u/20328966?v=4?s=100" width="100px;" alt="Jonathan Beverley"/><br /><sub><b>Jonathan Beverley</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=JonathanBeverley" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/zend"><img src="https://avatars1.githubusercontent.com/u/25160?v=4?s=100" width="100px;" alt="Zenghai Liang"/><br /><sub><b>Zenghai Liang</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=zend" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://about.me/matishadow"><img src="https://avatars0.githubusercontent.com/u/9083085?v=4?s=100" width="100px;" alt="Mateusz Tracz"/><br /><sub><b>Mateusz Tracz</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=matishadow" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://zergpool.com"><img src="https://avatars3.githubusercontent.com/u/36234677?v=4?s=100" width="100px;" alt="pinpin"/><br /><sub><b>pinpin</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=pinpins" title="Code">💻</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/TakuroOnoda"><img src="https://avatars0.githubusercontent.com/u/1407926?v=4?s=100" width="100px;" alt="Takuro Onoda"/><br /><sub><b>Takuro Onoda</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=TakuroOnoda" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/frauhottelmann"><img src="https://avatars2.githubusercontent.com/u/902705?v=4?s=100" width="100px;" alt="frauhottelmann"/><br /><sub><b>frauhottelmann</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=frauhottelmann" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="http://patalong.pl"><img src="https://avatars.githubusercontent.com/u/29167842?v=4?s=100" width="100px;" alt="Piotr Patalong"/><br /><sub><b>Piotr Patalong</b></sub></a><br /><a href="#design-VectorKappa" title="Design">🎨</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/clarkwang"><img src="https://avatars.githubusercontent.com/u/157076?v=4?s=100" width="100px;" alt="Clark Wang"/><br /><sub><b>Clark Wang</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=clarkwang" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/iamchating"><img src="https://avatars.githubusercontent.com/u/7088153?v=4?s=100" width="100px;" alt="iamchating"/><br /><sub><b>iamchating</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=iamchating" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/starxg"><img src="https://avatars.githubusercontent.com/u/34997494?v=4?s=100" width="100px;" alt="starxg"/><br /><sub><b>starxg</b></sub></a><br /><a href="#plugin-starxg" title="Plugin/utility libraries">🔌</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="http://hashnote.net/"><img src="https://avatars.githubusercontent.com/u/546312?v=4?s=100" width="100px;" alt="Alisue"/><br /><sub><b>Alisue</b></sub></a><br /><a href="#design-lambdalisue" title="Design">🎨</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/ydcool"><img src="https://avatars.githubusercontent.com/u/5668295?v=4?s=100" width="100px;" alt="Dominic Yin"/><br /><sub><b>Dominic Yin</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=ydcool" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/bdr99"><img src="https://avatars.githubusercontent.com/u/2292715?v=4?s=100" width="100px;" alt="Brandon Rothweiler"/><br /><sub><b>Brandon Rothweiler</b></sub></a><br /><a href="#design-bdr99" title="Design">🎨</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://git.io/JnP49"><img src="https://avatars.githubusercontent.com/u/63876444?v=4?s=100" width="100px;" alt="Logic Machine"/><br /><sub><b>Logic Machine</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=logicmachine123" title="Documentation">📖</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/cypherbits"><img src="https://avatars.githubusercontent.com/u/10424900?v=4?s=100" width="100px;" alt="cypherbits"/><br /><sub><b>cypherbits</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=cypherbits" title="Documentation">📖</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://modulolotus.net"><img src="https://avatars.githubusercontent.com/u/946421?v=4?s=100" width="100px;" alt="Matthew Davidson"/><br /><sub><b>Matthew Davidson</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=KingMob" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/al-wi"><img src="https://avatars.githubusercontent.com/u/11092199?v=4?s=100" width="100px;" alt="Alexander Wiedemann"/><br /><sub><b>Alexander Wiedemann</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=al-wi" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://www.notion.so/3d45c6bd2cbd4f938873a4bd12e23375"><img src="https://avatars.githubusercontent.com/u/59506394?v=4?s=100" width="100px;" alt="장보연"/><br /><sub><b>장보연</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=BoYeonJang" title="Documentation">📖</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/Me1onRind"><img src="https://avatars.githubusercontent.com/u/19531270?v=4?s=100" width="100px;" alt="zZ"/><br /><sub><b>zZ</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=Me1onRind" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/tainoNZ"><img src="https://avatars.githubusercontent.com/u/49261322?v=4?s=100" width="100px;" alt="Aaron Davison"/><br /><sub><b>Aaron Davison</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=tainoNZ" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/composer404"><img src="https://avatars.githubusercontent.com/u/58251560?v=4?s=100" width="100px;" alt="Przemyslaw Kozik"/><br /><sub><b>Przemyslaw Kozik</b></sub></a><br /><a href="#design-composer404" title="Design">🎨</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/highfredo"><img src="https://avatars.githubusercontent.com/u/5951524?v=4?s=100" width="100px;" alt="Alfredo Arellano de la Fuente"/><br /><sub><b>Alfredo Arellano de la Fuente</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=highfredo" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/NessunKim"><img src="https://avatars.githubusercontent.com/u/12974079?v=4?s=100" width="100px;" alt="MH Kim"/><br /><sub><b>MH Kim</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=NessunKim" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://discord.gg/4c5EVTBhtp"><img src="https://avatars.githubusercontent.com/u/40345645?v=4?s=100" width="100px;" alt="Marmota"/><br /><sub><b>Marmota</b></sub></a><br /><a href="#design-jaimeadf" title="Design">🎨</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://ares.zone"><img src="https://avatars.githubusercontent.com/u/40336192?v=4?s=100" width="100px;" alt="Ares Andrew"/><br /><sub><b>Ares Andrew</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=TENX-S" title="Documentation">📖</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://usual.io/"><img src="https://avatars.githubusercontent.com/u/780052?v=4?s=100" width="100px;" alt="George Korsnick"/><br /><sub><b>George Korsnick</b></sub></a><br /><a href="#financial-gkor" title="Financial">💵</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://about.me/ulu"><img src="https://avatars.githubusercontent.com/u/872764?v=4?s=100" width="100px;" alt="Artem Smirnov"/><br /><sub><b>Artem Smirnov</b></sub></a><br /><a href="#financial-uluhonolulu" title="Financial">💵</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/nevotheless"><img src="https://avatars.githubusercontent.com/u/779797?v=4?s=100" width="100px;" alt="Tim Kopplow"/><br /><sub><b>Tim Kopplow</b></sub></a><br /><a href="#financial-nevotheless" title="Financial">💵</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/mrthock"><img src="https://avatars.githubusercontent.com/u/88901709?v=4?s=100" width="100px;" alt="mrthock"/><br /><sub><b>mrthock</b></sub></a><br /><a href="#financial-mrthock" title="Financial">💵</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/lrottach"><img src="https://avatars.githubusercontent.com/u/50323692?v=4?s=100" width="100px;" alt="Lukas Rottach"/><br /><sub><b>Lukas Rottach</b></sub></a><br /><a href="#financial-lrottach" title="Financial">💵</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/boonkerz"><img src="https://avatars.githubusercontent.com/u/277321?v=4?s=100" width="100px;" alt="boonkerz"/><br /><sub><b>boonkerz</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=boonkerz" title="Code">💻</a> <a href="#translation-boonkerz" title="Translation">🌍</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/milotype"><img src="https://avatars.githubusercontent.com/u/43657314?v=4?s=100" width="100px;" alt="Milo Ivir"/><br /><sub><b>Milo Ivir</b></sub></a><br /><a href="#translation-milotype" title="Translation">🌍</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/JasonCubic"><img src="https://avatars.githubusercontent.com/u/8921015?v=4?s=100" width="100px;" alt="JasonCubic"/><br /><sub><b>JasonCubic</b></sub></a><br /><a href="#design-JasonCubic" title="Design">🎨</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/MaxWaldorf"><img src="https://avatars.githubusercontent.com/u/15877853?v=4?s=100" width="100px;" alt="MaxWaldorf"/><br /><sub><b>MaxWaldorf</b></sub></a><br /><a href="#infra-MaxWaldorf" title="Infrastructure (Hosting, Build-Tools, etc)">🚇</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/mwz"><img src="https://avatars.githubusercontent.com/u/1190768?v=4?s=100" width="100px;" alt="Michael Wizner"/><br /><sub><b>Michael Wizner</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=mwz" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/mgrulich"><img src="https://avatars.githubusercontent.com/u/781036?v=4?s=100" width="100px;" alt="Martin"/><br /><sub><b>Martin</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=mgrulich" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/piersandro"><img src="https://avatars.githubusercontent.com/u/19996309?v=4?s=100" width="100px;" alt="Piersandro Guerrera"/><br /><sub><b>Piersandro Guerrera</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=piersandro" title="Documentation">📖</a> <a href="#translation-piersandro" title="Translation">🌍</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/0x973"><img src="https://avatars.githubusercontent.com/u/19320096?v=4?s=100" width="100px;" alt="0x973"/><br /><sub><b>0x973</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=0x973" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/Allenator"><img src="https://avatars.githubusercontent.com/u/11794943?v=4?s=100" width="100px;" alt="Allenator"/><br /><sub><b>Allenator</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=Allenator" title="Documentation">📖</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center" valign="top" width="14.28%"><a href="http://microhobby.com.br/blog"><img src="https://avatars.githubusercontent.com/u/2633321?v=4?s=100" width="100px;" alt="Matheus Castello"/><br /><sub><b>Matheus Castello</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=microhobby" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/Jai-JAP"><img src="https://avatars.githubusercontent.com/u/78354625?v=4?s=100" width="100px;" alt="Jai A P"/><br /><sub><b>Jai A P</b></sub></a><br /><a href="#platform-Jai-JAP" title="Packaging/porting to new platform">📦</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://blog.ysc3839.com"><img src="https://avatars.githubusercontent.com/u/12028138?v=4?s=100" width="100px;" alt="Richard Yu"/><br /><sub><b>Richard Yu</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=ysc3839" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/artu-ole"><img src="https://avatars.githubusercontent.com/u/15938416?v=4?s=100" width="100px;" alt="artu-ole"/><br /><sub><b>artu-ole</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=artu-ole" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://timagribanov.github.io/"><img src="https://avatars.githubusercontent.com/u/48593815?v=4?s=100" width="100px;" alt="Timofey Gribanov"/><br /><sub><b>Timofey Gribanov</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=TimaGribanov" title="Documentation">📖</a> <a href="#translation-TimaGribanov" title="Translation">🌍</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://git.christianbingman.com"><img src="https://avatars.githubusercontent.com/u/42191425?v=4?s=100" width="100px;" alt="Christian Bingman"/><br /><sub><b>Christian Bingman</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=ChristianBingman" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="http://zhangzhipeng2023.cn/"><img src="https://avatars.githubusercontent.com/u/5310853?v=4?s=100" width="100px;" alt="zhipeng"/><br /><sub><b>zhipeng</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=Ox0400" title="Code">💻</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/woodmeal"><img src="https://avatars.githubusercontent.com/u/104011197?v=4?s=100" width="100px;" alt="woodmeal"/><br /><sub><b>woodmeal</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=woodmeal" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://magiclike.codeberg.page/"><img src="https://avatars.githubusercontent.com/u/82117109?v=4?s=100" width="100px;" alt="MagicLike"/><br /><sub><b>MagicLike</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=MagicLike" title="Documentation">📖</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/hisamafahri"><img src="https://avatars.githubusercontent.com/u/65691613?v=4?s=100" width="100px;" alt="Hisam Fahri"/><br /><sub><b>Hisam Fahri</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=hisamafahri" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://liangchengj.com"><img src="https://avatars.githubusercontent.com/u/48881023?v=4?s=100" width="100px;" alt="Liangcheng Juves"/><br /><sub><b>Liangcheng Juves</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=LiangchengJ" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/attet"><img src="https://avatars.githubusercontent.com/u/1911416?v=4?s=100" width="100px;" alt="Atte Timonen"/><br /><sub><b>Atte Timonen</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=attet" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://www.linkedin.com/in/joaolmpinto/"><img src="https://avatars.githubusercontent.com/u/1143125?v=4?s=100" width="100px;" alt="João Pinto"/><br /><sub><b>João Pinto</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=joaompinto" title="Documentation">📖</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/Qiming-Liu"><img src="https://avatars.githubusercontent.com/u/68600416?v=4?s=100" width="100px;" alt="Alan"/><br /><sub><b>Alan</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=Qiming-Liu" title="Code">💻</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://74th.tech/"><img src="https://avatars.githubusercontent.com/u/1060011?v=4?s=100" width="100px;" alt="Atsushi Morimoto"/><br /><sub><b>Atsushi Morimoto</b></sub></a><br /><a href="#financial-74th" title="Financial">💵</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://arles.red/"><img src="https://avatars.githubusercontent.com/u/5369096?v=4?s=100" width="100px;" alt="Arles"/><br /><sub><b>Arles</b></sub></a><br /><a href="#financial-aarles" title="Financial">💵</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://pentestbook.six2dez.com/"><img src="https://avatars.githubusercontent.com/u/24670991?v=4?s=100" width="100px;" alt="six2dez"/><br /><sub><b>six2dez</b></sub></a><br /><a href="#financial-six2dez" title="Financial">💵</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/CandiceJoy"><img src="https://avatars.githubusercontent.com/u/8854890?v=4?s=100" width="100px;" alt="Candice"/><br /><sub><b>Candice</b></sub></a><br /><a href="#financial-CandiceJoy" title="Financial">💵</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/kingrowen"><img src="https://avatars.githubusercontent.com/u/13178700?v=4?s=100" width="100px;" alt="Rowen Willabus"/><br /><sub><b>Rowen Willabus</b></sub></a><br /><a href="#financial-kingrowen" title="Financial">💵</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://hengy1.top/"><img src="https://avatars.githubusercontent.com/u/98681454?v=4?s=100" width="100px;" alt="HengY1Coding✨"/><br /><sub><b>HengY1Coding✨</b></sub></a><br /><a href="#financial-HengY1Sky" title="Financial">💵</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/FrancisHG"><img src="https://avatars.githubusercontent.com/u/1611626?v=4?s=100" width="100px;" alt="Francis Gelderloos"/><br /><sub><b>Francis Gelderloos</b></sub></a><br /><a href="#financial-FrancisHG" title="Financial">💵</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/astromasoud"><img src="https://avatars.githubusercontent.com/u/18737721?v=4?s=100" width="100px;" alt="astromasoud"/><br /><sub><b>astromasoud</b></sub></a><br /><a href="#financial-astromasoud" title="Financial">💵</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://spirit55555.dk/"><img src="https://avatars.githubusercontent.com/u/2357565?v=4?s=100" width="100px;" alt="Anders G. Jørgensen"/><br /><sub><b>Anders G. Jørgensen</b></sub></a><br /><a href="#financial-Spirit55555" title="Financial">💵</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/djradon"><img src="https://avatars.githubusercontent.com/u/5224156?v=4?s=100" width="100px;" alt="Dave Richardson"/><br /><sub><b>Dave Richardson</b></sub></a><br /><a href="#financial-djradon" title="Financial">💵</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://twitter.com/tpberntsen"><img src="https://avatars.githubusercontent.com/u/922318?v=4?s=100" width="100px;" alt="Thomas Peter Berntsen"/><br /><sub><b>Thomas Peter Berntsen</b></sub></a><br /><a href="#financial-tpberntsen" title="Financial">💵</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://bandism.net/"><img src="https://avatars.githubusercontent.com/u/22633385?v=4?s=100" width="100px;" alt="Ikko Ashimine"/><br /><sub><b>Ikko Ashimine</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=eltociear" title="Documentation">📖</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/giejqf"><img src="https://avatars.githubusercontent.com/u/9211230?v=4?s=100" width="100px;" alt="giejqf"/><br /><sub><b>giejqf</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=giejqf" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/LacazeThomas"><img src="https://avatars.githubusercontent.com/u/19855907?v=4?s=100" width="100px;" alt="Thomas LACAZE"/><br /><sub><b>Thomas LACAZE</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=LacazeThomas" title="Code">💻</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://pochen.me/"><img src="https://avatars.githubusercontent.com/u/1329716?v=4?s=100" width="100px;" alt="Po Chen"/><br /><sub><b>Po Chen</b></sub></a><br /><a href="#financial-princemaple" title="Financial">💵</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://victorchandra.carrd.co/"><img src="https://avatars.githubusercontent.com/u/41635105?v=4?s=100" width="100px;" alt="Victor Chandra"/><br /><sub><b>Victor Chandra</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=mzmznasipadang" title="Documentation">📖</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/daniel347x"><img src="https://avatars.githubusercontent.com/u/309746?v=4?s=100" width="100px;" alt="Dan Nissenbaum"/><br /><sub><b>Dan Nissenbaum</b></sub></a><br /><a href="#financial-daniel347x" title="Financial">💵</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/DunklerPhoenix"><img src="https://avatars.githubusercontent.com/u/1261305?v=4?s=100" width="100px;" alt="RogueThorn"/><br /><sub><b>RogueThorn</b></sub></a><br /><a href="#financial-DunklerPhoenix" title="Financial">💵</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="http://spenserblack.github.io"><img src="https://avatars.githubusercontent.com/u/8546709?v=4?s=100" width="100px;" alt="Spenser Black"/><br /><sub><b>Spenser Black</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=spenserblack" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/zuedev"><img src="https://avatars.githubusercontent.com/u/24614929?v=4?s=100" width="100px;" alt="Alex"/><br /><sub><b>Alex</b></sub></a><br /><a href="#financial-zuedev" title="Financial">💵</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://hengy1.top/"><img src="https://avatars.githubusercontent.com/u/98681454?v=4?s=100" width="100px;" alt="HengY1Coding✨"/><br /><sub><b>HengY1Coding✨</b></sub></a><br /><a href="#financial-HengY1Cola" title="Financial">💵</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://www.stackscale.com/"><img src="https://avatars.githubusercontent.com/u/195768?v=4?s=100" width="100px;" alt="David Carrero"/><br /><sub><b>David Carrero</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=dcarrero" title="Documentation">📖</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/zhoro"><img src="https://avatars.githubusercontent.com/u/1105687?v=4?s=100" width="100px;" alt="Andrii Zhovtiak"/><br /><sub><b>Andrii Zhovtiak</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=zhoro" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/JohnMasoner"><img src="https://avatars.githubusercontent.com/u/42313377?v=4?s=100" width="100px;" alt="Mason Ma"/><br /><sub><b>Mason Ma</b></sub></a><br /><a href="#financial-JohnMasoner" title="Financial">💵</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/ntimo"><img src="https://avatars.githubusercontent.com/u/6145026?v=4?s=100" width="100px;" alt="Timo"/><br /><sub><b>Timo</b></sub></a><br /><a href="#financial-ntimo" title="Financial">💵</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://www.linkedin.com/in/evinwatson/"><img src="https://avatars.githubusercontent.com/u/24227251?v=4?s=100" width="100px;" alt="Evin Watson"/><br /><sub><b>Evin Watson</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=EvinRWatson" title="Documentation">📖</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://t.me/hendrjl"><img src="https://avatars.githubusercontent.com/u/15981200?v=4?s=100" width="100px;" alt="Hendra Juli"/><br /><sub><b>Hendra Juli</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=deulizealand" title="Documentation">📖</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/wkricowski"><img src="https://avatars.githubusercontent.com/u/36803521?v=4?s=100" width="100px;" alt="Wellinton Kricowski"/><br /><sub><b>Wellinton Kricowski</b></sub></a><br /><a href="#financial-wkricowski" title="Financial">💵</a> <a href="https://github.com/Eugeny/tabby/commits?author=wkricowski" title="Documentation">📖</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/almzau"><img src="https://avatars.githubusercontent.com/u/29115846?v=4?s=100" width="100px;" alt="Allan"/><br /><sub><b>Allan</b></sub></a><br /><a href="#design-almzau" title="Design">🎨</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://oidamo.de"><img src="https://avatars.githubusercontent.com/u/17959794?v=4?s=100" width="100px;" alt="Benjamin Brandmeier"/><br /><sub><b>Benjamin Brandmeier</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=BenjaminBrandmeier" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/patric1025"><img src="https://avatars.githubusercontent.com/u/65654040?v=4?s=100" width="100px;" alt="patric1025"/><br /><sub><b>patric1025</b></sub></a><br /><a href="#translation-patric1025" title="Translation">🌍</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/hermitpopcorn"><img src="https://avatars.githubusercontent.com/u/16042129?v=4?s=100" width="100px;" alt="hermitpopcorn"/><br /><sub><b>hermitpopcorn</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=hermitpopcorn" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://joshuatz.com/"><img src="https://avatars.githubusercontent.com/u/17817563?v=4?s=100" width="100px;" alt="Joshua Tzucker"/><br /><sub><b>Joshua Tzucker</b></sub></a><br /><a href="#financial-joshuatz" title="Financial">💵</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/luxifr"><img src="https://avatars.githubusercontent.com/u/665715?v=4?s=100" width="100px;" alt="luxifr"/><br /><sub><b>luxifr</b></sub></a><br /><a href="#financial-luxifr" title="Financial">💵</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/ukulanne"><img src="https://avatars.githubusercontent.com/u/28586666?v=4?s=100" width="100px;" alt="Anne Summers"/><br /><sub><b>Anne Summers</b></sub></a><br /><a href="#financial-ukulanne" title="Financial">💵</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/Clem-Fern"><img src="https://avatars.githubusercontent.com/u/20025949?v=4?s=100" width="100px;" alt="Clem"/><br /><sub><b>Clem</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=Clem-Fern" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/elizabeth-dev"><img src="https://avatars.githubusercontent.com/u/13015727?v=4?s=100" width="100px;" alt="Elizabeth Martín Campos"/><br /><sub><b>Elizabeth Martín Campos</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=elizabeth-dev" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/siccous"><img src="https://avatars.githubusercontent.com/u/7812885?v=4?s=100" width="100px;" alt="Tomáš Hruška"/><br /><sub><b>Tomáš Hruška</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=siccous" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/karaketir16"><img src="https://avatars.githubusercontent.com/u/27349806?v=4?s=100" width="100px;" alt="Osman Karaketir"/><br /><sub><b>Osman Karaketir</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=karaketir16" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://www.gnomegarden.io/"><img src="https://avatars.githubusercontent.com/u/33667144?v=4?s=100" width="100px;" alt="Crypto Gnome"/><br /><sub><b>Crypto Gnome</b></sub></a><br /><a href="#financial-CryptoGnome" title="Financial">💵</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/rbukovansky"><img src="https://avatars.githubusercontent.com/u/1004491?v=4?s=100" width="100px;" alt="Richard Bukovansky"/><br /><sub><b>Richard Bukovansky</b></sub></a><br /><a href="#financial-rbukovansky" title="Financial">💵</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/pseudocc"><img src="https://avatars.githubusercontent.com/u/85104110?v=4?s=100" width="100px;" alt="catlas"/><br /><sub><b>catlas</b></sub></a><br /><a href="#financial-pseudocc" title="Financial">💵</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center" valign="top" width="14.28%"><a href="http://kapocsi.ca"><img src="https://avatars.githubusercontent.com/u/84490604?v=4?s=100" width="100px;" alt="Thomas Kapocsi"/><br /><sub><b>Thomas Kapocsi</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=Kapocsi" title="Documentation">📖</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://dylhack.dev/"><img src="https://avatars.githubusercontent.com/u/27179786?v=4?s=100" width="100px;" alt="Dylan Hackworth"/><br /><sub><b>Dylan Hackworth</b></sub></a><br /><a href="#financial-dylhack" title="Financial">💵</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/echo304"><img src="https://avatars.githubusercontent.com/u/16456651?v=4?s=100" width="100px;" alt="Sangboak Lee"/><br /><sub><b>Sangboak Lee</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=echo304" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/qyecst"><img src="https://avatars.githubusercontent.com/u/13901864?v=4?s=100" width="100px;" alt="qyecst"/><br /><sub><b>qyecst</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=qyecst" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/DehanLUO"><img src="https://avatars.githubusercontent.com/u/53093688?v=4?s=100" width="100px;" alt="Han"/><br /><sub><b>Han</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=DehanLUO" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/wljince007"><img src="https://avatars.githubusercontent.com/u/88243938?v=4?s=100" width="100px;" alt="wljince007"/><br /><sub><b>wljince007</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=wljince007" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/FeroTheFox"><img src="https://avatars.githubusercontent.com/u/52982404?v=4?s=100" width="100px;" alt="fero"/><br /><sub><b>fero</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=FeroTheFox" title="Code">💻</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://siebsie23.nl/"><img src="https://avatars.githubusercontent.com/u/25083973?v=4?s=100" width="100px;" alt="Sibren"/><br /><sub><b>Sibren</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=siebsie23" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://www.nathaniel-walser.com"><img src="https://avatars.githubusercontent.com/u/33339996?v=4?s=100" width="100px;" alt="Nathaniel Walser"/><br /><sub><b>Nathaniel Walser</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=nwalser" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/aaronhuggins"><img src="https://avatars.githubusercontent.com/u/16567111?v=4?s=100" width="100px;" alt="Aaron Huggins"/><br /><sub><b>Aaron Huggins</b></sub></a><br /><a href="#design-aaronhuggins" title="Design">🎨</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://zkxdex.github.io/"><img src="https://avatars.githubusercontent.com/u/66271780?v=4?s=100" width="100px;" alt="KDex"/><br /><sub><b>KDex</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=zKXDEX" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/kimbob13"><img src="https://avatars.githubusercontent.com/u/26755098?v=4?s=100" width="100px;" alt="ChangHwan Kim"/><br /><sub><b>ChangHwan Kim</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=kimbob13" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/ashneilson"><img src="https://avatars.githubusercontent.com/u/35913512?v=4?s=100" width="100px;" alt="Ash Neilson"/><br /><sub><b>Ash Neilson</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=ashneilson" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/cfs4819"><img src="https://avatars.githubusercontent.com/u/53071761?v=4?s=100" width="100px;" alt="Chen Fansong"/><br /><sub><b>Chen Fansong</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=cfs4819" title="Code">💻</a></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<!-- markdownlint-restore -->
|
||||
<!-- prettier-ignore-end -->
|
||||
|
||||
<!-- ALL-CONTRIBUTORS-LIST:END -->
|
||||
|
||||
Ten projekt podlega specyfikacji [dla współautorów](https://github.com/all-contributors/all-contributors). Wszelkiego rodzaju przyczynianie się do rozwoju jest tu mile widziane!
|
@@ -21,7 +21,7 @@
|
||||
|
||||
<br/>
|
||||
<p align="center">
|
||||
Esse README também está disponível em: <a href="./README.md">:gb: English</a> · <a href="./README.es-ES.md">:es: Spanish</a> · <a href="./README.ru-RU.md">:ru: Русский</a> · <a href="./README.ko-KR.md">:kr: 한국어</a> · <a href="./README.zh-CN.md">:cn: 简体中文</a> · <a href="./README.it-IT.md">:it: Italiano</a> · <a href="./README.de-DE.md">:de: Deutsch</a> · <a href="./README.ja-JP.md">:jp: 日本語</a> · <a href="./README.id-ID.md">:id: Bahasa Indonesia</a>
|
||||
Esse README também está disponível em: <a href="./README.md">:gb: English</a> · <a href="./README.es-ES.md">:es: Spanish</a> · <a href="./README.ru-RU.md">:ru: Русский</a> · <a href="./README.ko-KR.md">:kr: 한국어</a> · <a href="./README.zh-CN.md">:cn: 简体中文</a> · <a href="./README.it-IT.md">:it: Italiano</a> · <a href="./README.de-DE.md">:de: Deutsch</a> · <a href="./README.ja-JP.md">:jp: 日本語</a> · <a href="./README.id-ID.md">:id: Bahasa Indonesia</a> · <a href="./README.pl-PL.md">:poland: Polski</a>
|
||||
</p>
|
||||
|
||||
----
|
||||
@@ -120,6 +120,7 @@ Plugins e temas podem ser instalados durante a execução na pagina de configura
|
||||
* [clippy](https://github.com/Eugeny/tabby-clippy) - um plugin de exemplo que te incomoda o tempo todo
|
||||
* [workspace-manager](https://github.com/composer404/tabby-workspace-manager) - permite criar perfis de espaço de trabalho personalizados com base na configuração fornecida
|
||||
* [search-in-browser](https://github.com/composer404/tabby-search-in-browser) - abre o navegador padrão do sistema com um texto selecionado na guia do Tabby
|
||||
* [sftp-tab](https://github.com/wljince007/tabby-sftp-tab) - open sftp tab for ssh connection like SecureCRT
|
||||
|
||||
<a name="themes"></a>
|
||||
|
||||
@@ -245,7 +246,7 @@ Obrigado vai para essas pessoas maravilhosas ([emoji key](https://allcontributor
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/mwz"><img src="https://avatars.githubusercontent.com/u/1190768?v=4?s=100" width="100px;" alt="Michael Wizner"/><br /><sub><b>Michael Wizner</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=mwz" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/mgrulich"><img src="https://avatars.githubusercontent.com/u/781036?v=4?s=100" width="100px;" alt="Martin"/><br /><sub><b>Martin</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=mgrulich" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/piersandro"><img src="https://avatars.githubusercontent.com/u/19996309?v=4?s=100" width="100px;" alt="Piersandro Guerrera"/><br /><sub><b>Piersandro Guerrera</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=piersandro" title="Documentation">📖</a> <a href="#translation-piersandro" title="Translation">🌍</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="http://pingbase.cn"><img src="https://avatars.githubusercontent.com/u/19320096?v=4?s=100" width="100px;" alt="X-0x01"/><br /><sub><b>X-0x01</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=X-0x01" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/0x973"><img src="https://avatars.githubusercontent.com/u/19320096?v=4?s=100" width="100px;" alt="0x973"/><br /><sub><b>0x973</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=0x973" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/Allenator"><img src="https://avatars.githubusercontent.com/u/11794943?v=4?s=100" width="100px;" alt="Allenator"/><br /><sub><b>Allenator</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=Allenator" title="Documentation">📖</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
@@ -324,6 +325,19 @@ Obrigado vai para essas pessoas maravilhosas ([emoji key](https://allcontributor
|
||||
<td align="center" valign="top" width="14.28%"><a href="http://kapocsi.ca"><img src="https://avatars.githubusercontent.com/u/84490604?v=4?s=100" width="100px;" alt="Thomas Kapocsi"/><br /><sub><b>Thomas Kapocsi</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=Kapocsi" title="Documentation">📖</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://dylhack.dev/"><img src="https://avatars.githubusercontent.com/u/27179786?v=4?s=100" width="100px;" alt="Dylan Hackworth"/><br /><sub><b>Dylan Hackworth</b></sub></a><br /><a href="#financial-dylhack" title="Financial">💵</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/echo304"><img src="https://avatars.githubusercontent.com/u/16456651?v=4?s=100" width="100px;" alt="Sangboak Lee"/><br /><sub><b>Sangboak Lee</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=echo304" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/qyecst"><img src="https://avatars.githubusercontent.com/u/13901864?v=4?s=100" width="100px;" alt="qyecst"/><br /><sub><b>qyecst</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=qyecst" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/DehanLUO"><img src="https://avatars.githubusercontent.com/u/53093688?v=4?s=100" width="100px;" alt="Han"/><br /><sub><b>Han</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=DehanLUO" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/wljince007"><img src="https://avatars.githubusercontent.com/u/88243938?v=4?s=100" width="100px;" alt="wljince007"/><br /><sub><b>wljince007</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=wljince007" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/FeroTheFox"><img src="https://avatars.githubusercontent.com/u/52982404?v=4?s=100" width="100px;" alt="fero"/><br /><sub><b>fero</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=FeroTheFox" title="Code">💻</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://siebsie23.nl/"><img src="https://avatars.githubusercontent.com/u/25083973?v=4?s=100" width="100px;" alt="Sibren"/><br /><sub><b>Sibren</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=siebsie23" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://www.nathaniel-walser.com"><img src="https://avatars.githubusercontent.com/u/33339996?v=4?s=100" width="100px;" alt="Nathaniel Walser"/><br /><sub><b>Nathaniel Walser</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=nwalser" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/aaronhuggins"><img src="https://avatars.githubusercontent.com/u/16567111?v=4?s=100" width="100px;" alt="Aaron Huggins"/><br /><sub><b>Aaron Huggins</b></sub></a><br /><a href="#design-aaronhuggins" title="Design">🎨</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://zkxdex.github.io/"><img src="https://avatars.githubusercontent.com/u/66271780?v=4?s=100" width="100px;" alt="KDex"/><br /><sub><b>KDex</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=zKXDEX" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/kimbob13"><img src="https://avatars.githubusercontent.com/u/26755098?v=4?s=100" width="100px;" alt="ChangHwan Kim"/><br /><sub><b>ChangHwan Kim</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=kimbob13" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/ashneilson"><img src="https://avatars.githubusercontent.com/u/35913512?v=4?s=100" width="100px;" alt="Ash Neilson"/><br /><sub><b>Ash Neilson</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=ashneilson" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/cfs4819"><img src="https://avatars.githubusercontent.com/u/53071761?v=4?s=100" width="100px;" alt="Chen Fansong"/><br /><sub><b>Chen Fansong</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=cfs4819" title="Code">💻</a></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
@@ -21,7 +21,7 @@
|
||||
|
||||
<br/>
|
||||
<p align="center">
|
||||
Этот README также доступен на: <a href="./README.md">:gb: English</a> · <a href="./README.es-ES.md">:es: Spanish</a> · <a href="./README.ko-KR.md">:kr: 한국어</a> · <a href="./README.zh-CN.md">:cn: 简体中文</a> · <a href="./README.it-IT.md">:it: Italiano</a> · <a href="./README.de-DE.md">:de: Deutsch</a> · <a href="./README.ja-JP.md">:jp: 日本語</a> · <a href="./README.id-ID.md">:id: Bahasa Indonesia</a> · <a href="./README.pt-BR.md">:br: Português</a>
|
||||
Этот README также доступен на: <a href="./README.md">:gb: English</a> · <a href="./README.es-ES.md">:es: Spanish</a> · <a href="./README.ko-KR.md">:kr: 한국어</a> · <a href="./README.zh-CN.md">:cn: 简体中文</a> · <a href="./README.it-IT.md">:it: Italiano</a> · <a href="./README.de-DE.md">:de: Deutsch</a> · <a href="./README.ja-JP.md">:jp: 日本語</a> · <a href="./README.id-ID.md">:id: Bahasa Indonesia</a> · <a href="./README.pt-BR.md">:brazil: Português</a> · <a href="./README.pl-PL.md">:poland: Polski</a>
|
||||
</p>
|
||||
|
||||
----
|
||||
@@ -117,6 +117,7 @@
|
||||
* [clippy](https://github.com/Eugeny/tabby-clippy) — плагин-пример, который постоянно будет вас бесить;
|
||||
* [workspace-manager](https://github.com/composer404/tabby-workspace-manager) — позволяет создавать пользовательские провили рабочего окружеиня на основе конфига;
|
||||
* [search-in-browser](https://github.com/composer404/tabby-search-in-browser) — открывает браузер по умолчанию с текстом, выделенном во вкладке Tabby.
|
||||
* [sftp-tab](https://github.com/wljince007/tabby-sftp-tab) - open sftp tab for ssh connection like SecureCRT
|
||||
|
||||
<a name="themes"></a>
|
||||
# Темы
|
||||
@@ -237,7 +238,7 @@ Pull-запросы и плагины приветствуются!
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/mwz"><img src="https://avatars.githubusercontent.com/u/1190768?v=4?s=100" width="100px;" alt="Michael Wizner"/><br /><sub><b>Michael Wizner</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=mwz" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/mgrulich"><img src="https://avatars.githubusercontent.com/u/781036?v=4?s=100" width="100px;" alt="Martin"/><br /><sub><b>Martin</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=mgrulich" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/piersandro"><img src="https://avatars.githubusercontent.com/u/19996309?v=4?s=100" width="100px;" alt="Piersandro Guerrera"/><br /><sub><b>Piersandro Guerrera</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=piersandro" title="Documentation">📖</a> <a href="#translation-piersandro" title="Translation">🌍</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="http://pingbase.cn"><img src="https://avatars.githubusercontent.com/u/19320096?v=4?s=100" width="100px;" alt="X-0x01"/><br /><sub><b>X-0x01</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=X-0x01" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/0x973"><img src="https://avatars.githubusercontent.com/u/19320096?v=4?s=100" width="100px;" alt="0x973"/><br /><sub><b>0x973</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=0x973" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/Allenator"><img src="https://avatars.githubusercontent.com/u/11794943?v=4?s=100" width="100px;" alt="Allenator"/><br /><sub><b>Allenator</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=Allenator" title="Documentation">📖</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
@@ -316,6 +317,19 @@ Pull-запросы и плагины приветствуются!
|
||||
<td align="center" valign="top" width="14.28%"><a href="http://kapocsi.ca"><img src="https://avatars.githubusercontent.com/u/84490604?v=4?s=100" width="100px;" alt="Thomas Kapocsi"/><br /><sub><b>Thomas Kapocsi</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=Kapocsi" title="Documentation">📖</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://dylhack.dev/"><img src="https://avatars.githubusercontent.com/u/27179786?v=4?s=100" width="100px;" alt="Dylan Hackworth"/><br /><sub><b>Dylan Hackworth</b></sub></a><br /><a href="#financial-dylhack" title="Financial">💵</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/echo304"><img src="https://avatars.githubusercontent.com/u/16456651?v=4?s=100" width="100px;" alt="Sangboak Lee"/><br /><sub><b>Sangboak Lee</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=echo304" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/qyecst"><img src="https://avatars.githubusercontent.com/u/13901864?v=4?s=100" width="100px;" alt="qyecst"/><br /><sub><b>qyecst</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=qyecst" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/DehanLUO"><img src="https://avatars.githubusercontent.com/u/53093688?v=4?s=100" width="100px;" alt="Han"/><br /><sub><b>Han</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=DehanLUO" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/wljince007"><img src="https://avatars.githubusercontent.com/u/88243938?v=4?s=100" width="100px;" alt="wljince007"/><br /><sub><b>wljince007</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=wljince007" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/FeroTheFox"><img src="https://avatars.githubusercontent.com/u/52982404?v=4?s=100" width="100px;" alt="fero"/><br /><sub><b>fero</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=FeroTheFox" title="Code">💻</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://siebsie23.nl/"><img src="https://avatars.githubusercontent.com/u/25083973?v=4?s=100" width="100px;" alt="Sibren"/><br /><sub><b>Sibren</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=siebsie23" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://www.nathaniel-walser.com"><img src="https://avatars.githubusercontent.com/u/33339996?v=4?s=100" width="100px;" alt="Nathaniel Walser"/><br /><sub><b>Nathaniel Walser</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=nwalser" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/aaronhuggins"><img src="https://avatars.githubusercontent.com/u/16567111?v=4?s=100" width="100px;" alt="Aaron Huggins"/><br /><sub><b>Aaron Huggins</b></sub></a><br /><a href="#design-aaronhuggins" title="Design">🎨</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://zkxdex.github.io/"><img src="https://avatars.githubusercontent.com/u/66271780?v=4?s=100" width="100px;" alt="KDex"/><br /><sub><b>KDex</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=zKXDEX" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/kimbob13"><img src="https://avatars.githubusercontent.com/u/26755098?v=4?s=100" width="100px;" alt="ChangHwan Kim"/><br /><sub><b>ChangHwan Kim</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=kimbob13" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/ashneilson"><img src="https://avatars.githubusercontent.com/u/35913512?v=4?s=100" width="100px;" alt="Ash Neilson"/><br /><sub><b>Ash Neilson</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=ashneilson" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/cfs4819"><img src="https://avatars.githubusercontent.com/u/53071761?v=4?s=100" width="100px;" alt="Chen Fansong"/><br /><sub><b>Chen Fansong</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=cfs4819" title="Code">💻</a></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
@@ -21,7 +21,7 @@
|
||||
|
||||
<br/>
|
||||
<p align="center">
|
||||
本 README 还适用于以下语言: <a href="./README.md">:gb: English</a> · <a href="./README.es-ES.md">:es: Spanish</a> · <a href="./README.ru-RU.md">:ru: Русский</a> · <a href="./README.ko-KR.md">:kr: 한국어</a> · <a href="./README.it-IT.md">:it: Italiano</a> · <a href="./README.de-DE.md">:de: Deutsch</a> · <a href="./README.ja-JP.md">:jp: 日本語</a> · <a href="./README.id-ID.md">:id: Bahasa Indonesia</a> · <a href="./README.pt-BR.md">:br: Português</a>
|
||||
本 README 还适用于以下语言: <a href="./README.md">:gb: English</a> · <a href="./README.es-ES.md">:es: Spanish</a> · <a href="./README.ru-RU.md">:ru: Русский</a> · <a href="./README.ko-KR.md">:kr: 한국어</a> · <a href="./README.it-IT.md">:it: Italiano</a> · <a href="./README.de-DE.md">:de: Deutsch</a> · <a href="./README.ja-JP.md">:jp: 日本語</a> · <a href="./README.id-ID.md">:id: Bahasa Indonesia</a> · <a href="./README.pt-BR.md">:brazil: Português</a> · <a href="./README.pl-PL.md">:poland: Polski</a>
|
||||
</p>
|
||||
|
||||
----
|
||||
@@ -116,6 +116,7 @@
|
||||
* [clippy](https://github.com/Eugeny/tabby-clippy) - 一个可以一直烦你的示例插件
|
||||
* [workspace-manager](https://github.com/composer404/tabby-workspace-manager) - 允许根据给定的配置创建自定义工作区配置文件
|
||||
* [search-in-browser](https://github.com/composer404/tabby-search-in-browser) - 从 Tabby 标签页带有选中的文本来打开系统默认浏览器
|
||||
* [sftp-tab](https://github.com/wljince007/tabby-sftp-tab) - 为ssh连接打开类似SecureCRT的sftp标签页
|
||||
|
||||
<a name="themes"></a>
|
||||
# 主题
|
||||
@@ -236,7 +237,7 @@
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/mwz"><img src="https://avatars.githubusercontent.com/u/1190768?v=4?s=100" width="100px;" alt="Michael Wizner"/><br /><sub><b>Michael Wizner</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=mwz" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/mgrulich"><img src="https://avatars.githubusercontent.com/u/781036?v=4?s=100" width="100px;" alt="Martin"/><br /><sub><b>Martin</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=mgrulich" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/piersandro"><img src="https://avatars.githubusercontent.com/u/19996309?v=4?s=100" width="100px;" alt="Piersandro Guerrera"/><br /><sub><b>Piersandro Guerrera</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=piersandro" title="Documentation">📖</a> <a href="#translation-piersandro" title="Translation">🌍</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="http://pingbase.cn"><img src="https://avatars.githubusercontent.com/u/19320096?v=4?s=100" width="100px;" alt="X-0x01"/><br /><sub><b>X-0x01</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=X-0x01" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/0x973"><img src="https://avatars.githubusercontent.com/u/19320096?v=4?s=100" width="100px;" alt="0x973"/><br /><sub><b>0x973</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=0x973" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/Allenator"><img src="https://avatars.githubusercontent.com/u/11794943?v=4?s=100" width="100px;" alt="Allenator"/><br /><sub><b>Allenator</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=Allenator" title="Documentation">📖</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
@@ -315,6 +316,19 @@
|
||||
<td align="center" valign="top" width="14.28%"><a href="http://kapocsi.ca"><img src="https://avatars.githubusercontent.com/u/84490604?v=4?s=100" width="100px;" alt="Thomas Kapocsi"/><br /><sub><b>Thomas Kapocsi</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=Kapocsi" title="Documentation">📖</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://dylhack.dev/"><img src="https://avatars.githubusercontent.com/u/27179786?v=4?s=100" width="100px;" alt="Dylan Hackworth"/><br /><sub><b>Dylan Hackworth</b></sub></a><br /><a href="#financial-dylhack" title="Financial">💵</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/echo304"><img src="https://avatars.githubusercontent.com/u/16456651?v=4?s=100" width="100px;" alt="Sangboak Lee"/><br /><sub><b>Sangboak Lee</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=echo304" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/qyecst"><img src="https://avatars.githubusercontent.com/u/13901864?v=4?s=100" width="100px;" alt="qyecst"/><br /><sub><b>qyecst</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=qyecst" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/DehanLUO"><img src="https://avatars.githubusercontent.com/u/53093688?v=4?s=100" width="100px;" alt="Han"/><br /><sub><b>Han</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=DehanLUO" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/wljince007"><img src="https://avatars.githubusercontent.com/u/88243938?v=4?s=100" width="100px;" alt="wljince007"/><br /><sub><b>wljince007</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=wljince007" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/FeroTheFox"><img src="https://avatars.githubusercontent.com/u/52982404?v=4?s=100" width="100px;" alt="fero"/><br /><sub><b>fero</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=FeroTheFox" title="Code">💻</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://siebsie23.nl/"><img src="https://avatars.githubusercontent.com/u/25083973?v=4?s=100" width="100px;" alt="Sibren"/><br /><sub><b>Sibren</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=siebsie23" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://www.nathaniel-walser.com"><img src="https://avatars.githubusercontent.com/u/33339996?v=4?s=100" width="100px;" alt="Nathaniel Walser"/><br /><sub><b>Nathaniel Walser</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=nwalser" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/aaronhuggins"><img src="https://avatars.githubusercontent.com/u/16567111?v=4?s=100" width="100px;" alt="Aaron Huggins"/><br /><sub><b>Aaron Huggins</b></sub></a><br /><a href="#design-aaronhuggins" title="Design">🎨</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://zkxdex.github.io/"><img src="https://avatars.githubusercontent.com/u/66271780?v=4?s=100" width="100px;" alt="KDex"/><br /><sub><b>KDex</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=zKXDEX" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/kimbob13"><img src="https://avatars.githubusercontent.com/u/26755098?v=4?s=100" width="100px;" alt="ChangHwan Kim"/><br /><sub><b>ChangHwan Kim</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=kimbob13" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/ashneilson"><img src="https://avatars.githubusercontent.com/u/35913512?v=4?s=100" width="100px;" alt="Ash Neilson"/><br /><sub><b>Ash Neilson</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=ashneilson" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/cfs4819"><img src="https://avatars.githubusercontent.com/u/53071761?v=4?s=100" width="100px;" alt="Chen Fansong"/><br /><sub><b>Chen Fansong</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=cfs4819" title="Code">💻</a></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
@@ -183,7 +183,7 @@ export class Application {
|
||||
}
|
||||
|
||||
enableTray (): void {
|
||||
if (this.tray || process.platform === 'linux') {
|
||||
if (!!this.tray || process.platform === 'linux') {
|
||||
return
|
||||
}
|
||||
if (process.platform === 'darwin') {
|
||||
|
@@ -28,6 +28,16 @@ export function parseArgs (argv: string[], cwd: string): any {
|
||||
.command('recent [index]', 'open a tab with a recent profile', {
|
||||
profileNumber: { type: 'number' },
|
||||
})
|
||||
.command('quickConnect <providerId> <query>', 'open a tab for specified quick connect provider', yargs => {
|
||||
return yargs.positional('providerId', {
|
||||
describe: 'The name of a quick connect profile provider',
|
||||
type: 'string',
|
||||
choices: ['ssh', 'telnet'],
|
||||
}).positional('query', {
|
||||
describe: 'The quick connect query string',
|
||||
type: 'string',
|
||||
})
|
||||
})
|
||||
.version(app.getVersion())
|
||||
.option('debug', {
|
||||
alias: 'd',
|
||||
|
@@ -1,13 +1,14 @@
|
||||
import * as fs from 'fs'
|
||||
import * as path from 'path'
|
||||
import * as yaml from 'js-yaml'
|
||||
import { app } from 'electron'
|
||||
import { writeFile } from 'atomically'
|
||||
|
||||
|
||||
export const configPath = path.join(process.env.TABBY_CONFIG_DIRECTORY!, 'config.yaml')
|
||||
const legacyConfigPath = path.join(process.env.TABBY_CONFIG_DIRECTORY!, '../terminus', 'config.yaml')
|
||||
|
||||
|
||||
export function migrateConfig (): void {
|
||||
const configPath = path.join(app.getPath('userData'), 'config.yaml')
|
||||
const legacyConfigPath = path.join(app.getPath('userData'), '../terminus', 'config.yaml')
|
||||
if (fs.existsSync(legacyConfigPath) && (
|
||||
!fs.existsSync(configPath) ||
|
||||
fs.statSync(configPath).mtime < fs.statSync(legacyConfigPath).mtime
|
||||
@@ -19,7 +20,6 @@ export function migrateConfig (): void {
|
||||
export function loadConfig (): any {
|
||||
migrateConfig()
|
||||
|
||||
const configPath = path.join(app.getPath('userData'), 'config.yaml')
|
||||
if (fs.existsSync(configPath)) {
|
||||
return yaml.load(fs.readFileSync(configPath, 'utf8'))
|
||||
} else {
|
||||
@@ -27,8 +27,6 @@ export function loadConfig (): any {
|
||||
}
|
||||
}
|
||||
|
||||
const configPath = path.join(app.getPath('userData'), 'config.yaml')
|
||||
|
||||
export async function saveConfig (content: string): Promise<void> {
|
||||
await writeFile(configPath, content, { encoding: 'utf8' })
|
||||
await writeFile(configPath + '.backup', content, { encoding: 'utf8' })
|
||||
|
@@ -1,17 +1,23 @@
|
||||
import 'v8-compile-cache'
|
||||
import { app, ipcMain, Menu, dialog } from 'electron'
|
||||
|
||||
// set userData Path on portable version
|
||||
import './portable'
|
||||
|
||||
// set defaults of environment variables
|
||||
import 'dotenv/config'
|
||||
process.env.TABBY_PLUGINS ??= ''
|
||||
process.env.TABBY_CONFIG_DIRECTORY ??= app.getPath('userData')
|
||||
|
||||
|
||||
import 'v8-compile-cache'
|
||||
import 'source-map-support/register'
|
||||
import './sentry'
|
||||
import './lru'
|
||||
import { app, ipcMain, Menu, dialog } from 'electron'
|
||||
import { parseArgs } from './cli'
|
||||
import { Application } from './app'
|
||||
import electronDebug = require('electron-debug')
|
||||
import { loadConfig } from './config'
|
||||
|
||||
if (!process.env.TABBY_PLUGINS) {
|
||||
process.env.TABBY_PLUGINS = ''
|
||||
}
|
||||
|
||||
const argv = parseArgs(process.argv, process.cwd())
|
||||
|
||||
|
@@ -1,4 +1,4 @@
|
||||
import * as nodePTY from '@tabby-gang/node-pty'
|
||||
import * as nodePTY from 'node-pty'
|
||||
import { v4 as uuidv4 } from 'uuid'
|
||||
import { ipcMain } from 'electron'
|
||||
import { Application } from './app'
|
||||
|
@@ -26,7 +26,7 @@ abstract class GlasstronWindow extends BrowserWindow {
|
||||
abstract setBlur (_: boolean)
|
||||
}
|
||||
|
||||
const macOSVibrancyType = process.platform === 'darwin' ? compareVersions(macOSRelease().version || '0.0', '10.14', '>=') ? 'under-window' : 'dark' : null
|
||||
const macOSVibrancyType: any = process.platform === 'darwin' ? compareVersions(macOSRelease().version || '0.0', '10.14', '>=') ? 'under-window' : 'dark' : null
|
||||
|
||||
const activityIcon = nativeImage.createFromPath(`${app.getAppPath()}/assets/activity.png`)
|
||||
|
||||
@@ -92,8 +92,11 @@ export class Window {
|
||||
if (this.configStore.appearance?.frame === 'native') {
|
||||
bwOptions.frame = true
|
||||
} else {
|
||||
if (process.platform === 'darwin') {
|
||||
bwOptions.titleBarStyle = 'hidden'
|
||||
bwOptions.titleBarStyle = 'hidden'
|
||||
if (process.platform === 'win32') {
|
||||
bwOptions.titleBarOverlay = {
|
||||
color: '#00000000',
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -384,6 +387,22 @@ export class Window {
|
||||
this.setVibrancy(enabled, type)
|
||||
})
|
||||
|
||||
ipcMain.on('window-set-window-controls-color', (event, theme) => {
|
||||
if (!this.window || event.sender !== this.window.webContents) {
|
||||
return
|
||||
}
|
||||
|
||||
if (process.platform === 'win32') {
|
||||
const symbolColor: string = theme.foreground
|
||||
this.window.setTitleBarOverlay(
|
||||
{
|
||||
symbolColor: symbolColor,
|
||||
height: 32,
|
||||
},
|
||||
)
|
||||
}
|
||||
})
|
||||
|
||||
ipcMain.on('window-set-title', (event, title) => {
|
||||
if (!this.window || event.sender !== this.window.webContents) {
|
||||
return
|
||||
@@ -442,7 +461,7 @@ export class Window {
|
||||
this.window.on('resize', onBoundsChange)
|
||||
|
||||
ipcMain.on('window-set-traffic-light-position', (_event, x, y) => {
|
||||
this.window.setTrafficLightPosition({ x, y })
|
||||
this.window.setWindowButtonPosition({ x, y })
|
||||
})
|
||||
|
||||
ipcMain.on('window-set-opacity', (_event, opacity) => {
|
||||
|
@@ -16,7 +16,7 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@electron/remote": "2.0.10",
|
||||
"@tabby-gang/node-pty": "^0.11.0-beta.203",
|
||||
"node-pty": "^1.0",
|
||||
"any-promise": "^1.3.0",
|
||||
"electron-config": "2.0.0",
|
||||
"electron-debug": "^3.2.0",
|
||||
@@ -38,7 +38,7 @@
|
||||
"@tabby-gang/windows-blurbehind": "^3.0.0",
|
||||
"macos-native-processlist": "^2.1.0",
|
||||
"patch-package": "^6.5.0",
|
||||
"serialport": "11.0.0",
|
||||
"serialport": "11.0.1",
|
||||
"serialport-binding-webserialapi": "^1.0.3",
|
||||
"windows-native-registry": "^3.2.1",
|
||||
"windows-process-tree": "^0.4.0"
|
||||
@@ -47,7 +47,7 @@
|
||||
"@ngx-translate/core": "^14.0.0",
|
||||
"@types/mz": "2.7.4",
|
||||
"@types/node": "20.3.1",
|
||||
"atomically": "^1.7.0",
|
||||
"atomically": "^2.0.2",
|
||||
"filesize": "^9",
|
||||
"ngx-filesize": "^3.0.2"
|
||||
},
|
||||
@@ -64,6 +64,7 @@
|
||||
},
|
||||
"resolutions": {
|
||||
"*/node-abi": "^2.20.0",
|
||||
"node-gyp": "^10.0.0",
|
||||
"nan": "github:jkleinsc/nan#remove_accessor_signature"
|
||||
}
|
||||
}
|
||||
|
@@ -47,7 +47,7 @@ const config = {
|
||||
mz: 'commonjs mz',
|
||||
npm: 'commonjs npm',
|
||||
'node:os': 'commonjs os',
|
||||
'@tabby-gang/node-pty': 'commonjs @tabby-gang/node-pty',
|
||||
'node-pty': 'commonjs node-pty',
|
||||
path: 'commonjs path',
|
||||
util: 'commonjs util',
|
||||
'source-map-support': 'commonjs source-map-support',
|
||||
|
721
app/yarn.lock
721
app/yarn.lock
File diff suppressed because it is too large
Load Diff
@@ -1,16 +0,0 @@
|
||||
const fs = require('fs')
|
||||
const signHook = require('./afterSignHook.cjs')
|
||||
|
||||
module.exports = async function (params) {
|
||||
// notarize the app on Mac OS only.
|
||||
if (process.platform !== 'darwin' || !process.env.GITHUB_REF || !process.env.GITHUB_REF.startsWith('refs/tags/')) {
|
||||
return
|
||||
}
|
||||
console.log('afterBuild hook triggered')
|
||||
|
||||
let pkgName = fs.readdirSync('dist').find(x => x.endsWith('.pkg'))
|
||||
signHook({
|
||||
appOutDir: 'dist',
|
||||
_pathOverride: pkgName,
|
||||
})
|
||||
}
|
@@ -1,35 +0,0 @@
|
||||
// See: https://medium.com/@TwitterArchiveEraser/notarize-electron-apps-7a5f988406db
|
||||
|
||||
const fs = require('fs')
|
||||
const path = require('path')
|
||||
const notarizer = require('@electron/notarize')
|
||||
|
||||
module.exports = async function (params) {
|
||||
// notarize the app on Mac OS only.
|
||||
if (process.platform !== 'darwin' || !process.env.GITHUB_REF || !process.env.GITHUB_REF.startsWith('refs/tags/')) {
|
||||
return
|
||||
}
|
||||
console.log('afterSign hook triggered', params)
|
||||
|
||||
let appId = 'org.tabby'
|
||||
|
||||
let appPath = path.join(params.appOutDir, params._pathOverride || `${params.packager.appInfo.productFilename}.app`)
|
||||
if (!fs.existsSync(appPath)) {
|
||||
throw new Error(`Cannot find application at: ${appPath}`)
|
||||
}
|
||||
|
||||
console.log(`Notarizing ${appId} found at ${appPath}`)
|
||||
|
||||
try {
|
||||
await notarizer.notarize({
|
||||
appBundleId: appId,
|
||||
appPath: appPath,
|
||||
appleId: process.env.APPSTORE_USERNAME,
|
||||
appleIdPassword: process.env.APPSTORE_PASSWORD,
|
||||
})
|
||||
} catch (error) {
|
||||
console.error(error)
|
||||
}
|
||||
|
||||
console.log(`Done notarizing ${appId}`)
|
||||
}
|
@@ -3,8 +3,6 @@ appId: org.tabby
|
||||
productName: Tabby
|
||||
compression: normal
|
||||
npmRebuild: false
|
||||
afterSign: "./build/mac/afterSignHook.cjs"
|
||||
afterAllArtifactBuild: "./build/mac/afterBuildHook.cjs"
|
||||
files:
|
||||
- '**/*'
|
||||
- dist
|
||||
|
570
locale/af-ZA.po
570
locale/af-ZA.po
File diff suppressed because it is too large
Load Diff
568
locale/app.pot
568
locale/app.pot
File diff suppressed because it is too large
Load Diff
570
locale/bg-BG.po
570
locale/bg-BG.po
File diff suppressed because it is too large
Load Diff
2574
locale/cs-CZ.po
Normal file
2574
locale/cs-CZ.po
Normal file
File diff suppressed because it is too large
Load Diff
570
locale/da-DK.po
570
locale/da-DK.po
File diff suppressed because it is too large
Load Diff
588
locale/de-DE.po
588
locale/de-DE.po
File diff suppressed because it is too large
Load Diff
578
locale/en-GB.po
578
locale/en-GB.po
File diff suppressed because it is too large
Load Diff
598
locale/es-ES.po
598
locale/es-ES.po
File diff suppressed because it is too large
Load Diff
592
locale/fr-FR.po
592
locale/fr-FR.po
File diff suppressed because it is too large
Load Diff
602
locale/hr-HR.po
602
locale/hr-HR.po
File diff suppressed because it is too large
Load Diff
592
locale/id-ID.po
592
locale/id-ID.po
File diff suppressed because it is too large
Load Diff
590
locale/it-IT.po
590
locale/it-IT.po
File diff suppressed because it is too large
Load Diff
644
locale/ja-JP.po
644
locale/ja-JP.po
File diff suppressed because it is too large
Load Diff
638
locale/ko-KR.po
638
locale/ko-KR.po
File diff suppressed because it is too large
Load Diff
670
locale/pl-PL.po
670
locale/pl-PL.po
File diff suppressed because it is too large
Load Diff
596
locale/pt-BR.po
596
locale/pt-BR.po
File diff suppressed because it is too large
Load Diff
570
locale/pt-PT.po
570
locale/pt-PT.po
File diff suppressed because it is too large
Load Diff
594
locale/ru-RU.po
594
locale/ru-RU.po
File diff suppressed because it is too large
Load Diff
588
locale/sv-SE.po
588
locale/sv-SE.po
File diff suppressed because it is too large
Load Diff
592
locale/uk-UA.po
592
locale/uk-UA.po
File diff suppressed because it is too large
Load Diff
592
locale/zh-CN.po
592
locale/zh-CN.po
File diff suppressed because it is too large
Load Diff
594
locale/zh-TW.po
594
locale/zh-TW.po
File diff suppressed because it is too large
Load Diff
30
package.json
30
package.json
@@ -26,8 +26,8 @@
|
||||
"@types/js-yaml": "^4.0.5",
|
||||
"@types/node": "20.3.1",
|
||||
"@types/webpack-env": "^1.18.0",
|
||||
"@typescript-eslint/eslint-plugin": "^5.45.0",
|
||||
"@typescript-eslint/parser": "^5.54.1",
|
||||
"@typescript-eslint/eslint-plugin": "^6.4.1",
|
||||
"@typescript-eslint/parser": "^6.4.1",
|
||||
"apply-loader": "2.0.0",
|
||||
"axios": "^1.4.0",
|
||||
"babel-loader": "^9.1.2",
|
||||
@@ -39,24 +39,24 @@
|
||||
"cross-env": "7.0.3",
|
||||
"css-loader": "^6.7.3",
|
||||
"deep-equal": "2.0.5",
|
||||
"electron": "22.3.1",
|
||||
"electron-builder": "^24.0.0-alpha.1",
|
||||
"electron": "^27.0.4",
|
||||
"electron-builder": "^24.6.4",
|
||||
"electron-download": "^4.1.1",
|
||||
"electron-installer-snap": "^5.1.0",
|
||||
"electron-rebuild": "^3.2.9",
|
||||
"eslint": "^8.38.0",
|
||||
"eslint-import-resolver-typescript": "^3.5.2",
|
||||
"eslint-plugin-import": "^2.27.5",
|
||||
"eslint": "^8.48.0",
|
||||
"eslint-import-resolver-typescript": "^3.6.0",
|
||||
"eslint-plugin-import": "^2.28.1",
|
||||
"file-loader": "^6.2.0",
|
||||
"gettext-extractor": "^3.5.4",
|
||||
"gettext-extractor": "^3.8.0",
|
||||
"graceful-fs": "^4.2.10",
|
||||
"html-loader": "4.2.0",
|
||||
"json-loader": "^0.5.7",
|
||||
"lru-cache": "^6.0.0",
|
||||
"macos-release": "^3.1.0",
|
||||
"ngx-toastr": "^16.0.2",
|
||||
"node-abi": "^3.45.0",
|
||||
"npmlog": "7.0.1",
|
||||
"node-abi": "^3.51.0",
|
||||
"npmlog": "6.0.2",
|
||||
"npx": "^10.2.2",
|
||||
"patch-package": "^6.4.7",
|
||||
"po-gettext-loader": "^1.0.0",
|
||||
@@ -76,7 +76,7 @@
|
||||
"source-code-pro": "^2.38.0",
|
||||
"source-map-loader": "^4.0.1",
|
||||
"source-sans-pro": "3.6.0",
|
||||
"ssh2": "Eugeny/ssh2#9de907d62907d6d45debdcc0ed8dda5b7b19dc7c",
|
||||
"ssh2": "^1.14.0",
|
||||
"style-loader": "^3.3.1",
|
||||
"svg-inline-loader": "^0.8.2",
|
||||
"thenby": "^1.3.4",
|
||||
@@ -95,8 +95,7 @@
|
||||
},
|
||||
"resolutions": {
|
||||
"*/pug": "^3",
|
||||
"lzma-native": "^8.0.0",
|
||||
"*/node-abi": "^3.33.0",
|
||||
"lzma-native": "^8.0.6",
|
||||
"**/graceful-fs": "^4.2.4",
|
||||
"nan": "2.17.0"
|
||||
},
|
||||
@@ -115,5 +114,8 @@
|
||||
"i18n:push": "crowdin push"
|
||||
},
|
||||
"type": "module",
|
||||
"private": true
|
||||
"private": true,
|
||||
"dependencies": {
|
||||
"dotenv": "^16.3.1"
|
||||
}
|
||||
}
|
||||
|
@@ -1,15 +1,15 @@
|
||||
diff --git a/node_modules/app-builder-lib/out/appInfo.js b/node_modules/app-builder-lib/out/appInfo.js
|
||||
index 363f32c..a0434a9 100644
|
||||
index 49f6dca..0ea11f2 100644
|
||||
--- a/node_modules/app-builder-lib/out/appInfo.js
|
||||
+++ b/node_modules/app-builder-lib/out/appInfo.js
|
||||
@@ -100,9 +100,7 @@ class AppInfo {
|
||||
@@ -112,9 +112,7 @@ class AppInfo {
|
||||
return this.info.metadata.name;
|
||||
}
|
||||
get linuxPackageName() {
|
||||
- const name = this.name;
|
||||
- // https://github.com/electron-userland/electron-builder/issues/2963
|
||||
- return name.startsWith("@") ? this.sanitizedProductName : name;
|
||||
+ return 'tabby-terminal'
|
||||
+ return 'tabby-terminal';
|
||||
}
|
||||
get sanitizedName() {
|
||||
return filename_1.sanitizeFileName(this.name);
|
||||
return (0, filename_1.sanitizeFileName)(this.name);
|
@@ -9,10 +9,11 @@ process.env.ARCH = (process.env.ARCH || process.arch) === 'arm' ? 'armv7l' : pro
|
||||
|
||||
builder({
|
||||
dir: true,
|
||||
linux: ['deb', 'tar.gz', 'rpm', 'pacman'],
|
||||
linux: ['deb', 'tar.gz', 'rpm', 'pacman', 'appimage'],
|
||||
armv7l: process.env.ARCH === 'armv7l',
|
||||
arm64: process.env.ARCH === 'arm64',
|
||||
config: {
|
||||
npmRebuild: false,
|
||||
extraMetadata: {
|
||||
version: vars.version,
|
||||
},
|
||||
|
@@ -13,9 +13,12 @@ if (process.env.GITHUB_HEAD_REF) {
|
||||
process.env.CSC_IDENTITY_AUTO_DISCOVERY = 'false'
|
||||
}
|
||||
|
||||
process.env.APPLE_ID ??= process.env.APPSTORE_USERNAME
|
||||
process.env.APPLE_APP_SPECIFIC_PASSWORD ??= process.env.APPSTORE_PASSWORD
|
||||
|
||||
builder({
|
||||
dir: true,
|
||||
mac: ['pkg', 'zip'],
|
||||
mac: ['dmg', 'zip'],
|
||||
x64: process.env.ARCH === 'x86_64',
|
||||
arm64: process.env.ARCH === 'arm64',
|
||||
config: {
|
||||
@@ -24,6 +27,10 @@ builder({
|
||||
},
|
||||
mac: {
|
||||
identity: !process.env.CI || process.env.CSC_LINK ? undefined : null,
|
||||
notarize: process.env.APPLE_TEAM_ID ? {
|
||||
appBundleId: 'org.tabby',
|
||||
teamId: process.env.APPLE_TEAM_ID,
|
||||
} : false,
|
||||
},
|
||||
npmRebuild: process.env.ARCH !== 'arm64',
|
||||
publish: process.env.KEYGEN_TOKEN ? [
|
||||
|
@@ -9,7 +9,7 @@ sh.exec(`${sentryCli} releases new ${vars.version}`)
|
||||
if (process.platform === 'darwin') {
|
||||
for (const path of [
|
||||
'app/node_modules/@serialport/bindings/build/Release/bindings.node',
|
||||
'app/node_modules/@tabby-gang/node-pty/build/Release/pty.node',
|
||||
'app/node_modules/node-pty/build/Release/pty.node',
|
||||
'app/node_modules/fontmanager-redux/build/Release/fontmanager.node',
|
||||
'app/node_modules/macos-native-processlist/build/Release/native.node',
|
||||
]) {
|
||||
|
@@ -3,6 +3,8 @@ import * as fs from 'fs'
|
||||
import * as semver from 'semver'
|
||||
import * as childProcess from 'child_process'
|
||||
|
||||
process.env.ARCH = ((process.env.ARCH || process.arch) === 'arm') ? 'armv7l' : process.env.ARCH || process.arch
|
||||
|
||||
import * as url from 'url'
|
||||
const __dirname = url.fileURLToPath(new URL('.', import.meta.url))
|
||||
|
||||
@@ -58,21 +60,21 @@ export const keygenConfig = {
|
||||
win32: {
|
||||
x64: 'f481b9d6-d5da-4970-b926-f515373e986f',
|
||||
arm64: '950999b9-371c-419b-b291-938c5e4d364c',
|
||||
}[process.env.ARCH ?? process.arch],
|
||||
}[process.env.ARCH],
|
||||
darwin: {
|
||||
arm64: '98fbadee-c707-4cd6-9d99-56683595a846',
|
||||
x86_64: 'f5a48841-d5b8-4b7b-aaa7-cf5bffd36461',
|
||||
x64: 'f5a48841-d5b8-4b7b-aaa7-cf5bffd36461',
|
||||
}[process.env.ARCH ?? process.arch],
|
||||
}[process.env.ARCH],
|
||||
linux: {
|
||||
x64: '7bf45071-3031-4a26-9f2e-72604308313e',
|
||||
arm64: '39e3c736-d4d4-4fbf-a201-324b7bab0d17',
|
||||
armv7l: '50ae0a82-7f47-4fa4-b0a8-b0d575ce9409',
|
||||
armhf: '7df5aa12-04ab-4075-a0fe-93b0bbea9643',
|
||||
}[process.env.ARCH ?? process.arch],
|
||||
}[process.env.ARCH],
|
||||
}[process.platform],
|
||||
}
|
||||
|
||||
if (!keygenConfig.product) {
|
||||
throw new Error(`Unrecognized platform ${process.platform}/${process.env.ARCH ?? process.arch}`)
|
||||
throw new Error(`Unrecognized platform ${process.platform}/${process.env.ARCH}`)
|
||||
}
|
||||
|
@@ -1,3 +1,4 @@
|
||||
import slugify from 'slugify'
|
||||
import { BaseTabComponent } from '../components/baseTab.component'
|
||||
import { MenuItemOptions } from './menu'
|
||||
import { ToolbarButton } from './toolbarButtonProvider'
|
||||
@@ -6,34 +7,33 @@ export enum CommandLocation {
|
||||
LeftToolbar = 'left-toolbar',
|
||||
RightToolbar = 'right-toolbar',
|
||||
StartPage = 'start-page',
|
||||
TabHeaderMenu = 'tab-header-menu',
|
||||
TabBodyMenu = 'tab-body-menu',
|
||||
}
|
||||
|
||||
export class Command {
|
||||
id?: string
|
||||
id: string
|
||||
label: string
|
||||
sublabel?: string
|
||||
locations?: CommandLocation[]
|
||||
run: () => Promise<void>
|
||||
fullLabel?: string
|
||||
locations: CommandLocation[]
|
||||
run?: () => Promise<any>
|
||||
|
||||
/**
|
||||
* Raw SVG icon code
|
||||
*/
|
||||
icon?: string
|
||||
|
||||
/**
|
||||
* Optional Touch Bar icon ID
|
||||
*/
|
||||
touchBarNSImage?: string
|
||||
|
||||
/**
|
||||
* Optional Touch Bar button label
|
||||
*/
|
||||
touchBarTitle?: string
|
||||
|
||||
weight?: number
|
||||
|
||||
parent?: string
|
||||
|
||||
group?: string
|
||||
|
||||
checked?: boolean
|
||||
|
||||
static fromToolbarButton (button: ToolbarButton): Command {
|
||||
const command = new Command()
|
||||
command.id = `legacy:${slugify(button.title)}`
|
||||
command.label = button.title
|
||||
command.run = async () => button.click?.()
|
||||
command.icon = button.icon
|
||||
@@ -44,18 +44,29 @@ export class Command {
|
||||
if ((button.weight ?? 0) > 0) {
|
||||
command.locations.push(CommandLocation.RightToolbar)
|
||||
}
|
||||
command.touchBarNSImage = button.touchBarNSImage
|
||||
command.touchBarTitle = button.touchBarTitle
|
||||
command.weight = button.weight
|
||||
return command
|
||||
}
|
||||
|
||||
static fromMenuItem (item: MenuItemOptions): Command {
|
||||
const command = new Command()
|
||||
command.label = item.commandLabel ?? item.label ?? ''
|
||||
command.sublabel = item.sublabel
|
||||
command.run = async () => item.click?.()
|
||||
return command
|
||||
static fromMenuItem (item: MenuItemOptions): Command[] {
|
||||
if (item.type === 'separator') {
|
||||
return []
|
||||
}
|
||||
const commands: Command[] = [{
|
||||
id: `legacy:${slugify(item.commandLabel ?? item.label).toLowerCase()}`,
|
||||
label: item.commandLabel ?? item.label,
|
||||
run: async () => item.click?.(),
|
||||
locations: [CommandLocation.TabBodyMenu, CommandLocation.TabHeaderMenu],
|
||||
checked: item.checked,
|
||||
}]
|
||||
for (const submenu of item.submenu ?? []) {
|
||||
commands.push(...Command.fromMenuItem(submenu).map(x => ({
|
||||
...x,
|
||||
id: `${commands[0].id}:${slugify(x.label).toLowerCase()}`,
|
||||
parent: commands[0].id,
|
||||
})))
|
||||
}
|
||||
return commands
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -16,7 +16,7 @@ export { BootstrapData, PluginInfo, BOOTSTRAP_DATA } from './mainProcess'
|
||||
export { HostWindowService } from './hostWindow'
|
||||
export { HostAppService, Platform } from './hostApp'
|
||||
export { FileProvider } from './fileProvider'
|
||||
export { ProfileProvider, Profile, PartialProfile, ProfileSettingsComponent } from './profileProvider'
|
||||
export { ProfileProvider, ConnectableProfileProvider, QuickConnectProfileProvider, Profile, ConnectableProfile, PartialProfile, ProfileSettingsComponent, ProfileGroup, PartialProfileGroup } from './profileProvider'
|
||||
export { PromptModalComponent } from '../components/promptModal.component'
|
||||
export * from './commands'
|
||||
|
||||
@@ -37,6 +37,7 @@ export { UpdaterService } from '../services/updater.service'
|
||||
export { VaultService, Vault, VaultSecret, VaultFileSecret, VAULT_SECRET_TYPE_FILE, StoredVault, VaultSecretKey } from '../services/vault.service'
|
||||
export { FileProvidersService } from '../services/fileProviders.service'
|
||||
export { LocaleService } from '../services/locale.service'
|
||||
export { CommandService } from '../services/commands.service'
|
||||
export { TranslateService } from '@ngx-translate/core'
|
||||
export * from '../utils'
|
||||
export { UTF8Splitter } from '../utfSplitter'
|
||||
|
@@ -1,6 +1,4 @@
|
||||
export interface MenuItemOptions {
|
||||
type?: ('normal' | 'separator' | 'submenu' | 'checkbox' | 'radio')
|
||||
label?: string
|
||||
export type MenuItemOptions = {
|
||||
sublabel?: string
|
||||
enabled?: boolean
|
||||
checked?: boolean
|
||||
@@ -9,4 +7,10 @@ export interface MenuItemOptions {
|
||||
|
||||
/** @hidden */
|
||||
commandLabel?: string
|
||||
}
|
||||
} & ({
|
||||
type: 'separator',
|
||||
label?: string,
|
||||
} | {
|
||||
type?: 'normal' | 'submenu' | 'checkbox' | 'radio',
|
||||
label: string,
|
||||
})
|
||||
|
@@ -86,14 +86,18 @@ export interface FileUploadOptions {
|
||||
multiple: boolean
|
||||
}
|
||||
|
||||
export type PlatformTheme = 'light'|'dark'
|
||||
|
||||
export abstract class PlatformService {
|
||||
supportsWindowControls = false
|
||||
|
||||
get fileTransferStarted$ (): Observable<FileTransfer> { return this.fileTransferStarted }
|
||||
get displayMetricsChanged$ (): Observable<void> { return this.displayMetricsChanged }
|
||||
get themeChanged$ (): Observable<PlatformTheme> { return this.themeChanged }
|
||||
|
||||
protected fileTransferStarted = new Subject<FileTransfer>()
|
||||
protected displayMetricsChanged = new Subject<void>()
|
||||
protected themeChanged = new Subject<PlatformTheme>()
|
||||
|
||||
abstract readClipboard (): string
|
||||
abstract setClipboard (content: ClipboardContent): void
|
||||
@@ -169,6 +173,10 @@ export abstract class PlatformService {
|
||||
throw new Error('Not implemented')
|
||||
}
|
||||
|
||||
getTheme (): PlatformTheme {
|
||||
return 'dark'
|
||||
}
|
||||
|
||||
abstract getOSRelease (): string
|
||||
abstract getAppVersion (): string
|
||||
abstract openExternal (url: string): void
|
||||
|
@@ -21,6 +21,10 @@ export interface Profile {
|
||||
isTemplate: boolean
|
||||
}
|
||||
|
||||
export interface ConnectableProfile extends Profile {
|
||||
clearServiceMessagesOnConnect: boolean
|
||||
}
|
||||
|
||||
export type PartialProfile<T extends Profile> = Omit<Omit<Omit<{
|
||||
[K in keyof T]?: T[K]
|
||||
}, 'options'>, 'type'>, 'name'> & {
|
||||
@@ -31,6 +35,21 @@ export type PartialProfile<T extends Profile> = Omit<Omit<Omit<{
|
||||
}
|
||||
}
|
||||
|
||||
export interface ProfileGroup {
|
||||
id: string
|
||||
name: string
|
||||
profiles: PartialProfile<Profile>[]
|
||||
defaults: any
|
||||
editable: boolean
|
||||
}
|
||||
|
||||
export type PartialProfileGroup<T extends ProfileGroup> = Omit<Omit<{
|
||||
[K in keyof T]?: T[K]
|
||||
}, 'id'>, 'name'> & {
|
||||
id: string
|
||||
name: string
|
||||
}
|
||||
|
||||
export interface ProfileSettingsComponent<P extends Profile> {
|
||||
profile: P
|
||||
save?: () => void
|
||||
@@ -39,7 +58,6 @@ export interface ProfileSettingsComponent<P extends Profile> {
|
||||
export abstract class ProfileProvider<P extends Profile> {
|
||||
id: string
|
||||
name: string
|
||||
supportsQuickConnect = false
|
||||
settingsComponent?: new (...args: any[]) => ProfileSettingsComponent<P>
|
||||
configDefaults = {}
|
||||
|
||||
@@ -53,13 +71,15 @@ export abstract class ProfileProvider<P extends Profile> {
|
||||
|
||||
abstract getDescription (profile: PartialProfile<P>): string
|
||||
|
||||
quickConnect (query: string): PartialProfile<P>|null {
|
||||
return null
|
||||
}
|
||||
|
||||
intoQuickConnectString (profile: P): string|null {
|
||||
return null
|
||||
}
|
||||
|
||||
deleteProfile (profile: P): void { }
|
||||
}
|
||||
|
||||
export abstract class ConnectableProfileProvider<P extends ConnectableProfile> extends ProfileProvider<P> {}
|
||||
|
||||
export abstract class QuickConnectProfileProvider<P extends ConnectableProfile> extends ConnectableProfileProvider<P> {
|
||||
|
||||
abstract quickConnect (query: string): PartialProfile<P>|null
|
||||
|
||||
abstract intoQuickConnectString (profile: P): string|null
|
||||
|
||||
}
|
||||
|
@@ -9,16 +9,6 @@ export interface ToolbarButton {
|
||||
|
||||
title: string
|
||||
|
||||
/**
|
||||
* Optional Touch Bar icon ID
|
||||
*/
|
||||
touchBarNSImage?: string
|
||||
|
||||
/**
|
||||
* Optional Touch Bar button label
|
||||
*/
|
||||
touchBarTitle?: string
|
||||
|
||||
weight?: number
|
||||
|
||||
click?: () => void
|
||||
|
@@ -2,6 +2,7 @@ import { Injectable } from '@angular/core'
|
||||
import { HostAppService } from './api/hostApp'
|
||||
import { CLIHandler, CLIEvent } from './api/cli'
|
||||
import { HostWindowService } from './api/hostWindow'
|
||||
import { QuickConnectProfileProvider } from './api/profileProvider'
|
||||
import { ProfilesService } from './services/profiles.service'
|
||||
|
||||
@Injectable()
|
||||
@@ -27,6 +28,10 @@ export class ProfileCLIHandler extends CLIHandler {
|
||||
this.handleOpenRecentProfile(event.argv.profileNumber)
|
||||
return true
|
||||
}
|
||||
if (op === 'quickConnect') {
|
||||
this.handleOpenQuickConnect(event.argv.providerId, event.argv.query)
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
@@ -48,6 +53,21 @@ export class ProfileCLIHandler extends CLIHandler {
|
||||
this.profiles.openNewTabForProfile(profiles[profileNumber])
|
||||
this.hostWindow.bringToFront()
|
||||
}
|
||||
|
||||
private async handleOpenQuickConnect (providerId: string, query: string) {
|
||||
const provider = this.profiles.getProviders().find(x => x.id === providerId)
|
||||
if(!provider || !(provider instanceof QuickConnectProfileProvider)) {
|
||||
console.error(`Requested provider "${providerId}" not found`)
|
||||
return
|
||||
}
|
||||
const profile = provider.quickConnect(query)
|
||||
if(!profile) {
|
||||
console.error(`Could not parse quick connect query "${query}"`)
|
||||
return
|
||||
}
|
||||
this.profiles.openNewTabForProfile(profile)
|
||||
this.hostWindow.bringToFront()
|
||||
}
|
||||
}
|
||||
|
||||
@Injectable()
|
||||
|
@@ -1,10 +1,20 @@
|
||||
/* eslint-disable @typescript-eslint/explicit-module-boundary-types */
|
||||
import { Injectable } from '@angular/core'
|
||||
import { TranslateService } from '@ngx-translate/core'
|
||||
import { NgbModal } from '@ng-bootstrap/ng-bootstrap'
|
||||
|
||||
import { HostAppService, Platform } from './api/hostApp'
|
||||
import { ProfilesService } from './services/profiles.service'
|
||||
import { CommandProvider, Command, CommandLocation } from './api/commands'
|
||||
import { AppService } from './services/app.service'
|
||||
import { CommandProvider, Command, CommandLocation, CommandContext } from './api/commands'
|
||||
import { SplitDirection, SplitTabComponent } from './components/splitTab.component'
|
||||
import { BaseTabComponent } from './components/baseTab.component'
|
||||
import { PromptModalComponent } from './components/promptModal.component'
|
||||
import { HotkeysService } from './services/hotkeys.service'
|
||||
import { TabsService } from './services/tabs.service'
|
||||
import { SplitLayoutProfilesService } from './profiles'
|
||||
import { TAB_COLORS } from './utils'
|
||||
import { Subscription } from 'rxjs'
|
||||
|
||||
/** @hidden */
|
||||
@Injectable({ providedIn: 'root' })
|
||||
@@ -13,38 +23,327 @@ export class CoreCommandProvider extends CommandProvider {
|
||||
private hostApp: HostAppService,
|
||||
private profilesService: ProfilesService,
|
||||
private translate: TranslateService,
|
||||
private app: AppService,
|
||||
private splitLayoutProfilesService: SplitLayoutProfilesService,
|
||||
private ngbModal: NgbModal,
|
||||
private tabsService: TabsService,
|
||||
hotkeys: HotkeysService,
|
||||
) {
|
||||
super()
|
||||
hotkeys.hotkey$.subscribe(hotkey => {
|
||||
if (hotkey === 'switch-profile') {
|
||||
let tab = this.app.activeTab
|
||||
if (tab instanceof SplitTabComponent) {
|
||||
tab = tab.getFocusedTab()
|
||||
if (tab) {
|
||||
this.switchTabProfile(tab)
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
async activate () {
|
||||
const profile = await this.profilesService.showProfileSelector()
|
||||
async switchTabProfile (tab: BaseTabComponent) {
|
||||
const profile = await this.profilesService.showProfileSelector().catch(() => null)
|
||||
if (!profile) {
|
||||
return
|
||||
}
|
||||
|
||||
const params = await this.profilesService.newTabParametersForProfile(profile)
|
||||
if (!params) {
|
||||
return
|
||||
}
|
||||
|
||||
if (!await tab.canClose()) {
|
||||
return
|
||||
}
|
||||
|
||||
const newTab = this.tabsService.create(params)
|
||||
;(tab.parent as SplitTabComponent).replaceTab(tab, newTab)
|
||||
|
||||
tab.destroy()
|
||||
}
|
||||
|
||||
async showProfileSelector () {
|
||||
const profile = await this.profilesService.showProfileSelector().catch(() => null)
|
||||
if (profile) {
|
||||
this.profilesService.launchProfile(profile)
|
||||
}
|
||||
}
|
||||
|
||||
async provide (): Promise<Command[]> {
|
||||
return [
|
||||
async provide (context: CommandContext): Promise<Command[]> {
|
||||
const commands: Command[] = [
|
||||
{
|
||||
id: 'core:profile-selector',
|
||||
locations: [CommandLocation.LeftToolbar, CommandLocation.StartPage],
|
||||
label: this.translate.instant('Profiles & connections'),
|
||||
weight: 12,
|
||||
icon: this.hostApp.platform === Platform.Web
|
||||
? require('./icons/plus.svg')
|
||||
: require('./icons/profiles.svg'),
|
||||
run: async () => this.activate(),
|
||||
run: async () => this.showProfileSelector(),
|
||||
},
|
||||
...this.profilesService.getRecentProfiles().map((profile, index) => ({
|
||||
id: `core:recent-profile-${index}`,
|
||||
label: profile.name,
|
||||
locations: [CommandLocation.StartPage],
|
||||
icon: require('./icons/history.svg'),
|
||||
weight: 20,
|
||||
run: async () => {
|
||||
const p = (await this.profilesService.getProfiles()).find(x => x.id === profile.id) ?? profile
|
||||
this.profilesService.launchProfile(p)
|
||||
},
|
||||
})),
|
||||
]
|
||||
|
||||
if (context.tab) {
|
||||
const tab = context.tab
|
||||
|
||||
commands.push({
|
||||
id: `core:close-tab`,
|
||||
label: this.translate.instant('Close tab'),
|
||||
locations: [CommandLocation.TabHeaderMenu],
|
||||
weight: -35,
|
||||
group: 'core:close',
|
||||
run: async () => {
|
||||
if (this.app.tabs.includes(tab)) {
|
||||
this.app.closeTab(tab, true)
|
||||
} else {
|
||||
tab.destroy()
|
||||
}
|
||||
},
|
||||
})
|
||||
|
||||
commands.push({
|
||||
id: `core:close`,
|
||||
label: this.translate.instant('Close'),
|
||||
locations: [CommandLocation.TabBodyMenu],
|
||||
weight: 99,
|
||||
group: 'core:close',
|
||||
run: async () => {
|
||||
tab.destroy()
|
||||
},
|
||||
})
|
||||
|
||||
if (!context.tab.parent) {
|
||||
commands.push(...[{
|
||||
id: 'core:close-other-tabs',
|
||||
label: this.translate.instant('Close other tabs'),
|
||||
locations: [CommandLocation.TabHeaderMenu],
|
||||
weight: -34,
|
||||
group: 'core:close',
|
||||
run: async () => {
|
||||
for (const t of this.app.tabs.filter(x => x !== tab)) {
|
||||
this.app.closeTab(t, true)
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'core:close-tabs-to-the-right',
|
||||
label: this.translate.instant('Close tabs to the right'),
|
||||
locations: [CommandLocation.TabHeaderMenu],
|
||||
weight: -33,
|
||||
group: 'core:close',
|
||||
run: async () => {
|
||||
for (const t of this.app.tabs.slice(this.app.tabs.indexOf(tab) + 1)) {
|
||||
this.app.closeTab(t, true)
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'core:close-tabs-to-the-left',
|
||||
label: this.translate.instant('Close tabs to the left'),
|
||||
locations: [CommandLocation.TabHeaderMenu],
|
||||
weight: -32,
|
||||
group: 'core:close',
|
||||
run: async () => {
|
||||
for (const t of this.app.tabs.slice(0, this.app.tabs.indexOf(tab))) {
|
||||
this.app.closeTab(t, true)
|
||||
}
|
||||
},
|
||||
}])
|
||||
}
|
||||
|
||||
commands.push({
|
||||
id: 'core:rename-tab',
|
||||
label: this.translate.instant('Rename tab'),
|
||||
locations: [CommandLocation.TabHeaderMenu],
|
||||
group: 'core:common',
|
||||
weight: -13,
|
||||
run: async () => this.app.renameTab(tab),
|
||||
})
|
||||
commands.push({
|
||||
id: 'core:duplicate-tab',
|
||||
label: this.translate.instant('Duplicate tab'),
|
||||
locations: [CommandLocation.TabHeaderMenu],
|
||||
group: 'core:common',
|
||||
weight: -12,
|
||||
run: async () => this.app.duplicateTab(tab),
|
||||
})
|
||||
commands.push({
|
||||
id: 'core:tab-color',
|
||||
label: this.translate.instant('Color'),
|
||||
group: 'core:common',
|
||||
locations: [CommandLocation.TabHeaderMenu],
|
||||
weight: -11,
|
||||
})
|
||||
for (const color of TAB_COLORS) {
|
||||
commands.push({
|
||||
id: `core:tab-color-${color.name.toLowerCase()}`,
|
||||
parent: 'core:tab-color',
|
||||
label: this.translate.instant(color.name) ?? color.name,
|
||||
fullLabel: this.translate.instant('Set tab color to {color}', { color: this.translate.instant(color.name) }),
|
||||
checked: tab.color === color.value,
|
||||
locations: [CommandLocation.TabHeaderMenu],
|
||||
run: async () => {
|
||||
tab.color = color.value
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
if (tab.parent instanceof SplitTabComponent) {
|
||||
const directions: SplitDirection[] = ['r', 'b', 'l', 't']
|
||||
commands.push({
|
||||
id: 'core:split',
|
||||
label: this.translate.instant('Split'),
|
||||
group: 'core:panes',
|
||||
locations: [CommandLocation.TabBodyMenu],
|
||||
})
|
||||
for (const dir of directions) {
|
||||
commands.push({
|
||||
id: `core:split-${dir}`,
|
||||
label: {
|
||||
r: this.translate.instant('Right'),
|
||||
b: this.translate.instant('Down'),
|
||||
l: this.translate.instant('Left'),
|
||||
t: this.translate.instant('Up'),
|
||||
}[dir],
|
||||
fullLabel: {
|
||||
r: this.translate.instant('Split to the right'),
|
||||
b: this.translate.instant('Split to the down'),
|
||||
l: this.translate.instant('Split to the left'),
|
||||
t: this.translate.instant('Split to the up'),
|
||||
}[dir],
|
||||
locations: [CommandLocation.TabBodyMenu],
|
||||
parent: 'core:split',
|
||||
run: async () => {
|
||||
(tab.parent as SplitTabComponent).splitTab(tab, dir)
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
commands.push({
|
||||
id: 'core:switch-profile',
|
||||
label: this.translate.instant('Switch profile'),
|
||||
group: 'core:common',
|
||||
locations: [CommandLocation.TabBodyMenu],
|
||||
run: async () => this.switchTabProfile(tab),
|
||||
})
|
||||
}
|
||||
|
||||
if (tab instanceof SplitTabComponent && tab.getAllTabs().length > 1) {
|
||||
commands.push({
|
||||
id: 'core:save-split-tab-as-profile',
|
||||
label: this.translate.instant('Save layout as profile'),
|
||||
group: 'core:common',
|
||||
locations: [CommandLocation.TabHeaderMenu],
|
||||
run: async () => {
|
||||
const modal = this.ngbModal.open(PromptModalComponent)
|
||||
modal.componentInstance.prompt = this.translate.instant('Profile name')
|
||||
const name = (await modal.result.catch(() => null))?.value
|
||||
if (!name) {
|
||||
return
|
||||
}
|
||||
this.splitLayoutProfilesService.createProfile(tab, name)
|
||||
},
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
return commands
|
||||
}
|
||||
}
|
||||
|
||||
/** @hidden */
|
||||
@Injectable({ providedIn: 'root' })
|
||||
export class TaskCompletionCommandProvider extends CommandProvider {
|
||||
constructor (
|
||||
private app: AppService,
|
||||
private translate: TranslateService,
|
||||
) {
|
||||
super()
|
||||
}
|
||||
|
||||
async provide (context: CommandContext): Promise<Command[]> {
|
||||
if (!context.tab) {
|
||||
return []
|
||||
}
|
||||
|
||||
const process = await context.tab.getCurrentProcess()
|
||||
const items: Command[] = []
|
||||
|
||||
const extTab: (BaseTabComponent & { __completionNotificationEnabled?: boolean, __outputNotificationSubscription?: Subscription|null }) = context.tab
|
||||
|
||||
if (process) {
|
||||
items.push({
|
||||
id: 'core:process-name',
|
||||
label: this.translate.instant('Current process: {name}', process),
|
||||
group: 'core:process',
|
||||
weight: -1,
|
||||
locations: [CommandLocation.TabBodyMenu, CommandLocation.TabHeaderMenu],
|
||||
})
|
||||
items.push({
|
||||
id: 'core:notify-when-done',
|
||||
label: this.translate.instant('Notify when done'),
|
||||
group: 'core:process',
|
||||
weight: 0,
|
||||
checked: extTab.__completionNotificationEnabled,
|
||||
locations: [CommandLocation.TabBodyMenu, CommandLocation.TabHeaderMenu],
|
||||
run: async () => {
|
||||
extTab.__completionNotificationEnabled = !extTab.__completionNotificationEnabled
|
||||
|
||||
if (extTab.__completionNotificationEnabled) {
|
||||
this.app.observeTabCompletion(extTab).subscribe(() => {
|
||||
new Notification(this.translate.instant('Process completed'), {
|
||||
body: process.name,
|
||||
}).addEventListener('click', () => {
|
||||
this.app.selectTab(extTab)
|
||||
})
|
||||
extTab.__completionNotificationEnabled = false
|
||||
})
|
||||
} else {
|
||||
this.app.stopObservingTabCompletion(extTab)
|
||||
}
|
||||
},
|
||||
})
|
||||
}
|
||||
items.push({
|
||||
id: 'core:notify-on-activity',
|
||||
label: this.translate.instant('Notify on activity'),
|
||||
group: 'core:process',
|
||||
checked: !!extTab.__outputNotificationSubscription,
|
||||
locations: [CommandLocation.TabBodyMenu, CommandLocation.TabHeaderMenu],
|
||||
run: async () => {
|
||||
extTab.clearActivity()
|
||||
|
||||
if (extTab.__outputNotificationSubscription) {
|
||||
extTab.__outputNotificationSubscription.unsubscribe()
|
||||
extTab.__outputNotificationSubscription = null
|
||||
} else {
|
||||
extTab.__outputNotificationSubscription = extTab.activity$.subscribe(active => {
|
||||
if (extTab.__outputNotificationSubscription && active) {
|
||||
extTab.__outputNotificationSubscription.unsubscribe()
|
||||
extTab.__outputNotificationSubscription = null
|
||||
new Notification(this.translate.instant('Tab activity'), {
|
||||
body: extTab.title,
|
||||
}).addEventListener('click', () => {
|
||||
this.app.selectTab(extTab)
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
},
|
||||
})
|
||||
return items
|
||||
}
|
||||
}
|
||||
|
@@ -1,17 +1,21 @@
|
||||
title-bar(
|
||||
*ngIf='ready && !hostWindow.isFullscreen && config.store.appearance.frame == "full" && config.store.appearance.dock == "off"',
|
||||
(dblclick)='hostWindow.toggleMaximize()',
|
||||
*ngIf='ready && !hostWindow.isFullscreen && config.store.appearance.dock == "off" && isTitleBarNeeded()',
|
||||
(dblclick)='toggleMaximize()',
|
||||
[hideControls]='hostApp.platform !== Platform.Linux && !hostWindow.isFullscreen',
|
||||
[class.inset]='hostApp.platform == Platform.macOS && !hostWindow.isFullscreen'
|
||||
)
|
||||
|
||||
.content(
|
||||
*ngIf='ready',
|
||||
[class.tabs-on-top]='config.store.appearance.tabsLocation == "top" || config.store.appearance.tabsLocation == "left"',
|
||||
[class.tabs-on-side]='hasVerticalTabs()',
|
||||
[class.tabs-on-top]='config.store.appearance.tabsLocation == "top" || config.store.appearance.tabsLocation == "left" || config.store.appearance.tabsLocation == "right"',
|
||||
[class.tabs-on-left]='hasVerticalTabs() && config.store.appearance.tabsLocation == "left"',
|
||||
[class.tabs-titlebar-enabled]='isTitleBarNeeded()',
|
||||
[class.tabs-on-right]='hasVerticalTabs() && config.store.appearance.tabsLocation == "right"',
|
||||
)
|
||||
.tab-bar(
|
||||
*ngIf='!hostWindow.isFullscreen || config.store.appearance.tabsInFullscreen',
|
||||
(dblclick)='hostWindow.toggleMaximize()'
|
||||
[class.tab-bar-no-controls-overlay]='hostApp.platform == Platform.macOS',
|
||||
(dblclick)='!isTitleBarNeeded() && toggleMaximize()'
|
||||
)
|
||||
.inset.background(*ngIf='hostApp.platform == Platform.macOS \
|
||||
&& !hostWindow.isFullscreen \
|
||||
@@ -31,8 +35,7 @@ title-bar(
|
||||
[@animateTab]='{value: "in", params: {size: targetTabSize}}',
|
||||
[@.disabled]='hasVerticalTabs() || !config.store.accessibility.animations',
|
||||
(click)='app.selectTab(tab)',
|
||||
[class.fully-draggable]='hostApp.platform != Platform.macOS',
|
||||
[class.drag-region]='hostApp.platform == Platform.macOS && !(app.tabDragActive$|async)',
|
||||
[class.fully-draggable]='hostApp.platform !== Platform.macOS'
|
||||
)
|
||||
|
||||
.btn-group.background
|
||||
@@ -61,7 +64,11 @@ title-bar(
|
||||
(transfersChange)='onTransfersChange()'
|
||||
)
|
||||
|
||||
.drag-space.background([class.persistent]='config.store.appearance.frame == "thin" && hostApp.platform != Platform.macOS')
|
||||
.btn-space.background(
|
||||
[class.persistent]='config.store.appearance.frame == "thin"',
|
||||
[class.drag]='config.store.appearance.frame == "thin" \
|
||||
&& ((config.store.appearance.tabsLocation !== "left" && config.store.appearance.tabsLocation !== "right") || hostApp.platform !== Platform.macOS)'
|
||||
)
|
||||
|
||||
.btn-group.background
|
||||
.d-flex(
|
||||
@@ -81,9 +88,14 @@ title-bar(
|
||||
|
||||
window-controls.background(
|
||||
*ngIf='config.store.appearance.frame == "thin" \
|
||||
&& (hostApp.platform == Platform.Windows || hostApp.platform == Platform.Linux)',
|
||||
&& config.store.appearance.tabsLocation !== "left" \
|
||||
&& config.store.appearance.tabsLocation !== "right" \
|
||||
&& hostApp.platform == Platform.Linux',
|
||||
)
|
||||
|
||||
div.window-controls-spacer(
|
||||
*ngIf='config.store.appearance.frame == "thin" && (hostApp.platform == Platform.Windows) && (config.store.appearance.tabsLocation == "top")',
|
||||
)
|
||||
.content
|
||||
start-page.content-tab.content-tab-active(*ngIf='ready && app.tabs.length == 0')
|
||||
|
||||
|
@@ -35,17 +35,16 @@ $tab-border-radius: 4px;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
&.tabs-on-side {
|
||||
&.tabs-on-right {
|
||||
flex-direction: row-reverse;
|
||||
|
||||
&.tabs-on-top {
|
||||
flex-direction: row;
|
||||
}
|
||||
}
|
||||
|
||||
&.tabs-on-left {
|
||||
flex-direction: row;
|
||||
}
|
||||
}
|
||||
|
||||
.content.tabs-on-side > .tab-bar {
|
||||
.content.tabs-on-left > .tab-bar, .content.tabs-on-right > .tab-bar {
|
||||
height: 100%;
|
||||
width: var(--side-tab-width);
|
||||
overflow-y: auto;
|
||||
@@ -63,7 +62,7 @@ $tab-border-radius: 4px;
|
||||
}
|
||||
}
|
||||
|
||||
.drag-space {
|
||||
.btn-space {
|
||||
flex: auto;
|
||||
}
|
||||
|
||||
@@ -76,6 +75,18 @@ $tab-border-radius: 4px;
|
||||
}
|
||||
}
|
||||
|
||||
.content.tabs-on-left > .tab-bar.tab-bar-no-controls-overlay, .content.tabs-titlebar-enabled {
|
||||
.tabs {
|
||||
padding-top: 0 !important;
|
||||
}
|
||||
}
|
||||
|
||||
.content.tabs-on-right > .tab-bar {
|
||||
.tabs {
|
||||
// Account for WCO on Windows.
|
||||
padding-top: 36px;
|
||||
}
|
||||
}
|
||||
|
||||
.tab-bar {
|
||||
flex: none;
|
||||
@@ -115,18 +126,28 @@ $tab-border-radius: 4px;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
&>.drag-space {
|
||||
&>.btn-space {
|
||||
min-width: 1px;
|
||||
flex: 1 0 1%;
|
||||
-webkit-app-region: drag;
|
||||
|
||||
.tabs-on-top & {
|
||||
margin-top: 2px; // for window resizing
|
||||
}
|
||||
|
||||
&.persistent {
|
||||
min-width: 72px; // 2 x 36 px height, ie 2 squares
|
||||
&.drag {
|
||||
-webkit-app-region: drag;
|
||||
}
|
||||
|
||||
&.persistent {
|
||||
// min-width: 72px; // 2 x 36 px height, ie 2 squares
|
||||
// Given WCO on Windows, the min-width of the window buttons is about 138px.
|
||||
min-width: 138px;
|
||||
}
|
||||
}
|
||||
|
||||
&>.window-controls-spacer {
|
||||
min-width: 138px;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
& > .inset {
|
||||
|
@@ -238,6 +238,21 @@ export class AppRootComponent {
|
||||
|
||||
private async getToolbarButtons (aboveZero: boolean): Promise<Command[]> {
|
||||
return (await this.commands.getCommands({ tab: this.app.activeTab ?? undefined }))
|
||||
.filter(x => x.locations?.includes(aboveZero ? CommandLocation.RightToolbar : CommandLocation.LeftToolbar))
|
||||
.filter(x => x.locations.includes(aboveZero ? CommandLocation.RightToolbar : CommandLocation.LeftToolbar))
|
||||
}
|
||||
|
||||
toggleMaximize (): void {
|
||||
this.hostWindow.toggleMaximize()
|
||||
}
|
||||
|
||||
protected isTitleBarNeeded (): boolean {
|
||||
return (
|
||||
this.config.store.appearance.frame === 'full'
|
||||
||
|
||||
this.hostApp.platform !== Platform.macOS
|
||||
&& this.config.store.appearance.frame === 'thin'
|
||||
&& this.config.store.appearance.tabsLocation !== 'top'
|
||||
&& this.config.store.appearance.tabsLocation !== 'bottom'
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@@ -75,6 +75,7 @@ export abstract class BaseTabComponent extends BaseComponent {
|
||||
private titleChange = new Subject<string>()
|
||||
private focused = new Subject<void>()
|
||||
private blurred = new Subject<void>()
|
||||
private visibility = new Subject<boolean>()
|
||||
private progress = new Subject<number|null>()
|
||||
private activity = new Subject<boolean>()
|
||||
private destroyed = new Subject<void>()
|
||||
@@ -83,6 +84,8 @@ export abstract class BaseTabComponent extends BaseComponent {
|
||||
|
||||
get focused$ (): Observable<void> { return this.focused }
|
||||
get blurred$ (): Observable<void> { return this.blurred }
|
||||
/* @hidden */
|
||||
get visibility$ (): Observable<boolean> { return this.visibility }
|
||||
get titleChange$ (): Observable<string> { return this.titleChange.pipe(distinctUntilChanged()) }
|
||||
get progress$ (): Observable<number|null> { return this.progress.pipe(distinctUntilChanged()) }
|
||||
get activity$ (): Observable<boolean> { return this.activity }
|
||||
@@ -125,7 +128,7 @@ export abstract class BaseTabComponent extends BaseComponent {
|
||||
}
|
||||
|
||||
/**
|
||||
* Shows the acticity marker on the tab header
|
||||
* Shows the activity marker on the tab header
|
||||
*/
|
||||
displayActivity (): void {
|
||||
if (!this.hasActivity) {
|
||||
@@ -135,7 +138,7 @@ export abstract class BaseTabComponent extends BaseComponent {
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the acticity marker from the tab header
|
||||
* Removes the activity marker from the tab header
|
||||
*/
|
||||
clearActivity (): void {
|
||||
if (this.hasActivity) {
|
||||
@@ -177,6 +180,11 @@ export abstract class BaseTabComponent extends BaseComponent {
|
||||
this.blurred.next()
|
||||
}
|
||||
|
||||
/* @hidden */
|
||||
emitVisibility (visibility: boolean): void {
|
||||
this.visibility.next(visibility)
|
||||
}
|
||||
|
||||
insertIntoContainer (container: ViewContainerRef): EmbeddedViewRef<any> {
|
||||
this.viewContainerEmbeddedRef = container.insert(this.hostView) as EmbeddedViewRef<any>
|
||||
this.viewContainer = container
|
||||
|
@@ -18,45 +18,58 @@ export class SelectorModalComponent<T> {
|
||||
@Input() selectedIndex = 0
|
||||
hasGroups = false
|
||||
@ViewChildren('item') itemChildren: QueryList<ElementRef>
|
||||
private preventEdit: boolean
|
||||
|
||||
constructor (
|
||||
public modalInstance: NgbActiveModal,
|
||||
) { }
|
||||
constructor (public modalInstance: NgbActiveModal) {
|
||||
this.preventEdit = false
|
||||
}
|
||||
|
||||
ngOnInit (): void {
|
||||
this.onFilterChange()
|
||||
this.hasGroups = this.options.some(x => x.group)
|
||||
}
|
||||
|
||||
@HostListener('keydown', ['$event']) onKeyUp (event: KeyboardEvent): void {
|
||||
if (event.key === 'PageUp' || event.key === 'ArrowUp' && event.metaKey) {
|
||||
this.selectedIndex -= 10
|
||||
event.preventDefault()
|
||||
} else if (event.key === 'PageDown' || event.key === 'ArrowDown' && event.metaKey) {
|
||||
this.selectedIndex += 10
|
||||
event.preventDefault()
|
||||
} else if (event.key === 'ArrowUp') {
|
||||
this.selectedIndex--
|
||||
event.preventDefault()
|
||||
} else if (event.key === 'ArrowDown') {
|
||||
this.selectedIndex++
|
||||
event.preventDefault()
|
||||
} else if (event.key === 'Enter') {
|
||||
this.selectOption(this.filteredOptions[this.selectedIndex])
|
||||
} else if (event.key === 'Escape') {
|
||||
@HostListener('keydown', ['$event']) onKeyDown (event: KeyboardEvent): void {
|
||||
if (event.key === 'Escape') {
|
||||
this.close()
|
||||
}
|
||||
if (event.key === 'Backspace' && this.canEditSelected()) {
|
||||
event.preventDefault()
|
||||
this.filter = this.filteredOptions[this.selectedIndex].freeInputEquivalent!
|
||||
this.onFilterChange()
|
||||
}
|
||||
} else if (this.filteredOptions.length > 0) {
|
||||
if (event.key === 'PageUp' || event.key === 'ArrowUp' && event.metaKey) {
|
||||
this.selectedIndex -= Math.min(10, Math.max(1, this.selectedIndex))
|
||||
event.preventDefault()
|
||||
} else if (event.key === 'PageDown' || event.key === 'ArrowDown' && event.metaKey) {
|
||||
this.selectedIndex += Math.min(10, Math.max(1, this.filteredOptions.length - this.selectedIndex - 1))
|
||||
event.preventDefault()
|
||||
} else if (event.key === 'ArrowUp') {
|
||||
this.selectedIndex--
|
||||
event.preventDefault()
|
||||
} else if (event.key === 'ArrowDown') {
|
||||
this.selectedIndex++
|
||||
event.preventDefault()
|
||||
} else if (event.key === 'Enter') {
|
||||
this.selectOption(this.filteredOptions[this.selectedIndex])
|
||||
} else if (event.key === 'Backspace' && !this.preventEdit) {
|
||||
if (this.canEditSelected()) {
|
||||
event.preventDefault()
|
||||
this.filter = this.filteredOptions[this.selectedIndex].freeInputEquivalent!
|
||||
this.onFilterChange()
|
||||
} else {
|
||||
this.preventEdit = true
|
||||
}
|
||||
}
|
||||
|
||||
this.selectedIndex = (this.selectedIndex + this.filteredOptions.length) % this.filteredOptions.length
|
||||
Array.from(this.itemChildren)[this.selectedIndex]?.nativeElement.scrollIntoView({
|
||||
behavior: 'smooth',
|
||||
block: 'nearest',
|
||||
})
|
||||
this.selectedIndex = (this.selectedIndex + this.filteredOptions.length) % this.filteredOptions.length
|
||||
|
||||
Array.from(this.itemChildren)[this.selectedIndex]?.nativeElement.scrollIntoView({
|
||||
behavior: 'smooth',
|
||||
block: 'nearest',
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@HostListener('keyup', ['$event']) onKeyUp (event: KeyboardEvent): void {
|
||||
if (event.key === 'Backspace' && this.preventEdit) {
|
||||
this.preventEdit = false
|
||||
}
|
||||
}
|
||||
|
||||
onFilterChange (): void {
|
||||
@@ -76,10 +89,11 @@ export class SelectorModalComponent<T> {
|
||||
{ sort: true },
|
||||
).search(f)
|
||||
|
||||
const freeOption = this.options.find(x => x.freeInputPattern)
|
||||
if (freeOption && !this.filteredOptions.includes(freeOption)) {
|
||||
this.filteredOptions.push(freeOption)
|
||||
}
|
||||
this.options.filter(x => x.freeInputPattern).sort(firstBy<SelectorOption<T>, number>(x => x.weight ?? 0)).forEach(freeOption => {
|
||||
if (!this.filteredOptions.includes(freeOption)) {
|
||||
this.filteredOptions.push(freeOption)
|
||||
}
|
||||
})
|
||||
}
|
||||
this.selectedIndex = Math.max(0, this.selectedIndex)
|
||||
this.selectedIndex = Math.min(this.filteredOptions.length - 1, this.selectedIndex)
|
||||
|
@@ -275,6 +275,7 @@ export class SplitTabComponent extends BaseTabComponent implements AfterViewInit
|
||||
}
|
||||
})
|
||||
this.blurred$.subscribe(() => this.getAllTabs().forEach(x => x.emitBlurred()))
|
||||
this.visibility$.subscribe(visibility => this.getAllTabs().forEach(x => x.emitVisibility(visibility)))
|
||||
|
||||
this.tabAdded$.subscribe(() => this.updateTitle())
|
||||
this.tabRemoved$.subscribe(() => this.updateTitle())
|
||||
@@ -349,7 +350,7 @@ export class SplitTabComponent extends BaseTabComponent implements AfterViewInit
|
||||
}
|
||||
break
|
||||
case 'close-pane':
|
||||
this.removeTab(this.focusedTab)
|
||||
this.focusedTab.destroy()
|
||||
break
|
||||
case 'pane-increase-vertical':
|
||||
this.resizePane('v')
|
||||
@@ -474,7 +475,7 @@ export class SplitTabComponent extends BaseTabComponent implements AfterViewInit
|
||||
|
||||
let target = relative ? this.getParentOf(relative) : null
|
||||
if (!target) {
|
||||
// Rewrap the root container just in case the orientation isn't compatibile
|
||||
// Rewrap the root container just in case the orientation isn't compatible
|
||||
target = new SplitContainer()
|
||||
target.orientation = ['l', 'r'].includes(side) ? 'h' : 'v'
|
||||
target.children = [this.root]
|
||||
|
@@ -1,5 +1,6 @@
|
||||
import { Component } from '@angular/core'
|
||||
import { DomSanitizer } from '@angular/platform-browser'
|
||||
import { firstBy } from 'thenby'
|
||||
import { HomeBaseService } from '../services/homeBase.service'
|
||||
import { CommandService } from '../services/commands.service'
|
||||
import { Command, CommandLocation } from '../api/commands'
|
||||
@@ -20,7 +21,8 @@ export class StartPageComponent {
|
||||
commands: CommandService,
|
||||
) {
|
||||
commands.getCommands({}).then(c => {
|
||||
this.commands = c.filter(x => x.locations?.includes(CommandLocation.StartPage))
|
||||
this.commands = c.filter(x => x.locations.includes(CommandLocation.StartPage))
|
||||
this.commands.sort(firstBy(x => x.weight ?? 0))
|
||||
})
|
||||
}
|
||||
|
||||
|
@@ -1,16 +1,19 @@
|
||||
/* eslint-disable @typescript-eslint/explicit-module-boundary-types */
|
||||
import { Component, Input, Optional, Inject, HostBinding, HostListener, NgZone } from '@angular/core'
|
||||
import { Component, Input, HostBinding, HostListener, NgZone } from '@angular/core'
|
||||
import { auditTime } from 'rxjs'
|
||||
import { TabContextMenuItemProvider } from '../api/tabContextMenuProvider'
|
||||
|
||||
import { BaseTabComponent } from './baseTab.component'
|
||||
import { SplitTabComponent } from './splitTab.component'
|
||||
import { HotkeysService } from '../services/hotkeys.service'
|
||||
import { AppService } from '../services/app.service'
|
||||
import { HostAppService, Platform } from '../api/hostApp'
|
||||
import { ConfigService } from '../services/config.service'
|
||||
import { BaseComponent } from './base.component'
|
||||
import { CommandService } from '../services/commands.service'
|
||||
import { MenuItemOptions } from '../api/menu'
|
||||
import { PlatformService } from '../api/platform'
|
||||
import { CommandContext, CommandLocation } from '../api/commands'
|
||||
|
||||
import { BaseComponent } from './base.component'
|
||||
import { SplitTabComponent } from './splitTab.component'
|
||||
|
||||
/** @hidden */
|
||||
@Component({
|
||||
@@ -31,8 +34,8 @@ export class TabHeaderComponent extends BaseComponent {
|
||||
public hostApp: HostAppService,
|
||||
private hotkeys: HotkeysService,
|
||||
private platform: PlatformService,
|
||||
private commands: CommandService,
|
||||
private zone: NgZone,
|
||||
@Optional() @Inject(TabContextMenuItemProvider) protected contextMenuProviders: TabContextMenuItemProvider[],
|
||||
) {
|
||||
super()
|
||||
this.subscribeUntilDestroyed(this.hotkeys.hotkey$, (hotkey) => {
|
||||
@@ -42,7 +45,6 @@ export class TabHeaderComponent extends BaseComponent {
|
||||
}
|
||||
}
|
||||
})
|
||||
this.contextMenuProviders.sort((a, b) => a.weight - b.weight)
|
||||
}
|
||||
|
||||
ngOnInit () {
|
||||
@@ -56,26 +58,17 @@ export class TabHeaderComponent extends BaseComponent {
|
||||
}
|
||||
|
||||
async buildContextMenu (): Promise<MenuItemOptions[]> {
|
||||
let items: MenuItemOptions[] = []
|
||||
const contexts: CommandContext[] = [{ tab: this.tab }]
|
||||
|
||||
// Top-level tab menu
|
||||
for (const section of await Promise.all(this.contextMenuProviders.map(x => x.getItems(this.tab, true)))) {
|
||||
items.push({ type: 'separator' })
|
||||
items = items.concat(section)
|
||||
}
|
||||
if (this.tab instanceof SplitTabComponent) {
|
||||
const tab = this.tab.getFocusedTab()
|
||||
if (tab) {
|
||||
for (let section of await Promise.all(this.contextMenuProviders.map(x => x.getItems(tab, true)))) {
|
||||
// eslint-disable-next-line @typescript-eslint/no-loop-func
|
||||
section = section.filter(item => !items.some(ex => ex.label === item.label))
|
||||
if (section.length) {
|
||||
items.push({ type: 'separator' })
|
||||
items = items.concat(section)
|
||||
}
|
||||
}
|
||||
contexts.push({ tab })
|
||||
}
|
||||
}
|
||||
return items.slice(1)
|
||||
|
||||
return this.commands.buildContextMenu(contexts, CommandLocation.TabHeaderMenu)
|
||||
}
|
||||
|
||||
onTabDragStart (tab: BaseTabComponent) {
|
||||
|
@@ -1,2 +1,2 @@
|
||||
.title((dblclick)='hostWindow.toggleMaximize()') Tabby
|
||||
window-controls
|
||||
window-controls(*ngIf="!hideControls")
|
||||
|
@@ -1,4 +1,4 @@
|
||||
import { Component } from '@angular/core'
|
||||
import { Component, Input } from '@angular/core'
|
||||
import { HostWindowService } from '../api'
|
||||
|
||||
/** @hidden */
|
||||
@@ -8,5 +8,7 @@ import { HostWindowService } from '../api'
|
||||
styleUrls: ['./titleBar.component.scss'],
|
||||
})
|
||||
export class TitleBarComponent {
|
||||
@Input() hideControls: boolean
|
||||
|
||||
constructor (public hostWindow: HostWindowService) { }
|
||||
}
|
||||
|
@@ -1,10 +1,10 @@
|
||||
.container.mt-5.mb-5
|
||||
.mb-4
|
||||
.container.mt-3.mb-3
|
||||
.mb-3
|
||||
.tabby-logo
|
||||
h1.tabby-title Tabby
|
||||
sup α
|
||||
|
||||
.text-center.mb-5(translate) Thank you for downloading Tabby!
|
||||
.text-center.mb-3(translate) Thank you for downloading Tabby!
|
||||
|
||||
.form-line
|
||||
.header
|
||||
@@ -16,13 +16,54 @@
|
||||
*ngFor='let lang of allLanguages'
|
||||
) {{lang.name}}
|
||||
|
||||
.form-line
|
||||
.header
|
||||
.title(translate) Switch color scheme
|
||||
|
||||
.btn-group(role='group')
|
||||
input.btn-check(
|
||||
type='radio',
|
||||
name='colorSchemeMode',
|
||||
[(ngModel)]='config.store.appearance.colorSchemeMode',
|
||||
(ngModelChange)='config.save()',
|
||||
id='colorSchemeModeAuto',
|
||||
[value]='"auto"'
|
||||
)
|
||||
label.btn.btn-secondary(
|
||||
for='colorSchemeModeAuto'
|
||||
)
|
||||
span(translate) From system
|
||||
input.btn-check(
|
||||
type='radio',
|
||||
name='colorSchemeMode',
|
||||
[(ngModel)]='config.store.appearance.colorSchemeMode',
|
||||
(ngModelChange)='config.save()',
|
||||
id='colorSchemeModeDark',
|
||||
[value]='"dark"'
|
||||
)
|
||||
label.btn.btn-secondary(
|
||||
for='colorSchemeModeDark'
|
||||
)
|
||||
span(translate) Always dark
|
||||
input.btn-check(
|
||||
type='radio',
|
||||
name='colorSchemeMode',
|
||||
[(ngModel)]='config.store.appearance.colorSchemeMode',
|
||||
(ngModelChange)='config.save()',
|
||||
id='colorSchemeModeLight',
|
||||
[value]='"light"'
|
||||
)
|
||||
label.btn.btn-secondary(
|
||||
for='colorSchemeModeLight'
|
||||
)
|
||||
span(translate) Always light
|
||||
|
||||
.form-line
|
||||
.header
|
||||
.title(translate) Enable analytics
|
||||
.description(translate) Help track the number of Tabby installs across the world!
|
||||
toggle([(ngModel)]='config.store.enableAnalytics')
|
||||
|
||||
|
||||
.form-line
|
||||
.header
|
||||
.title(translate) Enable global hotkey (Ctrl-Space)
|
||||
|
@@ -6,3 +6,8 @@
|
||||
max-height: 100%;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.tabby-logo {
|
||||
width: 60px;
|
||||
height: 60px;
|
||||
}
|
||||
|
@@ -9,5 +9,6 @@ export class CoreConfigProvider extends ConfigProvider {
|
||||
[Platform.Linux]: require('./configDefaults.linux.yaml').default,
|
||||
[Platform.Web]: require('./configDefaults.web.yaml').default,
|
||||
}
|
||||
|
||||
defaults = require('./configDefaults.yaml').default
|
||||
}
|
||||
|
@@ -23,6 +23,7 @@ hotkeys:
|
||||
duplicate-tab: []
|
||||
restart-tab: []
|
||||
reconnect-tab: []
|
||||
disconnect-tab: []
|
||||
explode-tab:
|
||||
- 'Ctrl-Shift-.'
|
||||
combine-tabs:
|
||||
|
@@ -40,6 +40,7 @@ hotkeys:
|
||||
duplicate-tab: []
|
||||
restart-tab: []
|
||||
reconnect-tab: []
|
||||
disconnect-tab: []
|
||||
explode-tab:
|
||||
- '⌘-Shift-.'
|
||||
combine-tabs:
|
||||
@@ -95,5 +96,3 @@ hotkeys:
|
||||
- '⌘-Shift-E'
|
||||
command-selector:
|
||||
- '⌘-Shift-P'
|
||||
appearance:
|
||||
vibrancy: true
|
||||
|
@@ -24,6 +24,7 @@ hotkeys:
|
||||
duplicate-tab: []
|
||||
restart-tab: []
|
||||
reconnect-tab: []
|
||||
disconnect-tab: []
|
||||
explode-tab:
|
||||
- 'Ctrl-Shift-.'
|
||||
combine-tabs:
|
||||
|
@@ -11,7 +11,7 @@ appearance:
|
||||
tabsLocation: top
|
||||
tabsInFullscreen: false
|
||||
cycleTabs: true
|
||||
theme: Standard
|
||||
theme: Follow the color scheme
|
||||
frame: thin
|
||||
css: '/* * { color: blue !important; } */'
|
||||
opacity: 1.0
|
||||
@@ -19,6 +19,7 @@ appearance:
|
||||
vibrancyType: 'blur'
|
||||
lastTabClosesWindow: false
|
||||
spaciness: 1
|
||||
colorSchemeMode: 'dark'
|
||||
terminal:
|
||||
showBuiltinProfiles: true
|
||||
showRecentProfiles: 3
|
||||
@@ -31,6 +32,7 @@ hotkeys:
|
||||
profile-selectors:
|
||||
__nonStructural: true
|
||||
profiles: []
|
||||
groups: []
|
||||
profileDefaults:
|
||||
__nonStructural: true
|
||||
ssh:
|
||||
@@ -54,3 +56,4 @@ hacks:
|
||||
disableVibrancyWhileDragging: false
|
||||
enableFluentBackground: false
|
||||
language: null
|
||||
defaultQuickConnectProvider: "ssh"
|
||||
|
@@ -2,7 +2,6 @@ import { Injectable } from '@angular/core'
|
||||
import { TranslateService } from '@ngx-translate/core'
|
||||
import { ProfilesService } from './services/profiles.service'
|
||||
import { HotkeyDescription, HotkeyProvider } from './api/hotkeyProvider'
|
||||
import { PartialProfile, Profile } from './api'
|
||||
|
||||
/** @hidden */
|
||||
@Injectable()
|
||||
@@ -268,7 +267,7 @@ export class AppHotkeyProvider extends HotkeyProvider {
|
||||
return [
|
||||
...this.hotkeys,
|
||||
...profiles.map(profile => ({
|
||||
id: `profile.${AppHotkeyProvider.getProfileHotkeyName(profile)}`,
|
||||
id: `profile.${ProfilesService.getProfileHotkeyName(profile)}`,
|
||||
name: this.translate.instant('New tab: {profile}', { profile: profile.name }),
|
||||
})),
|
||||
...this.profilesService.getProviders().map(provider => ({
|
||||
@@ -278,7 +277,4 @@ export class AppHotkeyProvider extends HotkeyProvider {
|
||||
]
|
||||
}
|
||||
|
||||
static getProfileHotkeyName (profile: PartialProfile<Profile>): string {
|
||||
return (profile.id ?? profile.name).replace(/\./g, '-')
|
||||
}
|
||||
}
|
||||
|
@@ -37,7 +37,7 @@ import { FastHtmlBindDirective } from './directives/fastHtmlBind.directive'
|
||||
import { DropZoneDirective } from './directives/dropZone.directive'
|
||||
import { CdkAutoDropGroup } from './directives/cdkAutoDropGroup.directive'
|
||||
|
||||
import { Theme, CLIHandler, TabContextMenuItemProvider, TabRecoveryProvider, HotkeyProvider, ConfigProvider, PlatformService, FileProvider, ProfilesService, ProfileProvider, SelectorOption, Profile, SelectorService, CommandProvider } from './api'
|
||||
import { Theme, CLIHandler, TabRecoveryProvider, HotkeyProvider, ConfigProvider, PlatformService, FileProvider, ProfilesService, ProfileProvider, QuickConnectProfileProvider, SelectorOption, Profile, SelectorService, CommandProvider } from './api'
|
||||
|
||||
import { AppService } from './services/app.service'
|
||||
import { ConfigService } from './services/config.service'
|
||||
@@ -49,10 +49,9 @@ import { CommandService } from './services/commands.service'
|
||||
import { StandardTheme, StandardCompactTheme, PaperTheme, NewTheme } from './theme'
|
||||
import { CoreConfigProvider } from './config'
|
||||
import { AppHotkeyProvider } from './hotkeys'
|
||||
import { TaskCompletionContextMenu, CommonOptionsContextMenu, TabManagementContextMenu, ProfilesContextMenu } from './tabContextMenu'
|
||||
import { LastCLIHandler, ProfileCLIHandler } from './cli'
|
||||
import { SplitLayoutProfilesService } from './profiles'
|
||||
import { CoreCommandProvider } from './commands'
|
||||
import { CoreCommandProvider, TaskCompletionCommandProvider } from './commands'
|
||||
|
||||
export function TranslateMessageFormatCompilerFactory (): TranslateMessageFormatCompiler {
|
||||
return new TranslateMessageFormatCompiler()
|
||||
@@ -65,16 +64,13 @@ const PROVIDERS = [
|
||||
{ provide: Theme, useClass: PaperTheme, multi: true },
|
||||
{ provide: Theme, useClass: NewTheme, multi: true },
|
||||
{ provide: ConfigProvider, useClass: CoreConfigProvider, multi: true },
|
||||
{ provide: TabContextMenuItemProvider, useClass: CommonOptionsContextMenu, multi: true },
|
||||
{ provide: TabContextMenuItemProvider, useClass: TabManagementContextMenu, multi: true },
|
||||
{ provide: TabContextMenuItemProvider, useClass: TaskCompletionContextMenu, multi: true },
|
||||
{ provide: TabContextMenuItemProvider, useClass: ProfilesContextMenu, multi: true },
|
||||
{ provide: TabRecoveryProvider, useExisting: SplitTabRecoveryProvider, multi: true },
|
||||
{ provide: CLIHandler, useClass: ProfileCLIHandler, multi: true },
|
||||
{ provide: CLIHandler, useClass: LastCLIHandler, multi: true },
|
||||
{ provide: FileProvider, useClass: VaultFileProvider, multi: true },
|
||||
{ provide: ProfileProvider, useExisting: SplitLayoutProfilesService, multi: true },
|
||||
{ provide: CommandProvider, useExisting: CoreCommandProvider, multi: true },
|
||||
{ provide: CommandProvider, useExisting: TaskCompletionCommandProvider, multi: true },
|
||||
{
|
||||
provide: LOCALE_ID,
|
||||
deps: [LocaleService],
|
||||
@@ -177,7 +173,7 @@ export default class AppModule { // eslint-disable-line @typescript-eslint/no-ex
|
||||
if (hotkey.startsWith('profile.')) {
|
||||
const id = hotkey.substring(hotkey.indexOf('.') + 1)
|
||||
const profiles = await profilesService.getProfiles()
|
||||
const profile = profiles.find(x => AppHotkeyProvider.getProfileHotkeyName(x) === id)
|
||||
const profile = profiles.find(x => ProfilesService.getProfileHotkeyName(x) === id)
|
||||
if (profile) {
|
||||
profilesService.openNewTabForProfile(profile)
|
||||
}
|
||||
@@ -188,10 +184,10 @@ export default class AppModule { // eslint-disable-line @typescript-eslint/no-ex
|
||||
if (!provider) {
|
||||
return
|
||||
}
|
||||
this.showSelector(provider)
|
||||
this.showSelector(provider).catch(() => null)
|
||||
}
|
||||
if (hotkey === 'command-selector') {
|
||||
commands.showSelector()
|
||||
commands.showSelector().catch(() => null)
|
||||
}
|
||||
|
||||
if (hotkey === 'profile-selector') {
|
||||
@@ -214,11 +210,12 @@ export default class AppModule { // eslint-disable-line @typescript-eslint/no-ex
|
||||
callback: () => this.profilesService.openNewTabForProfile(p),
|
||||
}))
|
||||
|
||||
if (provider.supportsQuickConnect) {
|
||||
if (provider instanceof QuickConnectProfileProvider) {
|
||||
options.push({
|
||||
name: this.translate.instant('Quick connect'),
|
||||
freeInputPattern: this.translate.instant('Connect to "%s"...'),
|
||||
icon: 'fas fa-arrow-right',
|
||||
description: `(${provider.name.toUpperCase()})`,
|
||||
callback: query => {
|
||||
const p = provider.quickConnect(query)
|
||||
if (p) {
|
||||
|
@@ -230,11 +230,13 @@ export class AppService {
|
||||
if (this._activeTab) {
|
||||
this._activeTab.clearActivity()
|
||||
this._activeTab.emitBlurred()
|
||||
this._activeTab.emitVisibility(false)
|
||||
}
|
||||
this._activeTab = tab
|
||||
this.activeTabChange.next(tab)
|
||||
setImmediate(() => {
|
||||
this._activeTab?.emitFocused()
|
||||
this._activeTab?.emitVisibility(true)
|
||||
})
|
||||
this.hostWindow.setTitle(this._activeTab?.title)
|
||||
}
|
||||
|
@@ -1,6 +1,10 @@
|
||||
import { Inject, Injectable, Optional } from '@angular/core'
|
||||
import { AppService, Command, CommandContext, CommandProvider, ConfigService, MenuItemOptions, SplitTabComponent, TabContextMenuItemProvider, ToolbarButton, ToolbarButtonProvider, TranslateService } from '../api'
|
||||
import { TranslateService } from '@ngx-translate/core'
|
||||
import { Command, CommandContext, CommandLocation, CommandProvider, MenuItemOptions, SplitTabComponent, TabContextMenuItemProvider, ToolbarButton, ToolbarButtonProvider } from '../api'
|
||||
import { AppService } from './app.service'
|
||||
import { ConfigService } from './config.service'
|
||||
import { SelectorService } from './selector.service'
|
||||
import { firstBy } from 'thenby'
|
||||
|
||||
@Injectable({ providedIn: 'root' })
|
||||
export class CommandService {
|
||||
@@ -11,11 +15,11 @@ export class CommandService {
|
||||
private config: ConfigService,
|
||||
private app: AppService,
|
||||
private translate: TranslateService,
|
||||
@Optional() @Inject(TabContextMenuItemProvider) protected contextMenuProviders: TabContextMenuItemProvider[],
|
||||
@Optional() @Inject(TabContextMenuItemProvider) protected contextMenuProviders: TabContextMenuItemProvider[]|null,
|
||||
@Optional() @Inject(ToolbarButtonProvider) private toolbarButtonProviders: ToolbarButtonProvider[],
|
||||
@Inject(CommandProvider) private commandProviders: CommandProvider[],
|
||||
) {
|
||||
this.contextMenuProviders.sort((a, b) => a.weight - b.weight)
|
||||
this.contextMenuProviders?.sort((a, b) => a.weight - b.weight)
|
||||
}
|
||||
|
||||
async getCommands (context: CommandContext): Promise<Command[]> {
|
||||
@@ -29,8 +33,8 @@ export class CommandService {
|
||||
let items: MenuItemOptions[] = []
|
||||
if (context.tab) {
|
||||
for (const tabHeader of [false, true]) {
|
||||
// Top-level tab menu
|
||||
for (let section of await Promise.all(this.contextMenuProviders.map(x => x.getItems(context.tab!, tabHeader)))) {
|
||||
// Top-level tab menu
|
||||
for (let section of await Promise.all(this.contextMenuProviders?.map(x => x.getItems(context.tab!, tabHeader)) ?? [])) {
|
||||
// eslint-disable-next-line @typescript-eslint/no-loop-func
|
||||
section = section.filter(item => !items.some(ex => ex.label === item.label))
|
||||
items = items.concat(section)
|
||||
@@ -38,7 +42,7 @@ export class CommandService {
|
||||
if (context.tab instanceof SplitTabComponent) {
|
||||
const tab = context.tab.getFocusedTab()
|
||||
if (tab) {
|
||||
for (let section of await Promise.all(this.contextMenuProviders.map(x => x.getItems(tab, tabHeader)))) {
|
||||
for (let section of await Promise.all(this.contextMenuProviders?.map(x => x.getItems(tab, tabHeader)) ?? [])) {
|
||||
// eslint-disable-next-line @typescript-eslint/no-loop-func
|
||||
section = section.filter(item => !items.some(ex => ex.label === item.label))
|
||||
items = items.concat(section)
|
||||
@@ -50,21 +54,10 @@ export class CommandService {
|
||||
|
||||
items = items.filter(x => (x.enabled ?? true) && x.type !== 'separator')
|
||||
|
||||
const flatItems: MenuItemOptions[] = []
|
||||
function flattenItem (item: MenuItemOptions, prefix?: string): void {
|
||||
if (item.submenu) {
|
||||
item.submenu.forEach(x => flattenItem(x, (prefix ? `${prefix} > ` : '') + (item.commandLabel ?? item.label)))
|
||||
} else {
|
||||
flatItems.push({
|
||||
...item,
|
||||
label: (prefix ? `${prefix} > ` : '') + (item.commandLabel ?? item.label),
|
||||
})
|
||||
}
|
||||
}
|
||||
items.forEach(x => flattenItem(x))
|
||||
|
||||
const commands = buttons.map(x => Command.fromToolbarButton(x))
|
||||
commands.push(...flatItems.map(x => Command.fromMenuItem(x)))
|
||||
const commands = [
|
||||
...buttons.map(x => Command.fromToolbarButton(x)),
|
||||
...items.map(x => Command.fromMenuItem(x)).flat(),
|
||||
]
|
||||
|
||||
for (const provider of this.config.enabledServices(this.commandProviders)) {
|
||||
commands.push(...await provider.provide(context))
|
||||
@@ -74,20 +67,36 @@ export class CommandService {
|
||||
.filter(c => !this.config.store.commandBlacklist.includes(c.id))
|
||||
.sort((a, b) => (a.weight ?? 0) - (b.weight ?? 0))
|
||||
.map(command => {
|
||||
const run = command.run
|
||||
command.run = async () => {
|
||||
// Serialize execution
|
||||
this.lastCommand = this.lastCommand.finally(run)
|
||||
await this.lastCommand
|
||||
if (command.run) {
|
||||
const run = command.run
|
||||
command.run = async () => {
|
||||
// Serialize execution
|
||||
this.lastCommand = this.lastCommand.finally(run)
|
||||
await this.lastCommand
|
||||
}
|
||||
}
|
||||
return command
|
||||
})
|
||||
}
|
||||
|
||||
async getCommandsWithContexts (context: CommandContext[]): Promise<Command[]> {
|
||||
let commands: Command[] = []
|
||||
|
||||
for (const commandSet of await Promise.all(context.map(x => this.getCommands(x)))) {
|
||||
for (const command of commandSet) {
|
||||
// eslint-disable-next-line @typescript-eslint/no-loop-func
|
||||
commands = commands.filter(x => x.id !== command.id)
|
||||
commands.push(command)
|
||||
}
|
||||
}
|
||||
|
||||
return commands
|
||||
}
|
||||
|
||||
async run (id: string, context: CommandContext): Promise<void> {
|
||||
const commands = await this.getCommands(context)
|
||||
const command = commands.find(x => x.id === id)
|
||||
await command?.run()
|
||||
await command?.run?.()
|
||||
}
|
||||
|
||||
async showSelector (): Promise<void> {
|
||||
@@ -95,20 +104,80 @@ export class CommandService {
|
||||
return
|
||||
}
|
||||
|
||||
const context: CommandContext = {}
|
||||
const tab = this.app.activeTab
|
||||
if (tab instanceof SplitTabComponent) {
|
||||
context.tab = tab.getFocusedTab() ?? undefined
|
||||
const contexts: CommandContext[] = [{}]
|
||||
if (this.app.activeTab) {
|
||||
contexts.push({ tab: this.app.activeTab })
|
||||
}
|
||||
const commands = await this.getCommands(context)
|
||||
await this.selector.show(
|
||||
if (this.app.activeTab instanceof SplitTabComponent) {
|
||||
const tab = this.app.activeTab.getFocusedTab()
|
||||
if (tab) {
|
||||
contexts.push({ tab })
|
||||
}
|
||||
}
|
||||
|
||||
const commands = (await this.getCommandsWithContexts(contexts))
|
||||
.filter(x => x.run)
|
||||
.sort(firstBy(x => x.weight ?? 0))
|
||||
|
||||
return this.selector.show(
|
||||
this.translate.instant('Commands'),
|
||||
commands.map(c => ({
|
||||
name: c.label,
|
||||
name: c.fullLabel ?? c.label,
|
||||
callback: c.run,
|
||||
description: c.sublabel,
|
||||
icon: c.icon,
|
||||
})),
|
||||
)
|
||||
}
|
||||
|
||||
/** @hidden */
|
||||
async buildContextMenu (contexts: CommandContext[], location: CommandLocation): Promise<MenuItemOptions[]> {
|
||||
let commands = await this.getCommandsWithContexts(contexts)
|
||||
|
||||
commands = commands.filter(x => x.locations.includes(location))
|
||||
commands.sort(firstBy(x => x.weight ?? 0))
|
||||
|
||||
interface Group {
|
||||
id?: string
|
||||
weight: number
|
||||
commands: Command[]
|
||||
}
|
||||
|
||||
const groups: Group[] = []
|
||||
|
||||
for (const command of commands.filter(x => !x.parent)) {
|
||||
let group = groups.find(x => x.id === command.group)
|
||||
if (!group) {
|
||||
group = {
|
||||
id: command.group,
|
||||
weight: 0,
|
||||
commands: [],
|
||||
}
|
||||
groups.push(group)
|
||||
}
|
||||
group.weight += command.weight ?? 0
|
||||
group.commands.push(command)
|
||||
}
|
||||
|
||||
groups.sort(firstBy(x => x.weight / x.commands.length))
|
||||
|
||||
function mapCommand (command: Command): MenuItemOptions {
|
||||
const submenu = command.id ? commands.filter(x => x.parent === command.id).map(mapCommand) : []
|
||||
return {
|
||||
label: command.label,
|
||||
submenu: submenu.length ? submenu : undefined,
|
||||
checked: command.checked,
|
||||
enabled: !!command.run || !!submenu.length,
|
||||
type: command.checked ? 'checkbox' : undefined,
|
||||
click: () => command.run?.(),
|
||||
}
|
||||
}
|
||||
|
||||
const items: MenuItemOptions[] = []
|
||||
for (const group of groups) {
|
||||
items.push({ type: 'separator' })
|
||||
items.push(...group.commands.map(mapCommand))
|
||||
}
|
||||
|
||||
return items.slice(1)
|
||||
}
|
||||
}
|
||||
|
@@ -10,11 +10,15 @@ import { PlatformService } from '../api/platform'
|
||||
import { HostAppService } from '../api/hostApp'
|
||||
import { Vault, VaultService } from './vault.service'
|
||||
import { serializeFunction } from '../utils'
|
||||
import { PartialProfileGroup, ProfileGroup } from '../api/profileProvider'
|
||||
const deepmerge = require('deepmerge')
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
|
||||
export const configMerge = (a, b) => deepmerge(a, b, { arrayMerge: (_d, s) => s }) // eslint-disable-line @typescript-eslint/no-var-requires
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
|
||||
export const configMergeByDefault = (a, b) => deepmerge(a, b) // eslint-disable-line @typescript-eslint/no-var-requires
|
||||
|
||||
const LATEST_VERSION = 1
|
||||
|
||||
function isStructuralMember (v) {
|
||||
@@ -162,7 +166,7 @@ export class ConfigService {
|
||||
defaults = configMerge(provider.defaults, defaults)
|
||||
}
|
||||
return defaults
|
||||
}).reduce(configMerge)
|
||||
}).reduce(configMergeByDefault)
|
||||
}
|
||||
|
||||
getDefaults (): Record<string, any> {
|
||||
@@ -213,7 +217,9 @@ export class ConfigService {
|
||||
* Reads config YAML as string
|
||||
*/
|
||||
readRaw (): string {
|
||||
return yaml.dump(this._store)
|
||||
// Scrub undefined values
|
||||
const cleanStore = JSON.parse(JSON.stringify(this._store))
|
||||
return yaml.dump(cleanStore)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -351,6 +357,63 @@ export class ConfigService {
|
||||
delete window.localStorage.lastSerialConnection
|
||||
config.version = 3
|
||||
}
|
||||
if (config.version < 4) {
|
||||
for (const p of config.profiles ?? []) {
|
||||
if (!p.id) {
|
||||
p.id = `${p.type}:custom:${uuidv4()}`
|
||||
}
|
||||
}
|
||||
config.version = 4
|
||||
}
|
||||
if (config.version < 5) {
|
||||
const groups: PartialProfileGroup<ProfileGroup>[] = []
|
||||
for (const p of config.profiles ?? []) {
|
||||
if (!(p.group ?? '').trim()) {
|
||||
continue
|
||||
}
|
||||
|
||||
let group = groups.find(x => x.name === p.group)
|
||||
if (!group) {
|
||||
group = {
|
||||
id: `${uuidv4()}`,
|
||||
name: `${p.group}`,
|
||||
}
|
||||
groups.push(group)
|
||||
}
|
||||
p.group = group.id
|
||||
}
|
||||
|
||||
const profileGroupCollapsed = JSON.parse(window.localStorage.profileGroupCollapsed ?? '{}')
|
||||
for (const g of groups) {
|
||||
if (profileGroupCollapsed[g.name]) {
|
||||
const collapsed = profileGroupCollapsed[g.name]
|
||||
// eslint-disable-next-line @typescript-eslint/no-dynamic-delete
|
||||
delete profileGroupCollapsed[g.name]
|
||||
profileGroupCollapsed[g.id] = collapsed
|
||||
}
|
||||
}
|
||||
window.localStorage.profileGroupCollapsed = JSON.stringify(profileGroupCollapsed)
|
||||
|
||||
config.groups = groups
|
||||
config.version = 5
|
||||
}
|
||||
if (config.version < 6) {
|
||||
if (config.ssh?.clearServiceMessagesOnConnect === false) {
|
||||
config.profileDefaults ??= {}
|
||||
config.profileDefaults.ssh ??= {}
|
||||
config.profileDefaults.ssh.clearServiceMessagesOnConnect = false
|
||||
delete config.ssh?.clearServiceMessagesOnConnect
|
||||
}
|
||||
config.version = 6
|
||||
}
|
||||
if (config.version < 7) {
|
||||
if (!config.configSync?.host || config.configSync?.host === 'https://api.tabby.sh') {
|
||||
config.configSync ??= {}
|
||||
delete config.configSync.host
|
||||
delete config.configSync.token
|
||||
}
|
||||
config.version = 7
|
||||
}
|
||||
}
|
||||
|
||||
private async maybeDecryptConfig (store) {
|
||||
|
@@ -13,8 +13,9 @@ export class FileProvidersService {
|
||||
) { }
|
||||
|
||||
async selectAndStoreFile (description: string): Promise<string> {
|
||||
const p = await this.selectProvider()
|
||||
return p.selectAndStoreFile(description)
|
||||
return this.selectProvider().then(p => {
|
||||
return p.selectAndStoreFile(description)
|
||||
})
|
||||
}
|
||||
|
||||
async retrieveFile (key: string): Promise<Buffer> {
|
||||
|
@@ -7,6 +7,7 @@ import localeENUS from '@angular/common/locales/en'
|
||||
import localeENGB from '@angular/common/locales/en-GB'
|
||||
import localeAF from '@angular/common/locales/af'
|
||||
import localeBG from '@angular/common/locales/bg'
|
||||
import localeCS from '@angular/common/locales/cs'
|
||||
import localeDA from '@angular/common/locales/da'
|
||||
import localeDE from '@angular/common/locales/de'
|
||||
import localeES from '@angular/common/locales/es'
|
||||
@@ -31,6 +32,7 @@ registerLocaleData(localeENUS)
|
||||
registerLocaleData(localeENGB)
|
||||
registerLocaleData(localeAF)
|
||||
registerLocaleData(localeBG)
|
||||
registerLocaleData(localeCS)
|
||||
registerLocaleData(localeDA)
|
||||
registerLocaleData(localeDE)
|
||||
registerLocaleData(localeES)
|
||||
@@ -82,6 +84,10 @@ export class LocaleService {
|
||||
code: 'id-ID',
|
||||
name: 'Bahasa Indonesia',
|
||||
},
|
||||
{
|
||||
code: 'cs-CZ',
|
||||
name: 'Čeština',
|
||||
},
|
||||
{
|
||||
code: 'da-DK',
|
||||
name: 'Dansk',
|
||||
|
@@ -2,12 +2,15 @@ import { Injectable, Inject } from '@angular/core'
|
||||
import { TranslateService } from '@ngx-translate/core'
|
||||
import { NewTabParameters } from './tabs.service'
|
||||
import { BaseTabComponent } from '../components/baseTab.component'
|
||||
import { PartialProfile, Profile, ProfileProvider } from '../api/profileProvider'
|
||||
import { QuickConnectProfileProvider, PartialProfile, PartialProfileGroup, Profile, ProfileGroup, ProfileProvider } from '../api/profileProvider'
|
||||
import { SelectorOption } from '../api/selector'
|
||||
import { AppService } from './app.service'
|
||||
import { configMerge, ConfigProxy, ConfigService } from './config.service'
|
||||
import { NotificationsService } from './notifications.service'
|
||||
import { SelectorService } from './selector.service'
|
||||
import deepClone from 'clone-deep'
|
||||
import { v4 as uuidv4 } from 'uuid'
|
||||
import slugify from 'slugify'
|
||||
|
||||
@Injectable({ providedIn: 'root' })
|
||||
export class ProfilesService {
|
||||
@@ -36,6 +39,127 @@ export class ProfilesService {
|
||||
@Inject(ProfileProvider) private profileProviders: ProfileProvider<Profile>[],
|
||||
) { }
|
||||
|
||||
/*
|
||||
* Methods used to interact with ProfileProvider
|
||||
*/
|
||||
|
||||
getProviders (): ProfileProvider<Profile>[] {
|
||||
return [...this.profileProviders]
|
||||
}
|
||||
|
||||
providerForProfile <T extends Profile> (profile: PartialProfile<T>): ProfileProvider<T>|null {
|
||||
const provider = this.profileProviders.find(x => x.id === profile.type) ?? null
|
||||
return provider as unknown as ProfileProvider<T>|null
|
||||
}
|
||||
|
||||
getDescription <P extends Profile> (profile: PartialProfile<P>): string|null {
|
||||
profile = this.getConfigProxyForProfile(profile)
|
||||
return this.providerForProfile(profile)?.getDescription(profile) ?? null
|
||||
}
|
||||
|
||||
/*
|
||||
* Methods used to interact with Profile
|
||||
*/
|
||||
|
||||
/*
|
||||
* Return ConfigProxy for a given Profile
|
||||
* arg: skipUserDefaults -> do not merge global provider defaults in ConfigProxy
|
||||
* arg: skipGroupDefaults -> do not merge parent group provider defaults in ConfigProxy
|
||||
*/
|
||||
getConfigProxyForProfile <T extends Profile> (profile: PartialProfile<T>, options?: { skipGlobalDefaults?: boolean, skipGroupDefaults?: boolean }): T {
|
||||
const defaults = this.getProfileDefaults(profile, options).reduce(configMerge, {})
|
||||
return new ConfigProxy(profile, defaults) as unknown as T
|
||||
}
|
||||
|
||||
/**
|
||||
* Return an Array of Profiles
|
||||
* arg: includeBuiltin (default: true) -> include BuiltinProfiles
|
||||
* arg: clone (default: false) -> return deepclone Array
|
||||
*/
|
||||
async getProfiles (options?: { includeBuiltin?: boolean, clone?: boolean }): Promise<PartialProfile<Profile>[]> {
|
||||
let list = this.config.store.profiles ?? []
|
||||
if (options?.includeBuiltin ?? true) {
|
||||
const lists = await Promise.all(this.config.enabledServices(this.profileProviders).map(x => x.getBuiltinProfiles()))
|
||||
list = [
|
||||
...this.config.store.profiles ?? [],
|
||||
...lists.reduce((a, b) => a.concat(b), []),
|
||||
]
|
||||
}
|
||||
|
||||
const sortKey = p => `${this.resolveProfileGroupName(p.group ?? '')} / ${p.name}`
|
||||
list.sort((a, b) => sortKey(a).localeCompare(sortKey(b)))
|
||||
list.sort((a, b) => (a.isBuiltin ? 1 : 0) - (b.isBuiltin ? 1 : 0))
|
||||
return options?.clone ? deepClone(list) : list
|
||||
}
|
||||
|
||||
/**
|
||||
* Insert a new Profile in config
|
||||
* arg: genId (default: true) -> generate uuid in before pushing Profile into config
|
||||
*/
|
||||
async newProfile (profile: PartialProfile<Profile>, options?: { genId?: boolean }): Promise<void> {
|
||||
if (options?.genId ?? true) {
|
||||
profile.id = `${profile.type}:custom:${slugify(profile.name)}:${uuidv4()}`
|
||||
}
|
||||
|
||||
const cProfile = this.config.store.profiles.find(p => p.id === profile.id)
|
||||
if (cProfile) {
|
||||
throw new Error(`Cannot insert new Profile, duplicated Id: ${profile.id}`)
|
||||
}
|
||||
|
||||
this.config.store.profiles.push(profile)
|
||||
}
|
||||
|
||||
/**
|
||||
* Write a Profile in config
|
||||
*/
|
||||
async writeProfile (profile: PartialProfile<Profile>): Promise<void> {
|
||||
const cProfile = this.config.store.profiles.find(p => p.id === profile.id)
|
||||
if (cProfile) {
|
||||
// Fully replace the config
|
||||
for (const k in cProfile) {
|
||||
// eslint-disable-next-line @typescript-eslint/no-dynamic-delete
|
||||
delete cProfile[k]
|
||||
}
|
||||
Object.assign(cProfile, profile)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete a Profile from config
|
||||
*/
|
||||
async deleteProfile (profile: PartialProfile<Profile>): Promise<void> {
|
||||
this.providerForProfile(profile)?.deleteProfile(this.getConfigProxyForProfile(profile))
|
||||
this.config.store.profiles = this.config.store.profiles.filter(p => p.id !== profile.id)
|
||||
|
||||
const profileHotkeyName = ProfilesService.getProfileHotkeyName(profile)
|
||||
if (this.config.store.hotkeys.profile.hasOwnProperty(profileHotkeyName)) {
|
||||
const profileHotkeys = deepClone(this.config.store.hotkeys.profile)
|
||||
// eslint-disable-next-line @typescript-eslint/no-dynamic-delete
|
||||
delete profileHotkeys[profileHotkeyName]
|
||||
this.config.store.hotkeys.profile = profileHotkeys
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete all Profiles from config using option filter
|
||||
* arg: filter (p: PartialProfile<Profile>) => boolean -> predicate used to decide which profiles have to be deleted
|
||||
*/
|
||||
async bulkDeleteProfiles (filter: (p: PartialProfile<Profile>) => boolean): Promise<void> {
|
||||
for (const profile of this.config.store.profiles.filter(filter)) {
|
||||
this.providerForProfile(profile)?.deleteProfile(this.getConfigProxyForProfile(profile))
|
||||
|
||||
const profileHotkeyName = ProfilesService.getProfileHotkeyName(profile)
|
||||
if (this.config.store.hotkeys.profile.hasOwnProperty(profileHotkeyName)) {
|
||||
const profileHotkeys = deepClone(this.config.store.hotkeys.profile)
|
||||
// eslint-disable-next-line @typescript-eslint/no-dynamic-delete
|
||||
delete profileHotkeys[profileHotkeyName]
|
||||
this.config.store.hotkeys.profile = profileHotkeys
|
||||
}
|
||||
}
|
||||
|
||||
this.config.store.profiles = this.config.store.profiles.filter(x => !filter(x))
|
||||
}
|
||||
|
||||
async openNewTabForProfile <P extends Profile> (profile: PartialProfile<P>): Promise<BaseTabComponent|null> {
|
||||
const params = await this.newTabParametersForProfile(profile)
|
||||
if (params) {
|
||||
@@ -63,52 +187,40 @@ export class ProfilesService {
|
||||
return params
|
||||
}
|
||||
|
||||
getProviders (): ProfileProvider<Profile>[] {
|
||||
return [...this.profileProviders]
|
||||
async launchProfile (profile: PartialProfile<Profile>): Promise<void> {
|
||||
await this.openNewTabForProfile(profile)
|
||||
|
||||
let recentProfiles: PartialProfile<Profile>[] = JSON.parse(window.localStorage['recentProfiles'] ?? '[]')
|
||||
if (this.config.store.terminal.showRecentProfiles > 0) {
|
||||
recentProfiles = recentProfiles.filter(x => x.group !== profile.group || x.name !== profile.name)
|
||||
recentProfiles.unshift(profile)
|
||||
recentProfiles = recentProfiles.slice(0, this.config.store.terminal.showRecentProfiles)
|
||||
} else {
|
||||
recentProfiles = []
|
||||
}
|
||||
window.localStorage['recentProfiles'] = JSON.stringify(recentProfiles)
|
||||
}
|
||||
|
||||
async getProfiles (): Promise<PartialProfile<Profile>[]> {
|
||||
const lists = await Promise.all(this.config.enabledServices(this.profileProviders).map(x => x.getBuiltinProfiles()))
|
||||
let list = lists.reduce((a, b) => a.concat(b), [])
|
||||
list = [
|
||||
...this.config.store.profiles ?? [],
|
||||
...list,
|
||||
]
|
||||
const sortKey = p => `${p.group ?? ''} / ${p.name}`
|
||||
list.sort((a, b) => sortKey(a).localeCompare(sortKey(b)))
|
||||
list.sort((a, b) => (a.isBuiltin ? 1 : 0) - (b.isBuiltin ? 1 : 0))
|
||||
return list
|
||||
static getProfileHotkeyName (profile: PartialProfile<Profile>): string {
|
||||
return (profile.id ?? profile.name).replace(/\./g, '-')
|
||||
}
|
||||
|
||||
providerForProfile <T extends Profile> (profile: PartialProfile<T>): ProfileProvider<T>|null {
|
||||
const provider = this.profileProviders.find(x => x.id === profile.type) ?? null
|
||||
return provider as unknown as ProfileProvider<T>|null
|
||||
}
|
||||
|
||||
getDescription <P extends Profile> (profile: PartialProfile<P>): string|null {
|
||||
profile = this.getConfigProxyForProfile(profile)
|
||||
return this.providerForProfile(profile)?.getDescription(profile) ?? null
|
||||
}
|
||||
/*
|
||||
* Methods used to interact with Profile Selector
|
||||
*/
|
||||
|
||||
selectorOptionForProfile <P extends Profile, T> (profile: PartialProfile<P>): SelectorOption<T> {
|
||||
const fullProfile = this.getConfigProxyForProfile(profile)
|
||||
const provider = this.providerForProfile(fullProfile)
|
||||
const freeInputEquivalent = provider?.intoQuickConnectString(fullProfile) ?? undefined
|
||||
const freeInputEquivalent = provider instanceof QuickConnectProfileProvider ? provider.intoQuickConnectString(fullProfile) ?? undefined : undefined
|
||||
return {
|
||||
...profile,
|
||||
// eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing
|
||||
group: profile.group || '',
|
||||
group: this.resolveProfileGroupName(profile.group ?? ''),
|
||||
freeInputEquivalent,
|
||||
description: provider?.getDescription(fullProfile),
|
||||
}
|
||||
}
|
||||
|
||||
getRecentProfiles (): PartialProfile<Profile>[] {
|
||||
let recentProfiles: PartialProfile<Profile>[] = JSON.parse(window.localStorage['recentProfiles'] ?? '[]')
|
||||
recentProfiles = recentProfiles.slice(0, this.config.store.terminal.showRecentProfiles)
|
||||
return recentProfiles
|
||||
}
|
||||
|
||||
showProfileSelector (): Promise<PartialProfile<Profile>|null> {
|
||||
if (this.selector.active) {
|
||||
return Promise.resolve(null)
|
||||
@@ -118,12 +230,12 @@ export class ProfilesService {
|
||||
try {
|
||||
const recentProfiles = this.getRecentProfiles()
|
||||
|
||||
let options: SelectorOption<void>[] = recentProfiles.map(p => ({
|
||||
let options: SelectorOption<void>[] = recentProfiles.map((p, i) => ({
|
||||
...this.selectorOptionForProfile(p),
|
||||
group: this.translate.instant('Recent'),
|
||||
icon: 'fas fa-history',
|
||||
color: p.color,
|
||||
weight: -2,
|
||||
weight: i - (recentProfiles.length + 1),
|
||||
callback: async () => {
|
||||
if (p.id) {
|
||||
p = (await this.getProfiles()).find(x => x.id === p.id) ?? p
|
||||
@@ -177,27 +289,38 @@ export class ProfilesService {
|
||||
})
|
||||
} catch { }
|
||||
|
||||
if (this.getProviders().some(x => x.supportsQuickConnect)) {
|
||||
options.push({
|
||||
name: this.translate.instant('Quick connect'),
|
||||
freeInputPattern: this.translate.instant('Connect to "%s"...'),
|
||||
icon: 'fas fa-arrow-right',
|
||||
callback: query => {
|
||||
const profile = this.quickConnect(query)
|
||||
resolve(profile)
|
||||
},
|
||||
})
|
||||
}
|
||||
await this.selector.show(this.translate.instant('Select profile or enter an address'), options)
|
||||
this.getProviders().forEach(provider => {
|
||||
if (provider instanceof QuickConnectProfileProvider) {
|
||||
options.push({
|
||||
name: this.translate.instant('Quick connect'),
|
||||
freeInputPattern: this.translate.instant('Connect to "%s"...'),
|
||||
description: `(${provider.name.toUpperCase()})`,
|
||||
icon: 'fas fa-arrow-right',
|
||||
weight: provider.id !== this.config.store.defaultQuickConnectProvider ? 1 : 0,
|
||||
callback: query => {
|
||||
const profile = provider.quickConnect(query)
|
||||
resolve(profile)
|
||||
},
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
await this.selector.show(this.translate.instant('Select profile or enter an address'), options).catch(() => reject())
|
||||
} catch (err) {
|
||||
reject(err)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
getRecentProfiles (): PartialProfile<Profile>[] {
|
||||
let recentProfiles: PartialProfile<Profile>[] = JSON.parse(window.localStorage['recentProfiles'] ?? '[]')
|
||||
recentProfiles = recentProfiles.slice(0, this.config.store.terminal.showRecentProfiles)
|
||||
return recentProfiles
|
||||
}
|
||||
|
||||
async quickConnect (query: string): Promise<PartialProfile<Profile>|null> {
|
||||
for (const provider of this.getProviders()) {
|
||||
if (provider.supportsQuickConnect) {
|
||||
if (provider instanceof QuickConnectProfileProvider) {
|
||||
const profile = provider.quickConnect(query)
|
||||
if (profile) {
|
||||
return profile
|
||||
@@ -208,27 +331,178 @@ export class ProfilesService {
|
||||
return null
|
||||
}
|
||||
|
||||
getConfigProxyForProfile <T extends Profile> (profile: PartialProfile<T>, skipUserDefaults = false): T {
|
||||
/*
|
||||
* Methods used to interact with Profile/ProfileGroup/Global defaults
|
||||
*/
|
||||
|
||||
/**
|
||||
* Return global defaults for a given profile provider
|
||||
* Always return something, empty object if no defaults found
|
||||
*/
|
||||
getProviderDefaults (provider: ProfileProvider<Profile>): any {
|
||||
const defaults = this.config.store.profileDefaults
|
||||
return defaults[provider.id] ?? {}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set global defaults for a given profile provider
|
||||
*/
|
||||
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
|
||||
setProviderDefaults (provider: ProfileProvider<Profile>, pdefaults: any): void {
|
||||
this.config.store.profileDefaults[provider.id] = pdefaults
|
||||
}
|
||||
|
||||
/**
|
||||
* Return defaults for a given profile
|
||||
* Always return something, empty object if no defaults found
|
||||
* arg: skipUserDefaults -> do not merge global provider defaults in ConfigProxy
|
||||
* arg: skipGroupDefaults -> do not merge parent group provider defaults in ConfigProxy
|
||||
*/
|
||||
getProfileDefaults (profile: PartialProfile<Profile>, options?: { skipGlobalDefaults?: boolean, skipGroupDefaults?: boolean }): any[] {
|
||||
const provider = this.providerForProfile(profile)
|
||||
const defaults = [
|
||||
|
||||
return [
|
||||
this.profileDefaults,
|
||||
provider?.configDefaults ?? {},
|
||||
!provider || skipUserDefaults ? {} : this.config.store.profileDefaults[provider.id] ?? {},
|
||||
].reduce(configMerge, {})
|
||||
return new ConfigProxy(profile, defaults) as unknown as T
|
||||
provider && !options?.skipGlobalDefaults ? this.getProviderDefaults(provider) : {},
|
||||
provider && !options?.skipGlobalDefaults && !options?.skipGroupDefaults ? this.getProviderProfileGroupDefaults(profile.group ?? '', provider) : {},
|
||||
]
|
||||
}
|
||||
|
||||
async launchProfile (profile: PartialProfile<Profile>): Promise<void> {
|
||||
await this.openNewTabForProfile(profile)
|
||||
/*
|
||||
* Methods used to interact with ProfileGroup
|
||||
*/
|
||||
|
||||
let recentProfiles: PartialProfile<Profile>[] = JSON.parse(window.localStorage['recentProfiles'] ?? '[]')
|
||||
if (this.config.store.terminal.showRecentProfiles > 0) {
|
||||
recentProfiles = recentProfiles.filter(x => x.group !== profile.group || x.name !== profile.name)
|
||||
recentProfiles.unshift(profile)
|
||||
recentProfiles = recentProfiles.slice(0, this.config.store.terminal.showRecentProfiles)
|
||||
} else {
|
||||
recentProfiles = []
|
||||
/**
|
||||
* Synchronously return an Array of the existing ProfileGroups
|
||||
* Does not return builtin groups
|
||||
*/
|
||||
getSyncProfileGroups (): PartialProfileGroup<ProfileGroup>[] {
|
||||
return deepClone(this.config.store.groups ?? [])
|
||||
}
|
||||
|
||||
/**
|
||||
* Return an Array of the existing ProfileGroups
|
||||
* arg: includeProfiles (default: false) -> if false, does not fill up the profiles field of ProfileGroup
|
||||
* arg: includeNonUserGroup (default: false) -> if false, does not add built-in and ungrouped groups
|
||||
*/
|
||||
async getProfileGroups (options?: { includeProfiles?: boolean, includeNonUserGroup?: boolean }): Promise<PartialProfileGroup<ProfileGroup>[]> {
|
||||
let profiles: PartialProfile<Profile>[] = []
|
||||
if (options?.includeProfiles) {
|
||||
profiles = await this.getProfiles({ includeBuiltin: options.includeNonUserGroup, clone: true })
|
||||
}
|
||||
window.localStorage['recentProfiles'] = JSON.stringify(recentProfiles)
|
||||
|
||||
let groups: PartialProfileGroup<ProfileGroup>[] = this.getSyncProfileGroups()
|
||||
groups = groups.map(x => {
|
||||
x.editable = true
|
||||
|
||||
if (options?.includeProfiles) {
|
||||
x.profiles = profiles.filter(p => p.group === x.id)
|
||||
profiles = profiles.filter(p => p.group !== x.id)
|
||||
}
|
||||
|
||||
return x
|
||||
})
|
||||
|
||||
if (options?.includeNonUserGroup) {
|
||||
const builtInGroups: PartialProfileGroup<ProfileGroup>[] = []
|
||||
builtInGroups.push({
|
||||
id: 'built-in',
|
||||
name: this.translate.instant('Built-in'),
|
||||
editable: false,
|
||||
profiles: [],
|
||||
})
|
||||
|
||||
const ungrouped: PartialProfileGroup<ProfileGroup> = {
|
||||
id: 'ungrouped',
|
||||
name: this.translate.instant('Ungrouped'),
|
||||
editable: false,
|
||||
}
|
||||
|
||||
if (options.includeProfiles) {
|
||||
for (const profile of profiles.filter(p => p.isBuiltin)) {
|
||||
let group: PartialProfileGroup<ProfileGroup> | undefined = builtInGroups.find(g => g.id === slugify(profile.group ?? 'built-in'))
|
||||
if (!group) {
|
||||
group = {
|
||||
id: `${slugify(profile.group!)}`,
|
||||
name: `${profile.group!}`,
|
||||
editable: false,
|
||||
profiles: [],
|
||||
}
|
||||
builtInGroups.push(group)
|
||||
}
|
||||
|
||||
group.profiles!.push(profile)
|
||||
}
|
||||
|
||||
ungrouped.profiles = profiles.filter(p => !p.isBuiltin)
|
||||
}
|
||||
|
||||
groups = groups.concat(builtInGroups)
|
||||
groups.push(ungrouped)
|
||||
}
|
||||
|
||||
return groups
|
||||
}
|
||||
|
||||
/**
|
||||
* Insert a new ProfileGroup in config
|
||||
* arg: genId (default: true) -> generate uuid in before pushing Profile into config
|
||||
*/
|
||||
async newProfileGroup (group: PartialProfileGroup<ProfileGroup>, options?: { genId?: boolean }): Promise<void> {
|
||||
if (options?.genId ?? true) {
|
||||
group.id = `${uuidv4()}`
|
||||
}
|
||||
|
||||
const cProfileGroup = this.config.store.groups.find(p => p.id === group.id)
|
||||
if (cProfileGroup) {
|
||||
throw new Error(`Cannot insert new ProfileGroup, duplicated Id: ${group.id}`)
|
||||
}
|
||||
|
||||
this.config.store.groups.push(group)
|
||||
}
|
||||
|
||||
/**
|
||||
* Write a ProfileGroup in config
|
||||
*/
|
||||
async writeProfileGroup (group: PartialProfileGroup<ProfileGroup>): Promise<void> {
|
||||
delete group.profiles
|
||||
delete group.editable
|
||||
|
||||
const cGroup = this.config.store.groups.find(g => g.id === group.id)
|
||||
if (cGroup) {
|
||||
Object.assign(cGroup, group)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete a ProfileGroup from config
|
||||
*/
|
||||
async deleteProfileGroup (group: PartialProfileGroup<ProfileGroup>, options?: { deleteProfiles?: boolean }): Promise<void> {
|
||||
this.config.store.groups = this.config.store.groups.filter(g => g.id !== group.id)
|
||||
if (options?.deleteProfiles) {
|
||||
await this.bulkDeleteProfiles((p) => p.group === group.id)
|
||||
} else {
|
||||
for (const profile of this.config.store.profiles.filter(x => x.group === group.id)) {
|
||||
delete profile.group
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolve and return ProfileGroup Name from ProfileGroup ID
|
||||
*/
|
||||
resolveProfileGroupName (groupId: string): string {
|
||||
return this.config.store.groups.find(g => g.id === groupId)?.name ?? groupId
|
||||
}
|
||||
|
||||
/**
|
||||
* Return defaults for a given group ID and provider
|
||||
* Always return something, empty object if no defaults found
|
||||
* arg: skipUserDefaults -> do not merge global provider defaults in ConfigProxy
|
||||
*/
|
||||
getProviderProfileGroupDefaults (groupId: string, provider: ProfileProvider<Profile>): any {
|
||||
return this.getSyncProfileGroups().find(g => g.id === groupId)?.defaults?.[provider.id] ?? {}
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -3,6 +3,7 @@ import { Subject, Observable } from 'rxjs'
|
||||
import * as Color from 'color'
|
||||
import { ConfigService } from '../services/config.service'
|
||||
import { Theme } from '../api/theme'
|
||||
import { PlatformService, PlatformTheme } from '../api/platform'
|
||||
import { NewTheme } from '../theme'
|
||||
|
||||
@Injectable({ providedIn: 'root' })
|
||||
@@ -17,6 +18,7 @@ export class ThemesService {
|
||||
private constructor (
|
||||
private config: ConfigService,
|
||||
private standardTheme: NewTheme,
|
||||
private platform: PlatformService,
|
||||
@Inject(Theme) private themes: Theme[],
|
||||
) {
|
||||
this.rootElementStyleBackup = document.documentElement.style.cssText
|
||||
@@ -24,6 +26,10 @@ export class ThemesService {
|
||||
config.ready$.toPromise().then(() => {
|
||||
this.applyCurrentTheme()
|
||||
this.applyThemeVariables()
|
||||
platform.themeChanged$.subscribe(() => {
|
||||
this.applyCurrentTheme()
|
||||
this.applyThemeVariables()
|
||||
})
|
||||
config.changed$.subscribe(() => {
|
||||
this.applyCurrentTheme()
|
||||
this.applyThemeVariables()
|
||||
@@ -36,7 +42,7 @@ export class ThemesService {
|
||||
document.documentElement.style.cssText = this.rootElementStyleBackup
|
||||
}
|
||||
|
||||
const theme = this.config.store.terminal.colorScheme
|
||||
const theme = this._getActiveColorScheme()
|
||||
const isDark = Color(theme.background).luminosity() < Color(theme.foreground).luminosity()
|
||||
|
||||
function more (some, factor) {
|
||||
@@ -106,8 +112,10 @@ export class ThemesService {
|
||||
|
||||
const themeColors = {
|
||||
primary: theme.colors[accentIndex],
|
||||
secondary: less(theme.background, 0.5).string(),
|
||||
tertiary: theme.colors[8],
|
||||
secondary: isDark
|
||||
? less(theme.background, 0.5).string()
|
||||
: less(theme.background, 0.125).string(),
|
||||
tertiary: more(theme.background, 0.75).string(),
|
||||
warning: theme.colors[3],
|
||||
danger: theme.colors[1],
|
||||
success: theme.colors[2],
|
||||
@@ -184,6 +192,22 @@ export class ThemesService {
|
||||
return this.findTheme(this.config.store.appearance.theme) ?? this.standardTheme
|
||||
}
|
||||
|
||||
/// @hidden
|
||||
_getActiveColorScheme (): any {
|
||||
let theme: PlatformTheme = 'dark'
|
||||
if (this.config.store.appearance.colorSchemeMode === 'light') {
|
||||
theme = 'light'
|
||||
} else if (this.config.store.appearance.colorSchemeMode === 'auto') {
|
||||
theme = this.platform.getTheme()
|
||||
}
|
||||
|
||||
if (theme === 'light') {
|
||||
return this.config.store.terminal.lightColorScheme
|
||||
} else {
|
||||
return this.config.store.terminal.colorScheme
|
||||
}
|
||||
}
|
||||
|
||||
applyTheme (theme: Theme): void {
|
||||
if (!this.styleElement) {
|
||||
this.styleElement = document.createElement('style')
|
||||
|
@@ -285,7 +285,7 @@ export class VaultFileProvider extends FileProvider {
|
||||
icon: 'fas fa-file',
|
||||
result: f,
|
||||
})),
|
||||
])
|
||||
]).catch(() => null)
|
||||
if (result) {
|
||||
return `${this.prefix}${result.key.id}`
|
||||
}
|
||||
|
@@ -1,298 +0,0 @@
|
||||
/* eslint-disable @typescript-eslint/explicit-module-boundary-types */
|
||||
import { Injectable } from '@angular/core'
|
||||
import { NgbModal } from '@ng-bootstrap/ng-bootstrap'
|
||||
import { TranslateService } from '@ngx-translate/core'
|
||||
import { Subscription } from 'rxjs'
|
||||
import { AppService } from './services/app.service'
|
||||
import { BaseTabComponent } from './components/baseTab.component'
|
||||
import { SplitTabComponent, SplitDirection } from './components/splitTab.component'
|
||||
import { TabContextMenuItemProvider } from './api/tabContextMenuProvider'
|
||||
import { MenuItemOptions } from './api/menu'
|
||||
import { ProfilesService } from './services/profiles.service'
|
||||
import { TabsService } from './services/tabs.service'
|
||||
import { HotkeysService } from './services/hotkeys.service'
|
||||
import { PromptModalComponent } from './components/promptModal.component'
|
||||
import { SplitLayoutProfilesService } from './profiles'
|
||||
import { TAB_COLORS } from './utils'
|
||||
|
||||
/** @hidden */
|
||||
@Injectable()
|
||||
export class TabManagementContextMenu extends TabContextMenuItemProvider {
|
||||
weight = 99
|
||||
|
||||
constructor (
|
||||
private app: AppService,
|
||||
private translate: TranslateService,
|
||||
) {
|
||||
super()
|
||||
}
|
||||
|
||||
async getItems (tab: BaseTabComponent): Promise<MenuItemOptions[]> {
|
||||
let items: MenuItemOptions[] = [
|
||||
{
|
||||
label: this.translate.instant('Close'),
|
||||
commandLabel: this.translate.instant('Close tab'),
|
||||
click: () => {
|
||||
if (this.app.tabs.includes(tab)) {
|
||||
this.app.closeTab(tab, true)
|
||||
} else {
|
||||
tab.destroy()
|
||||
}
|
||||
},
|
||||
},
|
||||
]
|
||||
if (!tab.parent) {
|
||||
items = [
|
||||
...items,
|
||||
{
|
||||
label: this.translate.instant('Close other tabs'),
|
||||
click: () => {
|
||||
for (const t of this.app.tabs.filter(x => x !== tab)) {
|
||||
this.app.closeTab(t, true)
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
label: this.translate.instant('Close tabs to the right'),
|
||||
click: () => {
|
||||
for (const t of this.app.tabs.slice(this.app.tabs.indexOf(tab) + 1)) {
|
||||
this.app.closeTab(t, true)
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
label: this.translate.instant('Close tabs to the left'),
|
||||
click: () => {
|
||||
for (const t of this.app.tabs.slice(0, this.app.tabs.indexOf(tab))) {
|
||||
this.app.closeTab(t, true)
|
||||
}
|
||||
},
|
||||
},
|
||||
]
|
||||
} else if (tab.parent instanceof SplitTabComponent) {
|
||||
const directions: SplitDirection[] = ['r', 'b', 'l', 't']
|
||||
items.push({
|
||||
label: this.translate.instant('Split'),
|
||||
submenu: directions.map(dir => ({
|
||||
label: {
|
||||
r: this.translate.instant('Right'),
|
||||
b: this.translate.instant('Down'),
|
||||
l: this.translate.instant('Left'),
|
||||
t: this.translate.instant('Up'),
|
||||
}[dir],
|
||||
commandLabel: {
|
||||
r: this.translate.instant('Split to the right'),
|
||||
b: this.translate.instant('Split to the down'),
|
||||
l: this.translate.instant('Split to the left'),
|
||||
t: this.translate.instant('Split to the up'),
|
||||
}[dir],
|
||||
click: () => {
|
||||
(tab.parent as SplitTabComponent).splitTab(tab, dir)
|
||||
},
|
||||
})) as MenuItemOptions[],
|
||||
})
|
||||
}
|
||||
return items
|
||||
}
|
||||
}
|
||||
|
||||
/** @hidden */
|
||||
@Injectable()
|
||||
export class CommonOptionsContextMenu extends TabContextMenuItemProvider {
|
||||
weight = -1
|
||||
|
||||
constructor (
|
||||
private app: AppService,
|
||||
private ngbModal: NgbModal,
|
||||
private splitLayoutProfilesService: SplitLayoutProfilesService,
|
||||
private translate: TranslateService,
|
||||
) {
|
||||
super()
|
||||
}
|
||||
|
||||
async getItems (tab: BaseTabComponent, tabHeader?: boolean): Promise<MenuItemOptions[]> {
|
||||
let items: MenuItemOptions[] = []
|
||||
if (tabHeader) {
|
||||
const currentColor = TAB_COLORS.find(x => x.value === tab.color)?.name
|
||||
items = [
|
||||
...items,
|
||||
{
|
||||
label: this.translate.instant('Rename'),
|
||||
commandLabel: this.translate.instant('Rename tab'),
|
||||
click: () => {
|
||||
this.app.renameTab(tab)
|
||||
},
|
||||
},
|
||||
{
|
||||
label: this.translate.instant('Duplicate'),
|
||||
commandLabel: this.translate.instant('Duplicate tab'),
|
||||
click: () => this.app.duplicateTab(tab),
|
||||
},
|
||||
{
|
||||
label: this.translate.instant('Color'),
|
||||
commandLabel: this.translate.instant('Change tab color'),
|
||||
sublabel: currentColor ? this.translate.instant(currentColor) : undefined,
|
||||
submenu: TAB_COLORS.map(color => ({
|
||||
label: this.translate.instant(color.name) ?? color.name,
|
||||
type: 'radio',
|
||||
checked: tab.color === color.value,
|
||||
click: () => {
|
||||
tab.color = color.value
|
||||
},
|
||||
})) as MenuItemOptions[],
|
||||
},
|
||||
]
|
||||
|
||||
if (tab instanceof SplitTabComponent && tab.getAllTabs().length > 1) {
|
||||
items.push({
|
||||
label: this.translate.instant('Save layout as profile'),
|
||||
click: async () => {
|
||||
const modal = this.ngbModal.open(PromptModalComponent)
|
||||
modal.componentInstance.prompt = this.translate.instant('Profile name')
|
||||
const name = (await modal.result)?.value
|
||||
if (!name) {
|
||||
return
|
||||
}
|
||||
this.splitLayoutProfilesService.createProfile(tab, name)
|
||||
},
|
||||
})
|
||||
}
|
||||
}
|
||||
return items
|
||||
}
|
||||
}
|
||||
|
||||
/** @hidden */
|
||||
@Injectable()
|
||||
export class TaskCompletionContextMenu extends TabContextMenuItemProvider {
|
||||
constructor (
|
||||
private app: AppService,
|
||||
private translate: TranslateService,
|
||||
) {
|
||||
super()
|
||||
}
|
||||
|
||||
async getItems (tab: BaseTabComponent): Promise<MenuItemOptions[]> {
|
||||
const process = await tab.getCurrentProcess()
|
||||
const items: MenuItemOptions[] = []
|
||||
|
||||
const extTab: (BaseTabComponent & { __completionNotificationEnabled?: boolean, __outputNotificationSubscription?: Subscription|null }) = tab
|
||||
|
||||
if (process) {
|
||||
items.push({
|
||||
enabled: false,
|
||||
label: this.translate.instant('Current process: {name}', process),
|
||||
})
|
||||
items.push({
|
||||
label: this.translate.instant('Notify when done'),
|
||||
type: 'checkbox',
|
||||
checked: extTab.__completionNotificationEnabled,
|
||||
click: () => {
|
||||
extTab.__completionNotificationEnabled = !extTab.__completionNotificationEnabled
|
||||
|
||||
if (extTab.__completionNotificationEnabled) {
|
||||
this.app.observeTabCompletion(tab).subscribe(() => {
|
||||
new Notification(this.translate.instant('Process completed'), {
|
||||
body: process.name,
|
||||
}).addEventListener('click', () => {
|
||||
this.app.selectTab(tab)
|
||||
})
|
||||
extTab.__completionNotificationEnabled = false
|
||||
})
|
||||
} else {
|
||||
this.app.stopObservingTabCompletion(tab)
|
||||
}
|
||||
},
|
||||
})
|
||||
}
|
||||
items.push({
|
||||
label: this.translate.instant('Notify on activity'),
|
||||
type: 'checkbox',
|
||||
checked: !!extTab.__outputNotificationSubscription,
|
||||
click: () => {
|
||||
tab.clearActivity()
|
||||
|
||||
if (extTab.__outputNotificationSubscription) {
|
||||
extTab.__outputNotificationSubscription.unsubscribe()
|
||||
extTab.__outputNotificationSubscription = null
|
||||
} else {
|
||||
extTab.__outputNotificationSubscription = tab.activity$.subscribe(active => {
|
||||
if (extTab.__outputNotificationSubscription && active) {
|
||||
extTab.__outputNotificationSubscription.unsubscribe()
|
||||
extTab.__outputNotificationSubscription = null
|
||||
new Notification(this.translate.instant('Tab activity'), {
|
||||
body: tab.title,
|
||||
}).addEventListener('click', () => {
|
||||
this.app.selectTab(tab)
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
},
|
||||
})
|
||||
return items
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/** @hidden */
|
||||
@Injectable()
|
||||
export class ProfilesContextMenu extends TabContextMenuItemProvider {
|
||||
weight = 10
|
||||
|
||||
constructor (
|
||||
private profilesService: ProfilesService,
|
||||
private tabsService: TabsService,
|
||||
private app: AppService,
|
||||
private translate: TranslateService,
|
||||
hotkeys: HotkeysService,
|
||||
) {
|
||||
super()
|
||||
hotkeys.hotkey$.subscribe(hotkey => {
|
||||
if (hotkey === 'switch-profile') {
|
||||
let tab = this.app.activeTab
|
||||
if (tab instanceof SplitTabComponent) {
|
||||
tab = tab.getFocusedTab()
|
||||
if (tab) {
|
||||
this.switchTabProfile(tab)
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
async switchTabProfile (tab: BaseTabComponent) {
|
||||
const profile = await this.profilesService.showProfileSelector()
|
||||
if (!profile) {
|
||||
return
|
||||
}
|
||||
|
||||
const params = await this.profilesService.newTabParametersForProfile(profile)
|
||||
if (!params) {
|
||||
return
|
||||
}
|
||||
|
||||
if (!await tab.canClose()) {
|
||||
return
|
||||
}
|
||||
|
||||
const newTab = this.tabsService.create(params)
|
||||
;(tab.parent as SplitTabComponent).replaceTab(tab, newTab)
|
||||
|
||||
tab.destroy()
|
||||
}
|
||||
|
||||
async getItems (tab: BaseTabComponent): Promise<MenuItemOptions[]> {
|
||||
|
||||
if (tab.parent instanceof SplitTabComponent && tab.parent.getAllTabs().length > 1) {
|
||||
return [
|
||||
{
|
||||
label: this.translate.instant('Switch profile'),
|
||||
click: () => this.switchTabProfile(tab),
|
||||
},
|
||||
]
|
||||
}
|
||||
|
||||
return []
|
||||
}
|
||||
}
|
@@ -110,7 +110,7 @@ body {
|
||||
}
|
||||
|
||||
.nav {
|
||||
--bs-nav-link-color: var(--theme-fg);
|
||||
--bs-nav-link-color: var(--theme-fg-more);
|
||||
--bs-nav-link-hover-color: var(--theme-fg-less);
|
||||
--bs-nav-link-disabled-color: var(--bs-gray);
|
||||
}
|
||||
@@ -119,8 +119,8 @@ body {
|
||||
--bs-nav-tabs-border-width: 2px;
|
||||
--bs-nav-tabs-border-radius: 0;
|
||||
--bs-nav-tabs-link-hover-border-color: var(--bs-body-bg);
|
||||
--bs-nav-tabs-border-color: var(--theme-fg-less-2);
|
||||
--bs-nav-tabs-link-active-color: var(--theme-fg-less-2);
|
||||
--bs-nav-tabs-border-color: var(--theme-fg);
|
||||
--bs-nav-tabs-link-active-color: var(--theme-fg);
|
||||
|
||||
--bs-nav-tabs-link-active-bg: transparent;
|
||||
--bs-nav-tabs-link-active-border-color: transparent;
|
||||
|
@@ -22,5 +22,6 @@ export class ElectronConfigProvider extends ConfigProvider {
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
defaults = {}
|
||||
}
|
||||
|
@@ -99,6 +99,7 @@ export default class ElectronModule {
|
||||
})
|
||||
this.registerGlobalHotkey()
|
||||
this.updateVibrancy()
|
||||
this.updateWindowControlsColor()
|
||||
})
|
||||
|
||||
config.changed$.subscribe(() => {
|
||||
@@ -131,6 +132,8 @@ export default class ElectronModule {
|
||||
|
||||
config.changed$.subscribe(() => this.updateVibrancy())
|
||||
|
||||
config.changed$.subscribe(() => this.updateWindowControlsColor())
|
||||
|
||||
config.ready$.toPromise().then(() => {
|
||||
dockMenu.update()
|
||||
})
|
||||
@@ -169,6 +172,15 @@ export default class ElectronModule {
|
||||
|
||||
this.hostWindow.setOpacity(this.config.store.appearance.opacity)
|
||||
}
|
||||
|
||||
private updateWindowControlsColor () {
|
||||
// if windows and not using native frame, WCO does not exist, return.
|
||||
if (this.hostApp.platform === Platform.Windows && this.config.store.appearance.frame === 'native') {
|
||||
return
|
||||
}
|
||||
|
||||
this.electron.ipcRenderer.send('window-set-window-controls-color', this.config.store.terminal.colorScheme)
|
||||
}
|
||||
}
|
||||
|
||||
export { ElectronHostWindow, ElectronHostAppService, ElectronService }
|
||||
|
@@ -1,5 +1,5 @@
|
||||
import { Injectable } from '@angular/core'
|
||||
import { App, IpcRenderer, Shell, Dialog, Clipboard, GlobalShortcut, Screen, AutoUpdater, TouchBar, BrowserWindow, Menu, MenuItem, PowerSaveBlocker } from 'electron'
|
||||
import { App, IpcRenderer, Shell, Dialog, Clipboard, GlobalShortcut, Screen, AutoUpdater, TouchBar, BrowserWindow, Menu, MenuItem, PowerSaveBlocker, NativeTheme } from 'electron'
|
||||
import * as remote from '@electron/remote'
|
||||
|
||||
export interface MessageBoxResponse {
|
||||
@@ -20,6 +20,7 @@ export class ElectronService {
|
||||
process: any
|
||||
autoUpdater: AutoUpdater
|
||||
powerSaveBlocker: PowerSaveBlocker
|
||||
nativeTheme: NativeTheme
|
||||
TouchBar: typeof TouchBar
|
||||
BrowserWindow: typeof BrowserWindow
|
||||
Menu: typeof Menu
|
||||
@@ -43,5 +44,7 @@ export class ElectronService {
|
||||
this.BrowserWindow = remote.BrowserWindow
|
||||
this.Menu = remote.Menu
|
||||
this.MenuItem = remote.MenuItem
|
||||
this.MenuItem = remote.MenuItem
|
||||
this.nativeTheme = remote.nativeTheme
|
||||
}
|
||||
}
|
||||
|
@@ -10,6 +10,8 @@ import { ElectronService } from '../services/electron.service'
|
||||
import { ElectronHostWindow } from './hostWindow.service'
|
||||
import { ShellIntegrationService } from './shellIntegration.service'
|
||||
import { ElectronHostAppService } from './hostApp.service'
|
||||
import { PlatformTheme } from '../../../tabby-core/src/api/platform'
|
||||
import { configPath } from '../../../app/lib/config'
|
||||
const fontManager = require('fontmanager-redux') // eslint-disable-line
|
||||
|
||||
/* eslint-disable block-scoped-var */
|
||||
@@ -35,11 +37,15 @@ export class ElectronPlatformService extends PlatformService {
|
||||
private translate: TranslateService,
|
||||
) {
|
||||
super()
|
||||
this.configPath = path.join(electron.app.getPath('userData'), 'config.yaml')
|
||||
this.configPath = configPath
|
||||
|
||||
electron.ipcRenderer.on('host:display-metrics-changed', () => {
|
||||
this.zone.run(() => this.displayMetricsChanged.next())
|
||||
})
|
||||
|
||||
electron.nativeTheme.on('updated', () => {
|
||||
this.zone.run(() => this.themeChanged.next(this.getTheme()))
|
||||
})
|
||||
}
|
||||
|
||||
readClipboard (): string {
|
||||
@@ -243,6 +249,14 @@ export class ElectronPlatformService extends PlatformService {
|
||||
},
|
||||
)).filePaths[0]
|
||||
}
|
||||
|
||||
getTheme (): PlatformTheme {
|
||||
if (this.electron.nativeTheme.shouldUseDarkColors) {
|
||||
return 'dark'
|
||||
} else {
|
||||
return 'light'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class ElectronFileUpload extends FileUpload {
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user