mirror of
https://github.com/hcengineering/platform.git
synced 2024-12-22 19:11:33 +03:00
iniital ui
contribution
Signed-off-by: Andrey Platov <andrey@hardcoreeng.com>
This commit is contained in:
parent
7a9a284855
commit
73d85935ba
File diff suppressed because it is too large
Load Diff
3
dev/prod/.gitignore
vendored
Normal file
3
dev/prod/.gitignore
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
stats.json
|
||||
dist/
|
||||
|
43
dev/prod/package.json
Normal file
43
dev/prod/package.json
Normal file
@ -0,0 +1,43 @@
|
||||
{
|
||||
"name": "prod",
|
||||
"version": "1.0.0",
|
||||
"license": "EPL-2.0",
|
||||
"scripts": {
|
||||
"build": "cross-env NODE_ENV=production webpack",
|
||||
"analyze": "cross-env NODE_ENV=production webpack --json > stats.json",
|
||||
"show": "webpack-bundle-analyzer stats.json dist",
|
||||
"dev": "webpack serve --content-base public",
|
||||
"dev-server": "cross-env CLIENT=server webpack serve --content-base public",
|
||||
"start": "cross-env NODE_ENV=production webpack serve --content-base public",
|
||||
"test": "echo 'no tests'",
|
||||
"preformat-svelte": "prettier -w src/**/*.svelte",
|
||||
"lint": "eslint --max-warnings=0 src",
|
||||
"lint:fix": "yarn preformat-svelte && eslint --fix src",
|
||||
"deploy": "cp -p public/* dist && aws s3 sync dist s3://anticrm-platform --delete --acl public-read"
|
||||
},
|
||||
"devDependencies": {
|
||||
"cross-env":"^7.0.3",
|
||||
"webpack":"^5.48.0",
|
||||
"webpack-cli":"^4.7.2",
|
||||
"mini-css-extract-plugin":"^2.2.0",
|
||||
"dotenv-webpack":"^7.0.3",
|
||||
"autoprefixer":"^10.3.1",
|
||||
"postcss":"^8.3.6",
|
||||
"svelte-preprocess":"^4.7.4",
|
||||
"ts-loader":"^9.2.5",
|
||||
"css-loader":"^6.2.0",
|
||||
"postcss-loader":"^6.1.1",
|
||||
"sass-loader":"^12.1.0",
|
||||
"svelte-loader":"^3.1.2",
|
||||
"postcss-load-config":"^3.1.0",
|
||||
"file-loader":"^6.2.0",
|
||||
"sass":"^1.37.5",
|
||||
"webpack-dev-server":"^3.11.2",
|
||||
"style-loader":"^3.2.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"@anticrm/ui": "~0.6.0",
|
||||
"@anticrm/theme": "~0.6.0",
|
||||
"svelte": "^3.42.1"
|
||||
}
|
||||
}
|
5
dev/prod/postcss.config.js
Normal file
5
dev/prod/postcss.config.js
Normal file
@ -0,0 +1,5 @@
|
||||
module.exports = {
|
||||
plugins: [
|
||||
require('autoprefixer')
|
||||
]
|
||||
}
|
BIN
dev/prod/public/favicon.png
Normal file
BIN
dev/prod/public/favicon.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 3.1 KiB |
18
dev/prod/public/index.html
Normal file
18
dev/prod/public/index.html
Normal file
@ -0,0 +1,18 @@
|
||||
<!doctype html>
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<meta charset='utf8'>
|
||||
<meta name='viewport' content='width=device-width'>
|
||||
|
||||
<title>Svelte app</title>
|
||||
|
||||
<link rel='icon' type='image/png' href='favicon.png'>
|
||||
<link rel='stylesheet' href='bundle.css'>
|
||||
</head>
|
||||
|
||||
<body style="margin: 0; overflow: hidden;">
|
||||
<script src='/bundle.js'></script>
|
||||
</body>
|
||||
|
||||
</html>
|
53
dev/prod/src/main.ts
Normal file
53
dev/prod/src/main.ts
Normal file
@ -0,0 +1,53 @@
|
||||
//
|
||||
// Copyright © 2020 Anticrm Platform Contributors.
|
||||
//
|
||||
// Licensed under the Eclipse Public License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License. You may
|
||||
// obtain a copy of the License at https://www.eclipse.org/legal/epl-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
//
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
// import { setMetadata } from '@anticrm/platform'
|
||||
import { createApp } from '@anticrm/ui'
|
||||
// import login from '@anticrm/login'
|
||||
// import pluginCore from '@anticrm/plugin-core'
|
||||
// import meetingPlugin from '@anticrm/meeting'
|
||||
|
||||
// import { configurePlatform } from './platform'
|
||||
|
||||
// configurePlatform()
|
||||
|
||||
// const accountsUrl = process.env.APP_ACCOUNTS_URL
|
||||
// const appHost = process.env.APP_WSHOST
|
||||
// const appPort = process.env.APP_WSPORT
|
||||
// const appToken = process.env.APP_TOKEN
|
||||
// const meetingHost = process.env.MEETING_WSHOST
|
||||
// const meetingPort = process.env.MEETING_WSPORT
|
||||
|
||||
// setMetadata(login.metadata.AccountsUrl, accountsUrl)
|
||||
// setMetadata(pluginCore.metadata.ClientUrl, `${appHost}:${appPort}/${appToken}`)
|
||||
// setMetadata(meetingPlugin.metadata.ClientUrl, `${meetingHost}:${meetingPort}`)
|
||||
// platform.setMetadata(core.metadata.WSHost, host)
|
||||
// platform.setMetadata(core.metadata.WSPort, port)
|
||||
|
||||
// const loginInfo = currentAccount()
|
||||
// if (loginInfo) {
|
||||
// platform.setMetadata(core.metadata.WhoAmI, loginInfo.email)
|
||||
// platform.setMetadata(core.metadata.Token, loginInfo.token)
|
||||
// }
|
||||
|
||||
// async function boot (): Promise<void> {
|
||||
// uiService.createApp(document.body)
|
||||
// }
|
||||
|
||||
// boot().catch(err => {
|
||||
// new ErrorPage({ target: document.body, props: { error: err.message } })
|
||||
// })
|
||||
|
||||
createApp(document.body)
|
57
dev/prod/src/platform.txt
Normal file
57
dev/prod/src/platform.txt
Normal file
@ -0,0 +1,57 @@
|
||||
//
|
||||
// Copyright © 2020 Anticrm Platform Contributors.
|
||||
//
|
||||
// Licensed under the Eclipse Public License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License. You may
|
||||
// obtain a copy of the License at https://www.eclipse.org/legal/epl-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
//
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
import { addLocation } from '@anticrm/platform'
|
||||
|
||||
import { loginId } from '@anticrm/login'
|
||||
import { clientId } from '@anticrm/client'
|
||||
import { workbenchId } from '@anticrm/workbench'
|
||||
import { chunterId } from '@anticrm/chunter'
|
||||
import { recruitId } from '@anticrm/recruit'
|
||||
import { tableId } from '@anticrm/table'
|
||||
import { viewId } from '@anticrm/view'
|
||||
import { taskId } from '@anticrm/task'
|
||||
import { contactId } from '@anticrm/contact'
|
||||
|
||||
import { chunterServerId } from '@anticrm/chunter-server'
|
||||
|
||||
import '@anticrm/login-assets'
|
||||
import '@anticrm/chunter-assets'
|
||||
import '@anticrm/recruit-assets'
|
||||
import '@anticrm/task-assets'
|
||||
import '@anticrm/view-assets'
|
||||
|
||||
export function configurePlatform() {
|
||||
|
||||
// platform.setMetadata(ui.metadata.LoginApplication, 'login')
|
||||
// platform.setMetadata(ui.metadata.DefaultApplication, 'workbench')
|
||||
|
||||
// if (process.env.CLIENT === 'dev')
|
||||
addLocation(clientId, () => import(/* webpackChunkName: "client-dev" */ '@anticrm/plugin-client-dev'))
|
||||
// else
|
||||
// addLocation(core, () => import(/* webpackChunkName: "plugin-core" */ '@anticrm/plugin-core-impl'))
|
||||
|
||||
addLocation(loginId, () => import(/* webpackChunkName: "login" */ '@anticrm/plugin-login'))
|
||||
addLocation(workbenchId, () => import(/* webpackChunkName: "workbench" */ '@anticrm/plugin-workbench'))
|
||||
addLocation(chunterId, () => import(/* webpackChunkName: "chunter" */ '@anticrm/plugin-chunter'))
|
||||
addLocation(recruitId, () => import(/* webpackChunkName: "recruit" */ '@anticrm/plugin-recruit'))
|
||||
addLocation(tableId, () => import(/* webpackChunkName: "table" */ '@anticrm/table-resources'))
|
||||
addLocation(viewId, () => import(/* webpackChunkName: "view" */ '@anticrm/view-resources'))
|
||||
addLocation(taskId, () => import(/* webpackChunkName: "task" */ '@anticrm/task-resources'))
|
||||
addLocation(contactId, () => import(/* webpackChunkName: "contact" */ '@anticrm/contact-resources'))
|
||||
|
||||
addLocation(chunterServerId, () => import(/* webpackChunkName: "chunter-server" */ '@anticrm/chunter-server'))
|
||||
|
||||
}
|
16
dev/prod/tsconfig.json
Normal file
16
dev/prod/tsconfig.json
Normal file
@ -0,0 +1,16 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"outDir": "./dist/",
|
||||
"noImplicitAny": true,
|
||||
"module": "esnext",
|
||||
"target": "esnext",
|
||||
"allowJs": true,
|
||||
"sourceMap": true,
|
||||
"moduleResolution": "node",
|
||||
"allowSyntheticDefaultImports": true,
|
||||
"lib": [
|
||||
"esnext",
|
||||
"dom"
|
||||
]
|
||||
}
|
||||
}
|
163
dev/prod/webpack.config.js
Normal file
163
dev/prod/webpack.config.js
Normal file
@ -0,0 +1,163 @@
|
||||
//
|
||||
// Copyright © 2020 Anticrm Platform Contributors.
|
||||
//
|
||||
// Licensed under the Eclipse Public License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License. You may
|
||||
// obtain a copy of the License at https://www.eclipse.org/legal/epl-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
//
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
const MiniCssExtractPlugin = require('mini-css-extract-plugin')
|
||||
const Dotenv = require('dotenv-webpack')
|
||||
const path = require('path')
|
||||
const autoprefixer = require('autoprefixer')
|
||||
|
||||
const mode = process.env.NODE_ENV || 'development'
|
||||
const prod = mode === 'production'
|
||||
|
||||
module.exports = {
|
||||
entry: {
|
||||
bundle: [
|
||||
'@anticrm/theme/styles/global.scss',
|
||||
'./src/main.ts'
|
||||
]
|
||||
},
|
||||
resolve: {
|
||||
symlinks: true,
|
||||
alias: {
|
||||
svelte: path.resolve('./node_modules', 'svelte')
|
||||
},
|
||||
extensions: ['.mjs', '.js', '.svelte', '.ts'],
|
||||
mainFields: ['svelte', 'browser', 'module', 'main']
|
||||
},
|
||||
output: {
|
||||
path: __dirname + '/dist',
|
||||
filename: '[name].js',
|
||||
chunkFilename: '[name].[id].js',
|
||||
publicPath: '/'
|
||||
},
|
||||
module: {
|
||||
rules: [
|
||||
{
|
||||
test: /\.ts?$/,
|
||||
use: 'ts-loader',
|
||||
exclude: /node_modules/
|
||||
},
|
||||
{
|
||||
test: /\.svelte$/,
|
||||
use: {
|
||||
loader: 'svelte-loader',
|
||||
options: {
|
||||
emitCss: true,
|
||||
preprocess: require('svelte-preprocess')({ postcss: true })
|
||||
}
|
||||
// options: {
|
||||
// dev: !prod,
|
||||
// emitCss: true,
|
||||
// hotReload: !prod,
|
||||
// preprocess: require('svelte-preprocess')({
|
||||
// babel: {
|
||||
// presets: [
|
||||
// [
|
||||
// '@babel/preset-env',
|
||||
// {
|
||||
// loose: true,
|
||||
// modules: false,
|
||||
// targets: {
|
||||
// esmodules: true
|
||||
// }
|
||||
// }
|
||||
// ],
|
||||
// '@babel/typescript'
|
||||
// ],
|
||||
// plugins: ['@babel/plugin-proposal-optional-chaining']
|
||||
// }
|
||||
// })
|
||||
// }
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
test: /\.css$/,
|
||||
use: [
|
||||
prod ? MiniCssExtractPlugin.loader : 'style-loader',
|
||||
'css-loader',
|
||||
'postcss-loader'
|
||||
]
|
||||
},
|
||||
|
||||
{
|
||||
test: /\.scss$/,
|
||||
use: [
|
||||
prod ? MiniCssExtractPlugin.loader : 'style-loader',
|
||||
'css-loader',
|
||||
'postcss-loader',
|
||||
'sass-loader',
|
||||
],
|
||||
},
|
||||
|
||||
{
|
||||
test: /\.(ttf|otf|eot|woff|woff2)$/,
|
||||
use: {
|
||||
loader: 'file-loader',
|
||||
options: {
|
||||
name: 'fonts/[name].[ext]',
|
||||
esModule: false
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
test: /\.(jpg|png)$/,
|
||||
use: {
|
||||
loader: 'file-loader',
|
||||
options: {
|
||||
name: 'img/[name].[ext]',
|
||||
esModule: false
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
test: /\.svg$/,
|
||||
use: [
|
||||
{
|
||||
loader: 'file-loader',
|
||||
options: {
|
||||
esModule: false
|
||||
}
|
||||
},
|
||||
{
|
||||
loader: 'svgo-loader',
|
||||
options: {
|
||||
plugins: [
|
||||
{ name: 'removeHiddenElems', active: false }
|
||||
// { removeHiddenElems: { displayNone: false } },
|
||||
// { cleanupIDs: false },
|
||||
// { removeTitle: true }
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
mode,
|
||||
plugins: [
|
||||
new MiniCssExtractPlugin({
|
||||
filename: '[name].css'
|
||||
}),
|
||||
new Dotenv()
|
||||
],
|
||||
devtool: prod ? false : 'source-map',
|
||||
devServer: {
|
||||
publicPath: '/',
|
||||
historyApiFallback: {
|
||||
disableDotRule: true
|
||||
}
|
||||
}
|
||||
}
|
BIN
packages/theme/fonts/complete/otf/Raleway-Bold.otf
Normal file
BIN
packages/theme/fonts/complete/otf/Raleway-Bold.otf
Normal file
Binary file not shown.
BIN
packages/theme/fonts/complete/otf/Raleway-Regular.otf
Normal file
BIN
packages/theme/fonts/complete/otf/Raleway-Regular.otf
Normal file
Binary file not shown.
BIN
packages/theme/fonts/complete/woff/IBMPlexSans-Bold.woff
Normal file
BIN
packages/theme/fonts/complete/woff/IBMPlexSans-Bold.woff
Normal file
Binary file not shown.
BIN
packages/theme/fonts/complete/woff/IBMPlexSans-Medium.woff
Normal file
BIN
packages/theme/fonts/complete/woff/IBMPlexSans-Medium.woff
Normal file
Binary file not shown.
BIN
packages/theme/fonts/complete/woff/IBMPlexSans-Regular.woff
Normal file
BIN
packages/theme/fonts/complete/woff/IBMPlexSans-Regular.woff
Normal file
Binary file not shown.
BIN
packages/theme/fonts/complete/woff/IBMPlexSans-SemiBold.woff
Normal file
BIN
packages/theme/fonts/complete/woff/IBMPlexSans-SemiBold.woff
Normal file
Binary file not shown.
BIN
packages/theme/fonts/complete/woff2/IBMPlexSans-Bold.woff2
Normal file
BIN
packages/theme/fonts/complete/woff2/IBMPlexSans-Bold.woff2
Normal file
Binary file not shown.
BIN
packages/theme/fonts/complete/woff2/IBMPlexSans-Medium.woff2
Normal file
BIN
packages/theme/fonts/complete/woff2/IBMPlexSans-Medium.woff2
Normal file
Binary file not shown.
BIN
packages/theme/fonts/complete/woff2/IBMPlexSans-Regular.woff2
Normal file
BIN
packages/theme/fonts/complete/woff2/IBMPlexSans-Regular.woff2
Normal file
Binary file not shown.
BIN
packages/theme/fonts/complete/woff2/IBMPlexSans-SemiBold.woff2
Normal file
BIN
packages/theme/fonts/complete/woff2/IBMPlexSans-SemiBold.woff2
Normal file
Binary file not shown.
24
packages/theme/package.json
Normal file
24
packages/theme/package.json
Normal file
@ -0,0 +1,24 @@
|
||||
{
|
||||
"name": "@anticrm/theme",
|
||||
"version": "0.6.0",
|
||||
"main": "src/index.ts",
|
||||
"svelte": "src/index.ts",
|
||||
"author": "Anticrm Platform Contributors",
|
||||
"license": "EPL-2.0",
|
||||
"scripts": {
|
||||
"build": "",
|
||||
"test": "echo 'no tests'",
|
||||
"lint": "ts-standard src",
|
||||
"lint:fix": "ts-standard --fix src",
|
||||
"format": "prettier --write 'src/**/*.{ts*,js*,yml}' && ts-standard --fix src",
|
||||
"svelte-check": "svelte-check"
|
||||
},
|
||||
"devDependencies": {
|
||||
"svelte-loader":"^3.1.2",
|
||||
"sass":"^1.37.5",
|
||||
"svelte-preprocess":"^4.7.4"
|
||||
},
|
||||
"dependencies": {
|
||||
"svelte": "^3.37.0"
|
||||
}
|
||||
}
|
5
packages/theme/postcss.config.js
Normal file
5
packages/theme/postcss.config.js
Normal file
@ -0,0 +1,5 @@
|
||||
module.exports = {
|
||||
plugins: [
|
||||
require('autoprefixer')
|
||||
]
|
||||
}
|
52
packages/theme/src/Theme.svelte
Normal file
52
packages/theme/src/Theme.svelte
Normal file
@ -0,0 +1,52 @@
|
||||
<!--
|
||||
// Copyright © 2020, 2021 Anticrm Platform Contributors.
|
||||
//
|
||||
// Licensed under the Eclipse Public License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License. You may
|
||||
// obtain a copy of the License at https://www.eclipse.org/legal/epl-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
//
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
-->
|
||||
|
||||
<script lang="ts">
|
||||
import { setContext, onMount } from 'svelte'
|
||||
|
||||
const getCurrentTheme = (): string => localStorage.getItem('theme') ?? 'theme-dark'
|
||||
const getCurrnetFontSize = (): string => localStorage.getItem('fontsize') ?? 'normal-font'
|
||||
const currentTheme = getCurrentTheme()
|
||||
const currentFontSize = getCurrnetFontSize()
|
||||
|
||||
const setRootColors = (theme: string) => {
|
||||
document.body.setAttribute('class', `${theme} ${getCurrnetFontSize()}`)
|
||||
}
|
||||
const setRootFontSize = (fontsize: string) => {
|
||||
document.body.setAttribute('class', `${getCurrentTheme()} ${fontsize}`)
|
||||
}
|
||||
|
||||
setContext('theme', {
|
||||
currentTheme: currentTheme,
|
||||
setTheme: (name: string) => {
|
||||
setRootColors(name)
|
||||
localStorage.setItem('theme', name)
|
||||
}
|
||||
})
|
||||
setContext('fontsize', {
|
||||
currentFontSize: currentFontSize,
|
||||
setFontSize: (fontsize: string) => {
|
||||
setRootFontSize(fontsize)
|
||||
localStorage.setItem('fontsize', fontsize)
|
||||
}
|
||||
})
|
||||
|
||||
onMount(() => {
|
||||
setRootColors(currentTheme)
|
||||
setRootFontSize(currentFontSize)
|
||||
})
|
||||
</script>
|
||||
|
||||
<slot/>
|
16
packages/theme/src/index.ts
Normal file
16
packages/theme/src/index.ts
Normal file
@ -0,0 +1,16 @@
|
||||
//
|
||||
// Copyright © 2020 Anticrm Platform Contributors.
|
||||
//
|
||||
// Licensed under the Eclipse Public License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License. You may
|
||||
// obtain a copy of the License at https://www.eclipse.org/legal/epl-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
//
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
export { default as Theme } from './Theme.svelte'
|
5
packages/theme/src/svelte.d.ts
vendored
Normal file
5
packages/theme/src/svelte.d.ts
vendored
Normal file
@ -0,0 +1,5 @@
|
||||
declare module '*.svelte' {
|
||||
import { SvelteComponent } from 'svelte'
|
||||
const Component: SvelteComponent
|
||||
export default Component
|
||||
}
|
206
packages/theme/styles/_colors.scss
Normal file
206
packages/theme/styles/_colors.scss
Normal file
@ -0,0 +1,206 @@
|
||||
//
|
||||
// Copyright © 2021 Anticrm Platform Contributors.
|
||||
//
|
||||
// Licensed under the Eclipse Public License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License. You may
|
||||
// obtain a copy of the License at https://www.eclipse.org/legal/epl-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
//
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
/* Common Colors */
|
||||
* {
|
||||
--primary-button-enabled: #4474F6;
|
||||
--primary-button-hovered: #2A5FF6;
|
||||
--primary-button-pressed: #194CD7;
|
||||
--primary-button-focused: #194CD7;
|
||||
--primary-button-disabled: #5771B9;
|
||||
--primary-button-focused-border: #7393EB;
|
||||
--primary-button-outline: rgba(87, 132, 255, .3);
|
||||
--primary-button-border: rgba(255, 255, 255, .09);
|
||||
|
||||
--system-error-color: #EE7A7A;
|
||||
--system-error-60-color: rgba(238, 122, 122, .6); // #EE7A7A / 60%
|
||||
|
||||
--activity-status-active: #34DB80;
|
||||
--activity-status-dnd: #D95757;
|
||||
--activity-status-busy: #FCC500;
|
||||
--activity-status-away: #9099A2;
|
||||
|
||||
--primary-color-purple-01: #4B38BD;
|
||||
--primary-color-purple-02: #6552DB;
|
||||
--primary-color-purple-03: #9D92C4;
|
||||
--primary-color-orange-01: #CC4726;
|
||||
--primary-color-orange-02: #F47758;
|
||||
--primary-color-skyblue: #93CAF3;
|
||||
--primary-color-pink: #FA8DA1;
|
||||
|
||||
--highlight-red: #F96E50;
|
||||
}
|
||||
|
||||
/* Dark Theme */
|
||||
.theme-dark {
|
||||
--theme-bg-color: #18181e;
|
||||
--theme-bg-selection: #282830;
|
||||
--theme-menu-color: #111117;
|
||||
--theme-menu-selection: #1D1D23;
|
||||
--theme-menu-divider: rgba(255, 255, 255, .05);
|
||||
--theme-scroll-bar: #2C2C34;
|
||||
--theme-bg-modal: #2C2B35;
|
||||
--theme-border-modal: rgba(0, 0, 0, 0.2);
|
||||
--theme-chat-selection: radial-gradient(135.96% 3333.35% at -2.36% -27.63%, rgba(210, 183, 156, 0.11) 0%, rgba(204, 196, 184, 0.0785128) 20.8%, rgba(104, 104, 114, 0.11) 100%);
|
||||
--theme-chat-divider: rgb(36, 36, 41);
|
||||
|
||||
--theme-bg-accent-color: rgba(255, 255, 255, .03);
|
||||
--theme-bg-accent-hover: rgba(255, 255, 255, .06);
|
||||
--theme-bg-accent-press: rgba(255, 255, 255, .07);
|
||||
--theme-bg-focused-color: rgba(255, 255, 255, .1);
|
||||
--theme-bg-focused-border: rgba(255, 255, 255, .4);
|
||||
--theme-bg-accent-error: rgba(251, 158, 158, .06);
|
||||
--theme-on-color: #94AEF3;
|
||||
--theme-off-color: #77818E;
|
||||
--theme-bg-check: #F2F2F2;
|
||||
--theme-tooltip-color: #2C2C34;
|
||||
|
||||
--theme-button-bg-enabled: #1F1F25;
|
||||
--theme-button-bg-hovered: #26262B;
|
||||
--theme-button-bg-pressed: #2A2A30;
|
||||
--theme-button-bg-disabled: #212127;
|
||||
--theme-button-bg-focused: #2F2F34;
|
||||
--theme-button-bg-error: #262026;
|
||||
--theme-button-border-enabled: rgba(255, 255, 255, .06);
|
||||
--theme-button-border-hovered: rgba(255, 255, 255, .08);
|
||||
--theme-button-border-pressed: rgba(255, 255, 255, .12);
|
||||
--theme-button-border-disabled: rgba(255, 255, 255, .06);
|
||||
--theme-button-border-focused: rgba(255, 255, 255, .4);
|
||||
--theme-button-border-error: rgba(205, 104, 104, .1);
|
||||
|
||||
--theme-caption-color: #fff;
|
||||
--theme-content-accent-color: rgba(255, 255, 255, 0.8);
|
||||
--theme-content-color: rgba(255, 255, 255, 0.6);
|
||||
--theme-content-dark-color: rgba(255, 255, 255, 0.4);
|
||||
--theme-content-trans-color: rgba(255, 255, 255, 0.3);
|
||||
|
||||
--theme-userlink-color: #b92d52;
|
||||
--theme-userlink-hover: #b92d52;
|
||||
--theme-doclink-color: #2d6ab9;
|
||||
--theme-doclink-hover: #2d6ab9;
|
||||
--theme-status-online: #6cd871;
|
||||
--theme-shadow: 0px 4px 8px rgba(15, 15, 15, 0.5);
|
||||
--theme-text-shadow: 0px 0px 8px rgba(255, 255, 255, 0.25);
|
||||
}
|
||||
|
||||
/* Grey Theme */
|
||||
.theme-grey {
|
||||
--theme-bg-color: #393844;
|
||||
--theme-bg-selection: #454351;
|
||||
--theme-menu-color: #2C2B35;
|
||||
--theme-menu-selection: #37363F;
|
||||
--theme-menu-divider: rgba(255, 255, 255, .05);
|
||||
--theme-scroll-bar: #494852;
|
||||
--theme-bg-modal: #2C2B35;
|
||||
--theme-border-modal: rgba(0, 0, 0, 0.2);
|
||||
--theme-chat-selection: radial-gradient(135.96% 3333.35% at -2.36% -27.63%, rgba(210, 183, 156, 0.11) 0%, rgba(204, 196, 184, 0.0785128) 20.8%, rgba(104, 104, 114, 0.11) 100%);
|
||||
--theme-chat-divider: rgb(66, 65, 76);
|
||||
|
||||
--theme-bg-accent-color: rgba(255, 255, 255, .03);
|
||||
--theme-bg-accent-hover: rgba(255, 255, 255, .06);
|
||||
--theme-bg-accent-press: rgba(255, 255, 255, .07);
|
||||
--theme-bg-focused-color: rgba(255, 255, 255, .1);
|
||||
--theme-bg-focused-border: rgba(255, 255, 255, .4);
|
||||
--theme-bg-accent-error: rgba(251, 158, 158, .06);
|
||||
--theme-on-color: #94AEF3;
|
||||
--theme-off-color: #77818E;
|
||||
--theme-bg-check: #F2F2F2;
|
||||
--theme-tooltip-color: #4D4C58;
|
||||
|
||||
--theme-button-bg-enabled: #3F3E4A;
|
||||
--theme-button-bg-hovered: #45444F;
|
||||
--theme-button-bg-pressed: #494853;
|
||||
--theme-button-bg-disabled: #41404B;
|
||||
--theme-button-bg-focused: #4D4C57;
|
||||
--theme-button-bg-error: #453E49;
|
||||
--theme-button-border-enabled: rgba(255, 255, 255, .06);
|
||||
--theme-button-border-hovered: rgba(255, 255, 255, .08);
|
||||
--theme-button-border-pressed: rgba(255, 255, 255, .12);
|
||||
--theme-button-border-disabled: rgba(255, 255, 255, .06);
|
||||
--theme-button-border-focused: rgba(255, 255, 255, .4);
|
||||
--theme-button-border-error: rgba(205, 104, 104, .1);
|
||||
|
||||
--theme-caption-color: #fff;
|
||||
--theme-content-accent-color: rgba(255, 255, 255, 0.8);
|
||||
--theme-content-color: rgba(255, 255, 255, 0.6);
|
||||
--theme-content-dark-color: rgba(255, 255, 255, 0.4);
|
||||
--theme-content-trans-color: rgba(255, 255, 255, 0.3);
|
||||
|
||||
--theme-userlink-color: #b92d52;
|
||||
--theme-userlink-hover: #b92d52;
|
||||
--theme-doclink-color: #2d6ab9;
|
||||
--theme-doclink-hover: #2d6ab9;
|
||||
--theme-status-online: #6cd871;
|
||||
--theme-shadow: 0px 4px 8px rgba(15, 15, 15, 0.5);
|
||||
}
|
||||
|
||||
/* Light Theme */
|
||||
.theme-light {
|
||||
--theme-bg-color: #FFFFFF;
|
||||
--theme-bg-selection: #F1F1F4;
|
||||
--theme-menu-color: #E7E7E7;
|
||||
--theme-menu-selection: #DBDBDB;
|
||||
--theme-menu-divider: rgba(0, 0, 0, .08);
|
||||
--theme-scroll-bar: #CBCBCB;
|
||||
--theme-bg-modal: #fff;
|
||||
--theme-border-modal: rgba(0, 0, 0, 0.2);
|
||||
--theme-chat-selection: radial-gradient(135.96% 3333.35% at -2.36% -27.63%, rgba(210, 183, 156, 0.11) 0%, rgba(204, 196, 184, 0.0785128) 20.8%, rgba(104, 104, 114, 0.11) 100%);
|
||||
--theme-chat-divider: rgb(233, 233, 233);
|
||||
|
||||
--theme-bg-accent-color: rgba(0, 0, 0, .03);
|
||||
--theme-bg-accent-hover: rgba(0, 0, 0, .05);
|
||||
--theme-bg-accent-press: rgba(0, 0, 0, .07);
|
||||
--theme-bg-focused-color: rgba(0, 0, 0, .03);
|
||||
--theme-bg-focused-border: rgba(0, 0, 0, .4);
|
||||
--theme-bg-accent-error: rgba(251, 158, 158, .06);
|
||||
--theme-on-color: #4474F6;
|
||||
--theme-off-color: #ECEEF5;
|
||||
--theme-bg-check: #45444F;
|
||||
--theme-tooltip-color: #F1F1F4;
|
||||
|
||||
--theme-button-bg-enabled: #F7F7F7;
|
||||
--theme-button-bg-hovered: #F2F2F2;
|
||||
--theme-button-bg-pressed: #EDEDED;
|
||||
--theme-button-bg-disabled: #F7F7F7;
|
||||
--theme-button-bg-focused: #F7F7F7;
|
||||
--theme-button-bg-error: #FEF2F2;
|
||||
--theme-button-border-enabled: rgba(0, 0, 0, .06);
|
||||
--theme-button-border-hovered: rgba(0, 0, 0, .06);
|
||||
--theme-button-border-pressed: rgba(255, 255, 255, .06);
|
||||
--theme-button-border-disabled: rgba(255, 255, 255, .06);
|
||||
--theme-button-border-focused: rgba(255, 255, 255, .4);
|
||||
--theme-button-border-error: rgba(205, 104, 104, .1);
|
||||
|
||||
--theme-caption-color: #272121;
|
||||
--theme-content-accent-color: rgba(39, 33, 33, 0.8);
|
||||
--theme-content-color: rgba(39, 33, 33, 0.6);
|
||||
--theme-content-dark-color: rgba(39, 33, 33, 0.4);
|
||||
--theme-content-trans-color: rgba(31, 33, 43, 0.3);
|
||||
|
||||
--theme-userlink-color: #b92d52;
|
||||
--theme-userlink-hover: #b92d52;
|
||||
--theme-doclink-color: #2d6ab9;
|
||||
--theme-doclink-hover: #2d6ab9;
|
||||
--theme-status-online: #4ebc53;
|
||||
--theme-shadow: 0px 4px 8px rgba(155, 155, 155, 0.5);
|
||||
}
|
||||
|
||||
.small-font {
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.normal-font {
|
||||
font-size: 14px;
|
||||
}
|
94
packages/theme/styles/global.scss
Normal file
94
packages/theme/styles/global.scss
Normal file
@ -0,0 +1,94 @@
|
||||
//
|
||||
// Copyright © 2021 Anticrm Platform Contributors.
|
||||
//
|
||||
// Licensed under the Eclipse Public License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License. You may
|
||||
// obtain a copy of the License at https://www.eclipse.org/legal/epl-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
//
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
@import "./_colors.scss";
|
||||
|
||||
@font-face {
|
||||
font-family: 'IBM Plex Sans';
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
src: local('IBM Plex Sans'),
|
||||
local('IBMPlexSans'),
|
||||
url('../fonts/complete/woff2/IBMPlexSans-Regular.woff2') format('woff2'),
|
||||
url('../fonts/complete/woff/IBMPlexSans-Regular.woff') format('woff');
|
||||
}
|
||||
@font-face {
|
||||
font-family: 'IBM Plex Sans';
|
||||
font-style: normal;
|
||||
font-weight: 500;
|
||||
src: local('IBM Plex Sans Medium'),
|
||||
local('IBMPlexSans-Medium'),
|
||||
url('../fonts/complete/woff2/IBMPlexSans-Medium.woff2') format('woff2'),
|
||||
url('../fonts/complete/woff/IBMPlexSans-Medium.woff') format('woff');
|
||||
}
|
||||
@font-face {
|
||||
font-family: 'IBM Plex Sans';
|
||||
font-style: normal;
|
||||
font-weight: 600;
|
||||
src: local('IBM Plex Sans SemiBold'),
|
||||
local('IBMPlexSans-SemiBold'),
|
||||
url('../fonts/complete/woff2/IBMPlexSans-SemiBold.woff2') format('woff2'),
|
||||
url('../fonts/complete/woff/IBMPlexSans-SemiBold.woff') format('woff');
|
||||
}
|
||||
@font-face {
|
||||
font-family: 'IBM Plex Sans';
|
||||
font-style: normal;
|
||||
font-weight: 700;
|
||||
src: local('IBM Plex Sans Bold'),
|
||||
local('IBMPlexSans-Bold'),
|
||||
url('../fonts/complete/woff2/IBMPlexSans-Bold.woff2') format('woff2'),
|
||||
url('../fonts/complete/woff/IBMPlexSans-Bold.woff') format('woff');
|
||||
}
|
||||
|
||||
* {
|
||||
box-sizing: border-box;
|
||||
scrollbar-color: var(--theme-menu-color) var(--theme-bg-color);
|
||||
scrollbar-width: thin;
|
||||
}
|
||||
|
||||
::-webkit-scrollbar {
|
||||
width: 6px;
|
||||
}
|
||||
::-webkit-scrollbar:horizontal {
|
||||
height: 6px;
|
||||
}
|
||||
::-webkit-scrollbar-track {
|
||||
margin: 6px;
|
||||
// background-color: var(--theme-scroll-bar);
|
||||
}
|
||||
::-webkit-scrollbar-thumb {
|
||||
background-color: var(--theme-scroll-bar);
|
||||
border-radius: 4px;
|
||||
}
|
||||
::-webkit-scrollbar-thumb:hover {
|
||||
background-color: var(--theme-scroll-bar);
|
||||
border-radius: 4px;
|
||||
}
|
||||
::-webkit-scrollbar-corner {
|
||||
background-color: var(--theme-scroll-bar);
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
body {
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
text-rendering: optimizeLegibility;
|
||||
|
||||
font-family: 'IBM Plex Sans', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto;
|
||||
font-size: 14px;
|
||||
font-weight: 400;
|
||||
color: var(--theme-content-color);
|
||||
background-color: var(--theme-menu-color);
|
||||
}
|
13
packages/theme/styles/mixins.scss
Normal file
13
packages/theme/styles/mixins.scss
Normal file
@ -0,0 +1,13 @@
|
||||
@mixin bg-fullsize {
|
||||
position: absolute;
|
||||
top: 0px;
|
||||
left: 0px;
|
||||
min-width: 100%;
|
||||
min-height: 100%;
|
||||
}
|
||||
|
||||
@mixin bg-layer($color, $opacity) {
|
||||
@include bg-fullsize;
|
||||
background: $color;
|
||||
opacity: $opacity;
|
||||
}
|
5
packages/theme/svelte.config.js
Normal file
5
packages/theme/svelte.config.js
Normal file
@ -0,0 +1,5 @@
|
||||
const sveltePreprocess = require('svelte-preprocess')
|
||||
|
||||
module.exports = {
|
||||
preprocess: sveltePreprocess()
|
||||
};
|
10
packages/theme/tsconfig.json
Normal file
10
packages/theme/tsconfig.json
Normal file
@ -0,0 +1,10 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"target": "esnext",
|
||||
"module": "esnext",
|
||||
"declaration": true,
|
||||
"outDir": "./lib",
|
||||
"rootDir": "./src",
|
||||
"strict": true
|
||||
}
|
||||
}
|
BIN
packages/ui/img/chen.png
Executable file
BIN
packages/ui/img/chen.png
Executable file
Binary file not shown.
After Width: | Height: | Size: 33 KiB |
BIN
packages/ui/img/elon.png
Executable file
BIN
packages/ui/img/elon.png
Executable file
Binary file not shown.
After Width: | Height: | Size: 38 KiB |
BIN
packages/ui/img/header-green.png
Executable file
BIN
packages/ui/img/header-green.png
Executable file
Binary file not shown.
After Width: | Height: | Size: 186 KiB |
BIN
packages/ui/img/kathryn.png
Executable file
BIN
packages/ui/img/kathryn.png
Executable file
Binary file not shown.
After Width: | Height: | Size: 40 KiB |
BIN
packages/ui/img/tim.png
Executable file
BIN
packages/ui/img/tim.png
Executable file
Binary file not shown.
After Width: | Height: | Size: 34 KiB |
26
packages/ui/package.json
Normal file
26
packages/ui/package.json
Normal file
@ -0,0 +1,26 @@
|
||||
{
|
||||
"name": "@anticrm/ui",
|
||||
"version": "0.6.0",
|
||||
"main": "src/index.ts",
|
||||
"author": "Anticrm Platform Contributors",
|
||||
"license": "EPL-2.0",
|
||||
"scripts": {
|
||||
"build": "",
|
||||
"build:docs": "api-extractor run --local",
|
||||
"test": "jest",
|
||||
"lint": "eslint src",
|
||||
"lint:fix": "eslint --fix src",
|
||||
"format": "prettier --write 'src/**/*.{ts*,js*,yml}' && eslint --fix src",
|
||||
"svelte-check": "svelte-check"
|
||||
},
|
||||
"devDependencies": {
|
||||
"svelte-loader":"^3.1.2",
|
||||
"sass":"^1.37.5",
|
||||
"svelte-preprocess":"^4.7.4"
|
||||
},
|
||||
"dependencies": {
|
||||
"@anticrm/platform": "~0.6.0",
|
||||
"@anticrm/theme": "~0.6.0",
|
||||
"svelte": "^3.37.0"
|
||||
}
|
||||
}
|
5
packages/ui/postcss.config.js
Normal file
5
packages/ui/postcss.config.js
Normal file
@ -0,0 +1,5 @@
|
||||
module.exports = {
|
||||
plugins: [
|
||||
require('autoprefixer')
|
||||
]
|
||||
}
|
12
packages/ui/src/__test__/location.test.ts
Normal file
12
packages/ui/src/__test__/location.test.ts
Normal file
@ -0,0 +1,12 @@
|
||||
import { locationToUrl } from '../location'
|
||||
import { Location } from '../types'
|
||||
|
||||
describe('location', () => {
|
||||
it('should translate location to url', () => {
|
||||
const loc: Location = {
|
||||
path: ['x', 'y']
|
||||
}
|
||||
const url = locationToUrl(loc)
|
||||
expect(url).toBe('/x/y')
|
||||
})
|
||||
})
|
84
packages/ui/src/components/ActionIcon.svelte
Normal file
84
packages/ui/src/components/ActionIcon.svelte
Normal file
@ -0,0 +1,84 @@
|
||||
<!--
|
||||
// Copyright © 2020 Anticrm Platform Contributors.
|
||||
//
|
||||
// Licensed under the Eclipse Public License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License. You may
|
||||
// obtain a copy of the License at https://www.eclipse.org/legal/epl-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
//
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
-->
|
||||
|
||||
<script lang="ts">
|
||||
import type { IntlString, Asset } from '@anticrm/platform'
|
||||
import type { AnySvelteComponent } from '../types'
|
||||
|
||||
import Icon from './Icon.svelte'
|
||||
import Tooltip from './Tooltip.svelte'
|
||||
|
||||
export let label: IntlString
|
||||
export let direction: string = 'top'
|
||||
export let icon: Asset | AnySvelteComponent
|
||||
export let size: 'small' | 'medium' | 'large'
|
||||
export let action: () => Promise<void>
|
||||
export let invisible: boolean = false
|
||||
</script>
|
||||
|
||||
<Tooltip label={label} direction={direction}>
|
||||
<button class="button {size}" on:click|stopPropagation={action}>
|
||||
<div class="icon {size}" class:invisible={invisible}>
|
||||
{#if typeof (icon) === 'string'}
|
||||
<Icon {icon} {size}/>
|
||||
{:else}
|
||||
<svelte:component this={icon} size={size} />
|
||||
{/if}
|
||||
</div>
|
||||
</button>
|
||||
</Tooltip>
|
||||
|
||||
<style lang="scss">
|
||||
.button {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
padding: 0;
|
||||
border: 1px solid transparent;
|
||||
border-radius: 4px;
|
||||
outline: none;
|
||||
background-color: transparent;
|
||||
cursor: pointer;
|
||||
|
||||
.icon {
|
||||
opacity: .3;
|
||||
&.invisible {
|
||||
opacity: 0;
|
||||
}
|
||||
}
|
||||
&:hover .icon {
|
||||
opacity: 1;
|
||||
}
|
||||
&:focus {
|
||||
border: 1px solid var(--primary-button-focused-border);
|
||||
box-shadow: 0 0 0 3px var(--primary-button-outline);
|
||||
.icon {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
.small {
|
||||
width: 1.143em;
|
||||
height: 1.143em;
|
||||
}
|
||||
.medium {
|
||||
width: 1.429em;
|
||||
height: 1.429em;
|
||||
}
|
||||
.large {
|
||||
width: 1.714em;
|
||||
height: 1.714em;
|
||||
}
|
||||
</style>
|
96
packages/ui/src/components/Button.svelte
Normal file
96
packages/ui/src/components/Button.svelte
Normal file
@ -0,0 +1,96 @@
|
||||
<!--
|
||||
// Copyright © 2020 Anticrm Platform Contributors.
|
||||
//
|
||||
// Licensed under the Eclipse Public License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License. You may
|
||||
// obtain a copy of the License at https://www.eclipse.org/legal/epl-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
//
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
-->
|
||||
<script lang="ts">
|
||||
import type { IntlString } from '@anticrm/platform'
|
||||
import Spinner from './Spinner.svelte'
|
||||
import Label from './Label.svelte'
|
||||
|
||||
export let label: IntlString
|
||||
export let primary: boolean = false
|
||||
export let disabled: boolean = false
|
||||
export let loading: boolean = false
|
||||
export let width: string | undefined = undefined
|
||||
</script>
|
||||
|
||||
<button class="button" class:primary disabled={disabled || loading} style={width ? 'width: ' + width : ''} on:click>
|
||||
{#if loading}
|
||||
<Spinner />
|
||||
{:else}
|
||||
<Label {label} />
|
||||
{/if}
|
||||
</button>
|
||||
|
||||
<style lang="scss">
|
||||
.button {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
height: 48px;
|
||||
padding: 0 25px;
|
||||
color: var(--theme-caption-color);
|
||||
background-color: var(--theme-button-bg-enabled);
|
||||
border: 1px solid var(--theme-button-border-enabled);
|
||||
border-radius: 12px;
|
||||
outline: none;
|
||||
user-select: none;
|
||||
cursor: pointer;
|
||||
font-family: inherit;
|
||||
font-size: 14px;
|
||||
font-weight: 600;
|
||||
&:hover {
|
||||
background-color: var(--theme-button-bg-hovered);
|
||||
border-color: var(--theme-button-border-hovered);
|
||||
}
|
||||
&:focus {
|
||||
background-color: var(--theme-button-bg-focused);
|
||||
border-color: var(--theme-button-border-focused);
|
||||
}
|
||||
&:active {
|
||||
background-color: var(--theme-button-bg-pressed);
|
||||
border-color: var(--theme-button-border-pressed);
|
||||
}
|
||||
&:disabled {
|
||||
background-color: var(--theme-button-bg-disabled);
|
||||
border-color: var(--theme-button-border-disabled);
|
||||
color: rgb(var(--theme-caption-color) / 40%);
|
||||
cursor: not-allowed;
|
||||
}
|
||||
}
|
||||
|
||||
.primary {
|
||||
background-color: var(--primary-button-enabled);
|
||||
border-color: var(--primary-button-border);
|
||||
&:hover {
|
||||
background-color: var(--primary-button-hovered);
|
||||
border-color: var(--primary-button-border);
|
||||
}
|
||||
&:focus {
|
||||
background-color: var(--primary-button-focused);
|
||||
border-color: var(--primary-button-focused-border);
|
||||
box-shadow: 0 0 0 2px var(--primary-button-outline);
|
||||
}
|
||||
&:active {
|
||||
background-color: var(--primary-button-pressed);
|
||||
border-color: var(--primary-button-border);
|
||||
box-shadow: none;
|
||||
}
|
||||
&:disabled {
|
||||
background-color: var(--primary-button-disabled);
|
||||
border-color: var(--primary-button-border);
|
||||
color: rgb(var(--theme-caption-color) / 60%);
|
||||
cursor: not-allowed;
|
||||
}
|
||||
}
|
||||
</style>
|
85
packages/ui/src/components/CheckBox.svelte
Normal file
85
packages/ui/src/components/CheckBox.svelte
Normal file
@ -0,0 +1,85 @@
|
||||
<!--
|
||||
// Copyright © 2020 Anticrm Platform Contributors.
|
||||
//
|
||||
// Licensed under the Eclipse Public License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License. You may
|
||||
// obtain a copy of the License at https://www.eclipse.org/legal/epl-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
//
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
-->
|
||||
|
||||
<script lang="ts">
|
||||
export let checked: boolean = false
|
||||
</script>
|
||||
|
||||
<label class="checkbox">
|
||||
<input class="chBox" type="checkbox" bind:checked={checked}>
|
||||
<svg class="checkSVG" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg">
|
||||
<path class="back" d="M4,0h8c2.2,0,4,1.8,4,4v8c0,2.2-1.8,4-4,4H4c-2.2,0-4-1.8-4-4V4C0,1.8,1.8,0,4,0z"/>
|
||||
<polygon class="check" points="7.3,11.5 4,8.3 5,7.4 7.3,9.7 11.8,5.1 12.7,6.1 "/>
|
||||
<path class="border" d="M12,16H4c-2.2,0-4-1.8-4-4V4c0-2.2,1.8-4,4-4h8c2.2,0,4,1.8,4,4v8C16,14.2,14.2,16,12,16z M4,1 C2.3,1,1,2.3,1,4v8c0,1.7,1.3,3,3,3h8c1.7,0,3-1.3,3-3V4c0-1.7-1.3-3-3-3H4z"/>
|
||||
</svg>
|
||||
</label>
|
||||
|
||||
<style lang="scss">
|
||||
.checkbox {
|
||||
display: inline-block;
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
|
||||
.chBox {
|
||||
position: absolute;
|
||||
width: 1px;
|
||||
height: 1px;
|
||||
margin: -1px;
|
||||
border: 0;
|
||||
padding: 0;
|
||||
clip: rect(0 0 0 0);
|
||||
overflow: hidden;
|
||||
|
||||
&:checked + .checkSVG {
|
||||
& > .back {
|
||||
fill: var(--theme-bg-check);
|
||||
}
|
||||
& > .check {
|
||||
visibility: visible;
|
||||
fill: var(--theme-button-bg-enabled);
|
||||
}
|
||||
& > .border {
|
||||
visibility: hidden;
|
||||
}
|
||||
}
|
||||
&:not(:disabled) + .checkSVG {
|
||||
cursor: pointer;
|
||||
}
|
||||
&:disabled + .checkSVG {
|
||||
filter: grayscale(70%);
|
||||
}
|
||||
&:focus-within + .checkSVG {
|
||||
border: 1px solid var(--primary-button-focused-border);
|
||||
box-shadow: 0 0 0 2px var(--primary-button-outline);
|
||||
}
|
||||
}
|
||||
.checkSVG {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
border-radius: 4px;
|
||||
|
||||
.back {
|
||||
fill: var(--theme-button-bg-hovered);
|
||||
}
|
||||
.check {
|
||||
visibility: hidden;
|
||||
fill: var(--theme-button-bg-enabled);
|
||||
}
|
||||
.border {
|
||||
fill: var(--theme-button-border-enabled);
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
85
packages/ui/src/components/CheckBoxList.svelte
Normal file
85
packages/ui/src/components/CheckBoxList.svelte
Normal file
@ -0,0 +1,85 @@
|
||||
<!--
|
||||
// Copyright © 2020 Anticrm Platform Contributors.
|
||||
//
|
||||
// Licensed under the Eclipse Public License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License. You may
|
||||
// obtain a copy of the License at https://www.eclipse.org/legal/epl-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
//
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
-->
|
||||
|
||||
<script lang="ts">
|
||||
import type { IntlString } from '@anticrm/platform'
|
||||
import CheckBoxWithLabel from './CheckBoxWithLabel.svelte'
|
||||
import Label from './Label.svelte'
|
||||
import Add from './icons/Add.svelte'
|
||||
|
||||
export let label: IntlString
|
||||
export let items: Array<Object> = [
|
||||
{ id: 0, label: '15 minute phone call', done: true },
|
||||
{ id: 1, label: 'Follow up email', done: false },
|
||||
{ id: 2, label: 'First round interview', done: false },
|
||||
{ id: 3, label: 'Follow up email', done: false },
|
||||
{ id: 4, label: 'Second round interview', done: false },
|
||||
{ id: 5, label: 'Third round interview', done: false },
|
||||
]
|
||||
export let editable: boolean = false
|
||||
</script>
|
||||
|
||||
<div class="checkbox-list">
|
||||
{#each items as item}
|
||||
<div class="list-item"><CheckBoxWithLabel bind:label={item.label} bind:checked={item.done} {editable} /></div>
|
||||
{/each}
|
||||
<div class="add-item"
|
||||
on:click={() => {
|
||||
items.push({ id: Date.now(), label: 'New item', done: false })
|
||||
items = items
|
||||
}}
|
||||
>
|
||||
<div class="icon"><Add /></div>
|
||||
<div class="label"><Label {label} /></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<style lang="scss">
|
||||
.checkbox-list {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: stretch;
|
||||
margin: 0 16px;
|
||||
.list-item + .list-item {
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
.add-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-top: 20px;
|
||||
cursor: pointer;
|
||||
|
||||
.icon {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
opacity: .6;
|
||||
}
|
||||
.label {
|
||||
margin-left: 16px;
|
||||
color: var(--theme-content-color);
|
||||
}
|
||||
|
||||
&:hover {
|
||||
.icon {
|
||||
opacity: 1;
|
||||
}
|
||||
.label {
|
||||
color: var(--theme-caption-color);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
140
packages/ui/src/components/CheckBoxWithLabel.svelte
Normal file
140
packages/ui/src/components/CheckBoxWithLabel.svelte
Normal file
@ -0,0 +1,140 @@
|
||||
<!--
|
||||
// Copyright © 2020 Anticrm Platform Contributors.
|
||||
//
|
||||
// Licensed under the Eclipse Public License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License. You may
|
||||
// obtain a copy of the License at https://www.eclipse.org/legal/epl-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
//
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
-->
|
||||
|
||||
<script lang="ts">
|
||||
import { onMount } from 'svelte'
|
||||
import type { IntlString } from '@anticrm/platform'
|
||||
import CheckBox from './CheckBox.svelte'
|
||||
|
||||
export let label: IntlString
|
||||
export let checked: boolean = false
|
||||
export let editable: boolean = false
|
||||
|
||||
let text: HTMLElement
|
||||
let input: HTMLInputElement
|
||||
let onEdit: boolean = false
|
||||
let goOut: boolean = false
|
||||
|
||||
$: {
|
||||
if (text && input) {
|
||||
if (onEdit) {
|
||||
text.style.visibility = 'hidden'
|
||||
input.style.visibility = 'visible'
|
||||
input.focus()
|
||||
} else {
|
||||
input.style.visibility = 'hidden'
|
||||
text.style.visibility = 'visible'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const findNode = (el: Node, name: string): any => {
|
||||
while (el.parentNode !== null) {
|
||||
if (el.classList.contains(name)) return el
|
||||
el = el.parentNode
|
||||
}
|
||||
return false
|
||||
}
|
||||
const waitClick = (event: any): void => {
|
||||
if (onEdit) {
|
||||
if (!findNode(event.target, 'edit-item')) onEdit = false
|
||||
}
|
||||
}
|
||||
|
||||
function computeSize(t: EventTarget | null) {
|
||||
const target = t as HTMLInputElement
|
||||
const value = target.value
|
||||
text.innerHTML = label.replaceAll(' ', ' ')
|
||||
target.style.width = text.clientWidth + 12 + 'px'
|
||||
}
|
||||
|
||||
onMount(() => {
|
||||
computeSize(input)
|
||||
})
|
||||
</script>
|
||||
|
||||
<svelte:window on:mousedown={waitClick} />
|
||||
<div class="checkBox-container">
|
||||
<CheckBox bind:checked={checked} />
|
||||
<div class="label"
|
||||
on:click={() => {
|
||||
if (editable) {
|
||||
onEdit = true
|
||||
}
|
||||
}}
|
||||
>
|
||||
<input bind:this={input} type="text" bind:value={label}
|
||||
class="edit-item"
|
||||
on:input={(ev) => ev.target && computeSize(ev.target)}
|
||||
/>
|
||||
<div class="text" class:checked bind:this={text}>{label}</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<style lang="scss">
|
||||
.checkBox-container {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
.label {
|
||||
position: relative;
|
||||
margin-left: 16px;
|
||||
color: var(--theme-caption-color);
|
||||
&.onEdit {
|
||||
margin: 2px 0px 1px 17px;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.edit-item {
|
||||
max-width: 100%;
|
||||
height: 21px;
|
||||
margin: -3px;
|
||||
padding: 2px;
|
||||
font-family: inherit;
|
||||
font-size: 14px;
|
||||
line-height: 150%;
|
||||
color: var(--theme-caption-color);
|
||||
background-color: transparent;
|
||||
border: 1px solid transparent;
|
||||
border-radius: 2px;
|
||||
outline: none;
|
||||
|
||||
&:focus {
|
||||
border-color: var(--primary-button-enabled);
|
||||
}
|
||||
|
||||
&::-webkit-contacts-auto-fill-button,
|
||||
&::-webkit-credentials-auto-fill-button {
|
||||
visibility: hidden;
|
||||
display: none !important;
|
||||
pointer-events: none;
|
||||
height: 0;
|
||||
width: 0;
|
||||
margin: 0;
|
||||
}
|
||||
}
|
||||
.text {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
|
||||
&.checked {
|
||||
text-decoration: line-through;
|
||||
color: var(--theme-content-dark-color);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
67
packages/ui/src/components/Component.svelte
Normal file
67
packages/ui/src/components/Component.svelte
Normal file
@ -0,0 +1,67 @@
|
||||
<!--
|
||||
// Copyright © 2020 Anticrm Platform Contributors.
|
||||
//
|
||||
// Licensed under the Eclipse Public License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License. You may
|
||||
// obtain a copy of the License at https://www.eclipse.org/legal/epl-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
//
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
-->
|
||||
|
||||
<script lang="ts">
|
||||
import { getResource } from '@anticrm/platform'
|
||||
import type { AnyComponent } from '../types'
|
||||
|
||||
// import Icon from './Icon.svelte'
|
||||
import Spinner from './Spinner.svelte'
|
||||
import ErrorBoundary from './internal/ErrorBoundary'
|
||||
|
||||
export let is: AnyComponent
|
||||
export let props = {}
|
||||
|
||||
$: component = getResource(is)
|
||||
</script>
|
||||
|
||||
{#await component}
|
||||
<div class="spinner-container"><div class="inner"><Spinner /></div></div>
|
||||
{:then Ctor}
|
||||
<ErrorBoundary>
|
||||
<Ctor {...props} on:change on:close on:open on:click/>
|
||||
</ErrorBoundary>
|
||||
{:catch err}
|
||||
ERROR: {console.log(err, JSON.stringify(component))}
|
||||
{props}
|
||||
{err}
|
||||
<!-- <Icon icon={ui.icon.Error} size="32" /> -->
|
||||
{/await}
|
||||
|
||||
<style lang="scss">
|
||||
|
||||
.spinner-container {
|
||||
display: flex;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
@keyframes makeVisible {
|
||||
from {
|
||||
opacity: 0;
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
.spinner-container .inner {
|
||||
margin: auto;
|
||||
opacity: 0;
|
||||
animation-name: makeVisible;
|
||||
animation-duration: 0.25s;
|
||||
animation-delay: 0.1s;
|
||||
}
|
||||
|
||||
</style>
|
264
packages/ui/src/components/DatePicker.svelte
Normal file
264
packages/ui/src/components/DatePicker.svelte
Normal file
@ -0,0 +1,264 @@
|
||||
<!--
|
||||
// Copyright © 2020 Anticrm Platform Contributors.
|
||||
//
|
||||
// Licensed under the Eclipse Public License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License. You may
|
||||
// obtain a copy of the License at https://www.eclipse.org/legal/epl-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
//
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
-->
|
||||
<script lang="ts">
|
||||
import type { IntlString } from '@anticrm/platform'
|
||||
import Label from './Label.svelte'
|
||||
import PopupMenu from './PopupMenu.svelte'
|
||||
import Calendar from './icons/Calendar.svelte'
|
||||
import Close from './icons/Close.svelte'
|
||||
import Back from './icons/Back.svelte'
|
||||
import Forward from './icons/Forward.svelte'
|
||||
|
||||
export let title: IntlString
|
||||
export let selected: Date = new Date(Date.now())
|
||||
export let show: boolean = false
|
||||
|
||||
let view: Date = selected
|
||||
const months: Array<string> = [
|
||||
'January',
|
||||
'February',
|
||||
'March',
|
||||
'April',
|
||||
'May',
|
||||
'June',
|
||||
'July',
|
||||
'August',
|
||||
'September',
|
||||
'October',
|
||||
'November',
|
||||
'December'
|
||||
]
|
||||
let monthYear: string
|
||||
let days: Array<number>
|
||||
|
||||
const daysInMonth = (date: Date): number => {
|
||||
return 33 - new Date(date.getFullYear(), date.getMonth(), 33).getDate()
|
||||
}
|
||||
|
||||
$: {
|
||||
monthYear = months[view.getMonth()] + ' ' + view.getFullYear()
|
||||
days = []
|
||||
for (let i = 1; i <= daysInMonth(view); i++) {
|
||||
days.push(new Date(view.getFullYear(), view.getMonth(), i).getDay())
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<div class="dataPicker">
|
||||
<PopupMenu bind:show={show}>
|
||||
<button
|
||||
slot="trigger"
|
||||
class="btn"
|
||||
class:selected={show}
|
||||
on:click|preventDefault={() => {
|
||||
show = !show
|
||||
}}
|
||||
>
|
||||
<div class="icon">
|
||||
{#if show}<Close size={'small'} />{:else}<Calendar size={'medium'} />{/if}
|
||||
</div>
|
||||
</button>
|
||||
|
||||
<div class="header">
|
||||
<div class="title"><Label label={title} /></div>
|
||||
<div class="nav">
|
||||
<button
|
||||
class="btn arrow"
|
||||
on:click|preventDefault={() => {
|
||||
view.setMonth(view.getMonth() - 1)
|
||||
view = view
|
||||
}}><div class="icon"><Back size={'small'} /></div></button>
|
||||
<div class="monthYear">
|
||||
{monthYear}
|
||||
</div>
|
||||
<button
|
||||
class="btn arrow"
|
||||
on:click|preventDefault={() => {
|
||||
view.setMonth(view.getMonth() + 1)
|
||||
view = view
|
||||
}}><div class="icon"><Forward size={'small'} /></div></button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="calendar">
|
||||
<div class="caption">Mo</div>
|
||||
<div class="caption">Tu</div>
|
||||
<div class="caption">We</div>
|
||||
<div class="caption">Th</div>
|
||||
<div class="caption">Fr</div>
|
||||
<div class="caption">Sa</div>
|
||||
<div class="caption">Su</div>
|
||||
{#each days as day, i}
|
||||
<div
|
||||
class="day"
|
||||
class:selected={i + 1 === selected.getDate() &&
|
||||
view.getMonth() === selected.getMonth() &&
|
||||
view.getFullYear() === selected.getFullYear()}
|
||||
style="grid-column: {day + 1}/{day + 2};"
|
||||
on:click={() => {
|
||||
selected = new Date(view.getFullYear(), view.getMonth(), i + 1)
|
||||
show = false
|
||||
}}
|
||||
>
|
||||
{i + 1}
|
||||
</div>
|
||||
{/each}
|
||||
</div>
|
||||
</PopupMenu>
|
||||
<div class="selectDate">
|
||||
<div class="title"><Label label={title} /></div>
|
||||
<div class="date">
|
||||
{selected.getMonth() + 1} / {selected.getDate()} / {selected.getFullYear()}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<style lang="scss">
|
||||
.dataPicker {
|
||||
display: flex;
|
||||
flex-wrap: nowrap;
|
||||
|
||||
.btn {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
width: 36px;
|
||||
height: 36px;
|
||||
background-color: var(--theme-button-bg-focused);
|
||||
border: 1px solid transparent;
|
||||
border-radius: 8px;
|
||||
outline: none;
|
||||
cursor: pointer;
|
||||
|
||||
.icon {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
opacity: 0.3;
|
||||
}
|
||||
|
||||
&.arrow {
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
border: 1px solid var(--theme-bg-accent-color);
|
||||
border-radius: 4px;
|
||||
|
||||
.icon {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
}
|
||||
}
|
||||
|
||||
&.selected {
|
||||
background-color: var(--theme-button-bg-focused);
|
||||
border: 1px solid var(--theme-bg-accent-color);
|
||||
.icon {
|
||||
opacity: 0.6;
|
||||
}
|
||||
}
|
||||
|
||||
&:hover {
|
||||
background-color: var(--theme-button-bg-pressed);
|
||||
border: 1px solid var(--theme-bg-accent-color);
|
||||
.icon {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
&:focus {
|
||||
border: 1px solid var(--primary-button-focused-border);
|
||||
box-shadow: 0 0 0 3px var(--primary-button-outline);
|
||||
.icon {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.header {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
color: var(--theme-caption-color);
|
||||
|
||||
.title {
|
||||
margin-bottom: 12px;
|
||||
font-size: 14px;
|
||||
font-weight: 500;
|
||||
text-align: left;
|
||||
}
|
||||
.nav {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
min-width: 264px;
|
||||
|
||||
.monthYear {
|
||||
margin: 0 16px;
|
||||
line-height: 150%;
|
||||
white-space: nowrap;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.calendar {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(7, 1fr);
|
||||
gap: 2px;
|
||||
margin-top: 8px;
|
||||
|
||||
.caption {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
width: 36px;
|
||||
height: 36px;
|
||||
font-size: 12px;
|
||||
color: var(--theme-content-dark-color);
|
||||
}
|
||||
.day {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
width: 36px;
|
||||
height: 36px;
|
||||
font-family: inherit;
|
||||
color: var(--theme-content-dark-color);
|
||||
border-radius: 8px;
|
||||
cursor: pointer;
|
||||
|
||||
&.selected {
|
||||
background-color: var(--theme-button-bg-focused);
|
||||
border: 1px solid var(--theme-bg-accent-color);
|
||||
color: var(--theme-caption-color);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.selectDate {
|
||||
margin-left: 12px;
|
||||
.title {
|
||||
font-size: 12px;
|
||||
font-weight: 500;
|
||||
color: var(--theme-content-accent-color);
|
||||
}
|
||||
.date {
|
||||
font-size: 14px;
|
||||
color: var(--theme-caption-color);
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
120
packages/ui/src/components/Dialog.svelte
Normal file
120
packages/ui/src/components/Dialog.svelte
Normal file
@ -0,0 +1,120 @@
|
||||
<!--
|
||||
// Copyright © 2020, 2021 Anticrm Platform Contributors.
|
||||
// Copyright © 2021 Hardcore Engineering Inc.
|
||||
//
|
||||
// Licensed under the Eclipse Public License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License. You may
|
||||
// obtain a copy of the License at https://www.eclipse.org/legal/epl-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
//
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
-->
|
||||
|
||||
<script lang="ts">
|
||||
import type { IntlString } from '@anticrm/platform'
|
||||
|
||||
import { createEventDispatcher } from 'svelte'
|
||||
|
||||
import Close from './internal/icons/Close.svelte'
|
||||
import ScrollBox from './ScrollBox.svelte'
|
||||
import Button from './Button.svelte'
|
||||
import Label from './Label.svelte'
|
||||
|
||||
export let label: IntlString
|
||||
export let okLabel: IntlString
|
||||
export let okAction: () => void
|
||||
|
||||
const dispatch = createEventDispatcher()
|
||||
</script>
|
||||
|
||||
<div class="container">
|
||||
<form class="dialog">
|
||||
<div class="header">
|
||||
<div class="title"><Label {label}/></div>
|
||||
<div class="tool" on:click={() => { dispatch('close') }}><Close size={'small'}/></div>
|
||||
</div>
|
||||
<div class="content">
|
||||
<ScrollBox vertical gap={0}><slot/></ScrollBox>
|
||||
</div>
|
||||
<div class="footer">
|
||||
<Button label={okLabel} primary on:click={() => { okAction(); dispatch('close') }}/>
|
||||
<Button label={'Cancel'} on:click={() => { okAction(); dispatch('close') }}/>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<style lang="scss">
|
||||
.container {
|
||||
position: relative;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
flex-direction: row-reverse;
|
||||
width: 100vw;
|
||||
max-height: 100vh;
|
||||
height: 100vh;
|
||||
|
||||
.dialog {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
min-width: 40%;
|
||||
max-width: 80%;
|
||||
width: auto;
|
||||
max-height: 100vh;
|
||||
height: 100vh;
|
||||
background-color: var(--theme-bg-color);
|
||||
border-radius: 30px 0 0 30px;
|
||||
box-shadow: 0px 50px 120px rgba(0, 0, 0, 0.4);
|
||||
|
||||
.header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
flex-shrink: 0;
|
||||
padding: 0 32px 0 40px;
|
||||
height: 72px;
|
||||
|
||||
.title {
|
||||
flex-grow: 1;
|
||||
font-weight: 500;
|
||||
font-size: 18px;
|
||||
color: var(--theme-caption-color);
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
.tool {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
margin-left: 12px;
|
||||
opacity: .4;
|
||||
cursor: pointer;
|
||||
&:hover {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.content {
|
||||
flex-shrink: 0;
|
||||
width: 640px;
|
||||
margin: 0 40px;
|
||||
height: calc(100vh - 168px);
|
||||
}
|
||||
|
||||
.footer {
|
||||
display: flex;
|
||||
overflow: hidden;
|
||||
flex-direction: row-reverse;
|
||||
align-items: center;
|
||||
flex-shrink: 0;
|
||||
gap: 12px;
|
||||
padding: 0 40px;
|
||||
height: 96px;
|
||||
mask-image: linear-gradient(90deg, rgba(0, 0, 0, 0) 20px, rgba(0, 0, 0, 1) 40px);
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
79
packages/ui/src/components/DialogHeader.svelte
Normal file
79
packages/ui/src/components/DialogHeader.svelte
Normal file
@ -0,0 +1,79 @@
|
||||
<!--
|
||||
// Copyright © 2020, 2021 Anticrm Platform Contributors.
|
||||
// Copyright © 2021 Hardcore Engineering Inc.
|
||||
//
|
||||
// Licensed under the Eclipse Public License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License. You may
|
||||
// obtain a copy of the License at https://www.eclipse.org/legal/epl-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
//
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
-->
|
||||
|
||||
<script lang="ts">
|
||||
import Label from './Label.svelte'
|
||||
</script>
|
||||
|
||||
<div class="header">
|
||||
<div class="user-container">
|
||||
<div class="avatar"></div>
|
||||
<div class="info">
|
||||
<div class="name">Candidate Name</div>
|
||||
<div class="title">Candidate title</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<style lang="scss">
|
||||
|
||||
.header {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
width: 640px;
|
||||
min-height: 240px;
|
||||
background-image: url(../../img/header-green.png);
|
||||
background-repeat: no-repeat;
|
||||
background-clip: border-box;
|
||||
background-size: cover;
|
||||
border-radius: 20px;
|
||||
|
||||
.user-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
|
||||
.avatar {
|
||||
width: 80px;
|
||||
height: 80px;
|
||||
border-radius: 50%;
|
||||
background-color: #C4C4C4;
|
||||
}
|
||||
|
||||
.info {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
margin-top: 10px;
|
||||
|
||||
.name {
|
||||
font-size: 16px;
|
||||
font-weight: 500;
|
||||
line-height: 150%;
|
||||
color: var(--theme-caption-color);
|
||||
}
|
||||
.title {
|
||||
font-size: 12px;
|
||||
font-weight: 500;
|
||||
color: var(--theme-caption-color);
|
||||
opacity: .6;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
</style>
|
114
packages/ui/src/components/EditBox.svelte
Normal file
114
packages/ui/src/components/EditBox.svelte
Normal file
@ -0,0 +1,114 @@
|
||||
<!--
|
||||
// Copyright © 2020 Anticrm Platform Contributors.
|
||||
//
|
||||
// Licensed under the Eclipse Public License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License. You may
|
||||
// obtain a copy of the License at https://www.eclipse.org/legal/epl-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
//
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
-->
|
||||
|
||||
<script lang="ts">
|
||||
import { onMount } from 'svelte'
|
||||
import type { IntlString } from '@anticrm/platform'
|
||||
import Label from './Label.svelte'
|
||||
|
||||
export let label: IntlString | undefined
|
||||
export let width: string | undefined
|
||||
export let value: string | undefined
|
||||
export let placeholder: string = 'placeholder'
|
||||
export let password: boolean = false
|
||||
export let focus: boolean = false
|
||||
|
||||
let text: HTMLElement
|
||||
let input: HTMLInputElement
|
||||
|
||||
function computeSize(t: EventTarget | null) {
|
||||
const target = t as HTMLInputElement
|
||||
const value = target.value
|
||||
text.innerHTML = (value === '' ? placeholder : value).replaceAll(' ', ' ')
|
||||
target.style.width = text.clientWidth + 6 + 'px'
|
||||
}
|
||||
|
||||
onMount(() => {
|
||||
if (focus) {
|
||||
input.focus()
|
||||
focus = false
|
||||
}
|
||||
computeSize(input)
|
||||
})
|
||||
</script>
|
||||
|
||||
<div class="editbox" style="{width ? 'width: ' + width : ''}"
|
||||
on:click={() => { input.focus() }}
|
||||
>
|
||||
<div class="text" bind:this={text}></div>
|
||||
{#if label}<div class="label"><Label label={label}/></div>{/if}
|
||||
{#if password}
|
||||
<input bind:this={input} type="password" bind:value {placeholder} on:input={(ev) => ev.target && computeSize(ev.target)} />
|
||||
{:else}
|
||||
<input bind:this={input} type="text" bind:value {placeholder} on:input={(ev) => ev.target && computeSize(ev.target)} />
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
<style lang="scss">
|
||||
|
||||
.text {
|
||||
position: absolute;
|
||||
visibility: hidden;
|
||||
}
|
||||
.editbox {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
min-width: 50px;
|
||||
height: auto;
|
||||
|
||||
.label {
|
||||
margin-bottom: 4px;
|
||||
font-size: 12px;
|
||||
font-weight: 500;
|
||||
color: var(--theme-caption-color);
|
||||
opacity: .8;
|
||||
pointer-events: none;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
input {
|
||||
max-width: 100%;
|
||||
height: 21px;
|
||||
margin: -3px;
|
||||
padding: 2px;
|
||||
font-family: inherit;
|
||||
font-size: 14px;
|
||||
line-height: 150%;
|
||||
color: var(--theme-caption-color);
|
||||
background-color: transparent;
|
||||
border: 1px solid transparent;
|
||||
border-radius: 2px;
|
||||
outline: none;
|
||||
|
||||
&:focus {
|
||||
border-color: var(--primary-button-enabled);
|
||||
}
|
||||
&::placeholder {
|
||||
color: var(--theme-content-dark-color);
|
||||
}
|
||||
|
||||
&::-webkit-contacts-auto-fill-button,
|
||||
&::-webkit-credentials-auto-fill-button {
|
||||
visibility: hidden;
|
||||
display: none !important;
|
||||
pointer-events: none;
|
||||
height: 0;
|
||||
width: 0;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
</style>
|
76
packages/ui/src/components/EditStylish.svelte
Normal file
76
packages/ui/src/components/EditStylish.svelte
Normal file
@ -0,0 +1,76 @@
|
||||
<!--
|
||||
// Copyright © 2020 Anticrm Platform Contributors.
|
||||
//
|
||||
// Licensed under the Eclipse Public License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License. You may
|
||||
// obtain a copy of the License at https://www.eclipse.org/legal/epl-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
//
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
-->
|
||||
<script lang="ts">
|
||||
import type { IntlString, Asset } from '@anticrm/platform'
|
||||
import type { AnySvelteComponent } from '../types'
|
||||
import Icon from './Icon.svelte'
|
||||
|
||||
export let icon: Asset | AnySvelteComponent
|
||||
export let width: string | undefined = undefined
|
||||
export let value: string | undefined = undefined
|
||||
export let placeholder: string = 'placeholder'
|
||||
</script>
|
||||
|
||||
<div class="editbox" style={width ? 'width: ' + width : ''}>
|
||||
<input type="text" bind:value {placeholder} />
|
||||
<div class="icon">
|
||||
{#if typeof (icon) === 'string'}
|
||||
<Icon {icon} size={'small'} />
|
||||
{:else}
|
||||
<svelte:component this={icon} size={'small'} />
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<style lang="scss">
|
||||
.editbox {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 0;
|
||||
min-width: 268px;
|
||||
height: 40px;
|
||||
background-color: var(--theme-bg-focused-color);
|
||||
border: 1px solid var(--theme-bg-accent-color);
|
||||
border-radius: 8px;
|
||||
|
||||
&:focus-within {
|
||||
border-color: var(--theme-bg-focused-border);
|
||||
}
|
||||
input {
|
||||
width: 100%;
|
||||
height: 40px;
|
||||
margin: 0;
|
||||
padding: 10px 12px;
|
||||
font-family: inherit;
|
||||
color: var(--theme-caption-color);
|
||||
background-color: transparent;
|
||||
outline: none;
|
||||
border: none;
|
||||
border-radius: 8px;
|
||||
|
||||
&::placeholder {
|
||||
color: var(--theme-content-trans-color);
|
||||
}
|
||||
}
|
||||
|
||||
.icon {
|
||||
margin: 12px;
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
opacity: .3;
|
||||
}
|
||||
}
|
||||
</style>
|
34
packages/ui/src/components/Grid.svelte
Executable file
34
packages/ui/src/components/Grid.svelte
Executable file
@ -0,0 +1,34 @@
|
||||
<!--
|
||||
// Copyright © 2020 Anticrm Platform Contributors.
|
||||
//
|
||||
// Licensed under the Eclipse Public License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License. You may
|
||||
// obtain a copy of the License at https://www.eclipse.org/legal/epl-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
//
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
-->
|
||||
<script lang="ts">
|
||||
export let column: number = 2
|
||||
export let rowGap: number = 40
|
||||
export let columnGap: number = 24
|
||||
|
||||
const style = `grid-template-columns: repeat(${column}, 1fr); row-gap: ${rowGap}px; column-gap: ${columnGap}px;`
|
||||
</script>
|
||||
|
||||
<div class="grid" {style}>
|
||||
<slot />
|
||||
</div>
|
||||
|
||||
<style lang="scss">
|
||||
.grid {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr;
|
||||
row-gap: 40px;
|
||||
column-gap: 24px;
|
||||
}
|
||||
</style>
|
45
packages/ui/src/components/Icon.svelte
Normal file
45
packages/ui/src/components/Icon.svelte
Normal file
@ -0,0 +1,45 @@
|
||||
<!--
|
||||
// Copyright © 2020, 2021 Anticrm Platform Contributors.
|
||||
//
|
||||
// Licensed under the Eclipse Public License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License. You may
|
||||
// obtain a copy of the License at https://www.eclipse.org/legal/epl-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
//
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
-->
|
||||
|
||||
<script lang="ts">
|
||||
import type { Asset } from '@anticrm/platform'
|
||||
import { getMetadata } from '@anticrm/platform'
|
||||
|
||||
export let icon: Asset
|
||||
export let size: 'small' | 'medium' | 'large'
|
||||
export let fill = 'var(--theme-caption-color)'
|
||||
|
||||
let url: string
|
||||
$: url = getMetadata(icon) ?? 'https://anticrm.org/logo.svg'
|
||||
</script>
|
||||
|
||||
<svg class={size} {fill}>
|
||||
<use href={url} />
|
||||
</svg>
|
||||
|
||||
<style lang="scss">
|
||||
.small {
|
||||
width: 1.143em;
|
||||
height: 1.143em;
|
||||
}
|
||||
.medium {
|
||||
width: 1.429em;
|
||||
height: 1.429em;
|
||||
}
|
||||
.large {
|
||||
width: 1.714em;
|
||||
height: 1.714em;
|
||||
}
|
||||
</style>
|
37
packages/ui/src/components/IconSize.svelte
Normal file
37
packages/ui/src/components/IconSize.svelte
Normal file
@ -0,0 +1,37 @@
|
||||
<!--
|
||||
// Copyright © 2020 Anticrm Platform Contributors.
|
||||
//
|
||||
// Licensed under the Eclipse Public License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License. You may
|
||||
// obtain a copy of the License at https://www.eclipse.org/legal/epl-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
//
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
-->
|
||||
|
||||
<script lang="ts">
|
||||
export let size: 'small' | 'medium' | 'large'
|
||||
</script>
|
||||
|
||||
<div class={size}>
|
||||
<slot />
|
||||
</div>
|
||||
|
||||
<style lang="scss">
|
||||
.small {
|
||||
width: 1.143em;
|
||||
height: 1.143em;
|
||||
}
|
||||
.medium {
|
||||
width: 1.429em;
|
||||
height: 1.429em;
|
||||
}
|
||||
.large {
|
||||
width: 1.714em;
|
||||
height: 1.714em;
|
||||
}
|
||||
</style>
|
32
packages/ui/src/components/Label.svelte
Normal file
32
packages/ui/src/components/Label.svelte
Normal file
@ -0,0 +1,32 @@
|
||||
<!--
|
||||
// Copyright © 2020, 2021 Anticrm Platform Contributors.
|
||||
//
|
||||
// Licensed under the Eclipse Public License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License. You may
|
||||
// obtain a copy of the License at https://www.eclipse.org/legal/epl-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
//
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
-->
|
||||
|
||||
<script lang="ts">
|
||||
import type { IntlString } from '@anticrm/platform'
|
||||
import { translate } from '@anticrm/platform'
|
||||
|
||||
export let label: IntlString
|
||||
export let params: Record<string, any> = {}
|
||||
|
||||
$: translation = translate(label, params)
|
||||
</script>
|
||||
|
||||
{#await translation}
|
||||
{label}
|
||||
{:then text}
|
||||
{text}
|
||||
{/await}
|
||||
|
||||
|
110
packages/ui/src/components/PopupItem.svelte
Normal file
110
packages/ui/src/components/PopupItem.svelte
Normal file
@ -0,0 +1,110 @@
|
||||
<!--
|
||||
// Copyright © 2020 Anticrm Platform Contributors.
|
||||
//
|
||||
// Licensed under the Eclipse Public License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License. You may
|
||||
// obtain a copy of the License at https://www.eclipse.org/legal/epl-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
//
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
-->
|
||||
|
||||
<script lang="ts">
|
||||
import type { IntlString } from '@anticrm/platform'
|
||||
import type { AnySvelteComponent } from '../types'
|
||||
import Label from './Label.svelte'
|
||||
import Check from './icons/Check.svelte'
|
||||
|
||||
export let title: IntlString | undefined = undefined
|
||||
export let component: AnySvelteComponent | undefined = undefined
|
||||
export let props: Object = {}
|
||||
export let selectable: boolean = false
|
||||
export let selected: boolean = false
|
||||
export let action: () => Promise<void> = async () => {}
|
||||
|
||||
if (title) {
|
||||
component = Label
|
||||
props = { label: title }
|
||||
}
|
||||
</script>
|
||||
|
||||
<button class="popup-item" on:click={() => {
|
||||
if (selectable) selected = !selected
|
||||
action()
|
||||
}}>
|
||||
<div class="title">
|
||||
<svelte:component this={component} {...props}/>
|
||||
</div>
|
||||
{#if selectable}
|
||||
<div class="check" class:selected={selected}><Check/></div>
|
||||
{/if}
|
||||
</button>
|
||||
|
||||
<style lang="scss">
|
||||
.popup-item {
|
||||
position: relative;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin: 0;
|
||||
padding: 8px 12px;
|
||||
height: 40px;
|
||||
background-color: transparent;
|
||||
border: 1px solid transparent;
|
||||
border-radius: 8px;
|
||||
outline: none;
|
||||
cursor: pointer;
|
||||
|
||||
.title {
|
||||
flex-grow: 1;
|
||||
font-size: 14px;
|
||||
line-height: 18px;
|
||||
text-align: left;
|
||||
color: var(--theme-content-accent-color);
|
||||
}
|
||||
|
||||
.check {
|
||||
margin-left: 12px;
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
border-radius: 50%;
|
||||
opacity: 0;
|
||||
|
||||
&.selected {
|
||||
opacity: .8;
|
||||
}
|
||||
}
|
||||
|
||||
&:hover {
|
||||
background-color: var(--theme-button-bg-pressed);
|
||||
border: 1px solid var(--theme-bg-accent-color);
|
||||
.title {
|
||||
color: var(--theme-caption-color);
|
||||
}
|
||||
.check {
|
||||
opacity: .2;
|
||||
&.selected {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
&:focus {
|
||||
border: 1px solid var(--primary-button-focused-border);
|
||||
box-shadow: 0 0 0 3px var(--primary-button-outline);
|
||||
z-index: 1;
|
||||
.title {
|
||||
color: var(--theme-caption-color);
|
||||
}
|
||||
.check {
|
||||
opacity: .2;
|
||||
&.selected {
|
||||
opacity: .8;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
125
packages/ui/src/components/PopupMenu.svelte
Normal file
125
packages/ui/src/components/PopupMenu.svelte
Normal file
@ -0,0 +1,125 @@
|
||||
<!--
|
||||
// Copyright © 2020 Anticrm Platform Contributors.
|
||||
//
|
||||
// Licensed under the Eclipse Public License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License. You may
|
||||
// obtain a copy of the License at https://www.eclipse.org/legal/epl-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
//
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
-->
|
||||
<script lang="ts">
|
||||
import { afterUpdate, onDestroy } from 'svelte/internal'
|
||||
|
||||
export let margin: number = 12
|
||||
export let show: boolean
|
||||
|
||||
let trigger: HTMLElement
|
||||
let popup: HTMLElement
|
||||
let scrolling: boolean
|
||||
let elScroll: Node
|
||||
|
||||
afterUpdate(() => {
|
||||
if (show) showPopup()
|
||||
else hidePopup()
|
||||
})
|
||||
|
||||
const showPopup = (): void => {
|
||||
fitPopup()
|
||||
popup.style.visibility = 'visible'
|
||||
elScroll = findNode(trigger, 'scrollBox')
|
||||
if (elScroll) elScroll.addEventListener('scroll', startScroll)
|
||||
}
|
||||
const hidePopup = (): void => {
|
||||
if (popup) {
|
||||
popup.style.visibility = 'hidden'
|
||||
popup.style.maxHeight = ''
|
||||
}
|
||||
if (elScroll) elScroll.removeEventListener('scroll', startScroll)
|
||||
}
|
||||
|
||||
const fitPopup = (): void => {
|
||||
const rectT = trigger.getBoundingClientRect()
|
||||
const rectP = popup.getBoundingClientRect()
|
||||
scrolling = false
|
||||
if (rectT.top > document.body.clientHeight - rectT.bottom) {
|
||||
// Up
|
||||
if (rectT.top - 20 - margin < rectP.height) {
|
||||
scrolling = true
|
||||
popup.style.maxHeight = `${rectT.top - margin - 20}px`
|
||||
popup.style.top = '20px'
|
||||
} else popup.style.top = `${rectT.top - rectP.height - margin}px`
|
||||
} else {
|
||||
// Down
|
||||
if (rectT.bottom + rectP.height + 20 + margin > document.body.clientHeight) {
|
||||
scrolling = true
|
||||
popup.style.maxHeight = `${document.body.clientHeight - rectT.bottom - margin - 20}px`
|
||||
}
|
||||
popup.style.top = `${rectT.bottom + margin}px`
|
||||
}
|
||||
if (rectT.left + rectP.width + 20 > document.body.clientWidth) {
|
||||
popup.style.left = `${document.body.clientWidth - rectP.width - 20}px`
|
||||
} else popup.style.left = `${rectT.left}px`
|
||||
}
|
||||
|
||||
const findNode = (el: Node, name: string): any => {
|
||||
while (el.parentNode !== null) {
|
||||
if (el.classList.contains(name)) return el
|
||||
el = el.parentNode
|
||||
}
|
||||
return false
|
||||
}
|
||||
const waitClick = (event: any): void => {
|
||||
event.stopPropagation()
|
||||
if (show) {
|
||||
if (!findNode(event.target, 'popup-menu')) show = false
|
||||
}
|
||||
}
|
||||
const startScroll = (): void => { show = false }
|
||||
|
||||
onDestroy(() => {
|
||||
if (elScroll) elScroll.removeEventListener('scroll', startScroll)
|
||||
})
|
||||
</script>
|
||||
|
||||
<svelte:window on:mouseup={waitClick} on:resize={startScroll} />
|
||||
<div class="popup-menu">
|
||||
<div bind:this={trigger}>
|
||||
<slot name="trigger" />
|
||||
</div>
|
||||
<div class="popup" bind:this={popup}>
|
||||
{#if show}
|
||||
<div class="content" class:scrolling><slot /></div>
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<style lang="scss">
|
||||
.popup {
|
||||
position: fixed;
|
||||
visibility: hidden;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
padding: 16px;
|
||||
color: var(--theme-caption-color);
|
||||
background-color: var(--theme-button-bg-hovered);
|
||||
border: 1px solid var(--theme-button-border-enabled);
|
||||
border-radius: 12px;
|
||||
box-shadow: 0px 20px 60px rgba(0, 0, 0, 0.6);
|
||||
user-select: none;
|
||||
z-index: 10;
|
||||
|
||||
.content {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
&.scrolling {
|
||||
overflow-y: auto;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
47
packages/ui/src/components/Progress.svelte
Normal file
47
packages/ui/src/components/Progress.svelte
Normal file
@ -0,0 +1,47 @@
|
||||
<!--
|
||||
// Copyright © 2020 Anticrm Platform Contributors.
|
||||
//
|
||||
// Licensed under the Eclipse Public License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License. You may
|
||||
// obtain a copy of the License at https://www.eclipse.org/legal/epl-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
//
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
-->
|
||||
|
||||
<script lang="ts">
|
||||
export let value: number
|
||||
export let min: number = 0
|
||||
export let max: number = 100
|
||||
export let color: string = '#50BCF9'
|
||||
|
||||
const proc: number = (max - min) / 100
|
||||
if (value > max) value = max
|
||||
if (value < min) value = min
|
||||
</script>
|
||||
|
||||
<div class="progress-container">
|
||||
<div class="bar" style="background-color: {color}; width: calc(100% * {Math.round((value - min) / proc)} / 100);"/>
|
||||
</div>
|
||||
|
||||
<style lang="scss">
|
||||
.progress-container {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
height: 4px;
|
||||
background-color: var(--theme-button-bg-hovered);
|
||||
border-radius: 2px;
|
||||
|
||||
.bar {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
height: 100%;
|
||||
border-radius: 2px;
|
||||
}
|
||||
}
|
||||
</style>
|
27
packages/ui/src/components/Row.svelte
Executable file
27
packages/ui/src/components/Row.svelte
Executable file
@ -0,0 +1,27 @@
|
||||
<!--
|
||||
// Copyright © 2020 Anticrm Platform Contributors.
|
||||
//
|
||||
// Licensed under the Eclipse Public License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License. You may
|
||||
// obtain a copy of the License at https://www.eclipse.org/legal/epl-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
//
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
-->
|
||||
<script lang="ts">
|
||||
</script>
|
||||
|
||||
<div class="row">
|
||||
<slot />
|
||||
</div>
|
||||
|
||||
<style lang="scss">
|
||||
.row {
|
||||
grid-column-start: 1;
|
||||
grid-column-end: -1;
|
||||
}
|
||||
</style>
|
77
packages/ui/src/components/ScrollBox.svelte
Normal file
77
packages/ui/src/components/ScrollBox.svelte
Normal file
@ -0,0 +1,77 @@
|
||||
<!--
|
||||
// Copyright © 2020 Anticrm Platform Contributors.
|
||||
//
|
||||
// Licensed under the Eclipse Public License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License. You may
|
||||
// obtain a copy of the License at https://www.eclipse.org/legal/epl-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
//
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
-->
|
||||
|
||||
<script lang="ts">
|
||||
export let gap: number = 12
|
||||
export let vertical: boolean = false
|
||||
export let stretch: boolean = false
|
||||
export let bothScroll: boolean = false
|
||||
</script>
|
||||
|
||||
<div class="scroll" class:vertical={vertical} class:bothScroll={bothScroll}>
|
||||
<div class="box" class:stretch={stretch} style="gap: {gap}px">
|
||||
<slot/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<style lang="scss">
|
||||
.scroll {
|
||||
position: relative;
|
||||
width: auto;
|
||||
height: 100%;
|
||||
overflow-x: auto;
|
||||
overflow-y: hidden;
|
||||
margin-right: 0;
|
||||
margin-bottom: -5px;
|
||||
|
||||
.box {
|
||||
position: absolute;
|
||||
display: grid;
|
||||
grid-auto-flow: column;
|
||||
padding: 0 0 5px 0;
|
||||
gap: 24px;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: auto;
|
||||
height: 100%;
|
||||
&.stretch {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
&.vertical {
|
||||
margin: 0 -10px 0 -10px;
|
||||
overflow-x: hidden;
|
||||
overflow-y: auto;
|
||||
.box {
|
||||
grid-auto-flow: row;
|
||||
padding: 0 10px 0 10px;
|
||||
width: 100%;
|
||||
height: auto;
|
||||
&.stretch {
|
||||
height: 100%;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&.bothScroll {
|
||||
margin: 0 -5px -5px 0;
|
||||
overflow: auto;
|
||||
.box {
|
||||
padding: 0 5px 5px 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
75
packages/ui/src/components/Section.svelte
Normal file
75
packages/ui/src/components/Section.svelte
Normal file
@ -0,0 +1,75 @@
|
||||
<!--
|
||||
// Copyright © 2020 Anticrm Platform Contributors.
|
||||
//
|
||||
// Licensed under the Eclipse Public License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License. You may
|
||||
// obtain a copy of the License at https://www.eclipse.org/legal/epl-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
//
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
-->
|
||||
|
||||
<script lang="ts">
|
||||
import { IntlString } from '@anticrm/platform'
|
||||
import type { AnySvelteComponent } from '../types'
|
||||
import Label from './Label.svelte'
|
||||
import ArrowUp from './icons/Up.svelte'
|
||||
import ArrowDown from './icons/Down.svelte'
|
||||
|
||||
export let icon: AnySvelteComponent
|
||||
export let label: IntlString
|
||||
export let closed: boolean = false
|
||||
</script>
|
||||
|
||||
<div class="section-container"
|
||||
on:click|preventDefault={() => {
|
||||
closed = !closed
|
||||
}}
|
||||
>
|
||||
<svelte:component this={icon} size={'medium'} />
|
||||
<div class="title"><Label {label} /></div>
|
||||
<div class="arrow">{#if closed}<ArrowUp size={'small'} />{:else}<ArrowDown size={'small'} />{/if}</div>
|
||||
</div>
|
||||
<div class="section-content" class:hidden={closed}><slot/></div>
|
||||
|
||||
<style lang="scss">
|
||||
.section-container {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
flex-wrap: nowrap;
|
||||
width: 100%;
|
||||
height: 80px;
|
||||
min-height: 80px;
|
||||
cursor: pointer;
|
||||
user-select: none;
|
||||
|
||||
.title {
|
||||
flex-grow: 1;
|
||||
margin-left: 12px;
|
||||
font-weight: 500;
|
||||
color: var(--theme-caption-color);
|
||||
}
|
||||
.arrow {
|
||||
margin: 8px;
|
||||
}
|
||||
}
|
||||
.section-content {
|
||||
margin: 16px 0 54px;
|
||||
height: auto;
|
||||
visibility: visible;
|
||||
&.hidden {
|
||||
margin: 0;
|
||||
height: 0;
|
||||
visibility: hidden;
|
||||
}
|
||||
}
|
||||
:global(.section-container + .section-container),
|
||||
:global(.section-content + .section-container) {
|
||||
border-top: 1px solid var(--theme-menu-divider);
|
||||
}
|
||||
</style>
|
76
packages/ui/src/components/SelectBox.svelte
Normal file
76
packages/ui/src/components/SelectBox.svelte
Normal file
@ -0,0 +1,76 @@
|
||||
<!--
|
||||
// Copyright © 2020 Anticrm Platform Contributors.
|
||||
//
|
||||
// Licensed under the Eclipse Public License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License. You may
|
||||
// obtain a copy of the License at https://www.eclipse.org/legal/epl-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
//
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
-->
|
||||
<script lang="ts">
|
||||
export let gap: number = 12
|
||||
export let vertical: boolean = false
|
||||
export let stretch: boolean = false
|
||||
export let bothScroll: boolean = false
|
||||
</script>
|
||||
|
||||
<div class="scrollBox" class:vertical class:bothScroll>
|
||||
<div class="box" class:stretch style="gap: {gap}px">
|
||||
<slot />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<style lang="scss">
|
||||
.scrollBox {
|
||||
position: relative;
|
||||
width: auto;
|
||||
height: 100%;
|
||||
overflow-x: auto;
|
||||
overflow-y: hidden;
|
||||
margin-right: 0;
|
||||
margin-bottom: -5px;
|
||||
|
||||
.box {
|
||||
position: absolute;
|
||||
display: grid;
|
||||
grid-auto-flow: column;
|
||||
padding: 0 0 5px 0;
|
||||
gap: 24px;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: auto;
|
||||
height: 100%;
|
||||
&.stretch {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
&.vertical {
|
||||
margin: 0 -10px 0 -10px;
|
||||
overflow-x: hidden;
|
||||
overflow-y: auto;
|
||||
.box {
|
||||
padding: 0 10px 0 10px;
|
||||
width: 100%;
|
||||
height: auto;
|
||||
grid-auto-flow: row;
|
||||
&.stretch {
|
||||
height: 100%;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&.bothScroll {
|
||||
margin: 0 -5px -5px 0;
|
||||
overflow: auto;
|
||||
.box {
|
||||
padding: 0 5px 5px 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
117
packages/ui/src/components/SelectItem.svelte
Normal file
117
packages/ui/src/components/SelectItem.svelte
Normal file
@ -0,0 +1,117 @@
|
||||
<!--
|
||||
// Copyright © 2020 Anticrm Platform Contributors.
|
||||
//
|
||||
// Licensed under the Eclipse Public License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License. You may
|
||||
// obtain a copy of the License at https://www.eclipse.org/legal/epl-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
//
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
-->
|
||||
|
||||
<script lang="ts">
|
||||
import type { AnySvelteComponent, IPopupItem } from '../types'
|
||||
import Label from './Label.svelte'
|
||||
import PopupMenu from './PopupMenu.svelte'
|
||||
import PopupItem from './PopupItem.svelte'
|
||||
import ActionIcon from './ActionIcon.svelte'
|
||||
import Close from './icons/Close.svelte'
|
||||
|
||||
export let component: AnySvelteComponent | undefined = undefined
|
||||
export let items: Array<IPopupItem>
|
||||
export let item: IPopupItem
|
||||
export let vAlign: 'top' | 'middle' | 'bottom' = 'bottom'
|
||||
export let hAlign: 'left' | 'center' | 'right' = 'left'
|
||||
export let margin: number = 16
|
||||
export let gap: number = 8
|
||||
|
||||
let byTitle: boolean = (component) ? false : true
|
||||
let pressed: boolean = false
|
||||
|
||||
</script>
|
||||
|
||||
<PopupMenu {vAlign} {hAlign} {margin} bind:show={pressed}>
|
||||
<button class="btn" slot="trigger" style="margin: {gap/2}px;"
|
||||
on:click={(event) => {
|
||||
pressed = !pressed
|
||||
event.stopPropagation()
|
||||
}}
|
||||
>
|
||||
<div class="title">
|
||||
{#if byTitle }
|
||||
<Label label={item.title}/>
|
||||
{:else}
|
||||
<svelte:component this={component} {...item.props}/>
|
||||
{/if}
|
||||
</div>
|
||||
<div class="icon"><ActionIcon label={'Remove'} direction={'top'} icon={Close} size={'small'} action={async () => { item.selected = false }}/></div>
|
||||
</button>
|
||||
{#if byTitle }
|
||||
<PopupItem bind:title={item.title} selectable bind:selected={item.selected}/>
|
||||
{:else}
|
||||
<PopupItem bind:component={component} bind:props={item.props} selectable bind:selected={item.selected}/>
|
||||
{/if}
|
||||
{#each items.filter(i => !i.selected) as noItem}
|
||||
{#if byTitle }
|
||||
<PopupItem title={noItem.title} selectable bind:selected={noItem.selected} action={async () => {
|
||||
pressed = false
|
||||
item.selected = false
|
||||
}}/>
|
||||
{:else}
|
||||
<PopupItem component={component} props={noItem.props} selectable bind:selected={noItem.selected} action={async () => {
|
||||
pressed = false
|
||||
item.selected = false
|
||||
}}/>
|
||||
{/if}
|
||||
{/each}
|
||||
</PopupMenu>
|
||||
|
||||
<style lang="scss">
|
||||
.btn {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
flex-wrap: nowrap;
|
||||
margin: 0;
|
||||
padding: 8px 12px;
|
||||
width: auto;
|
||||
height: 40px;
|
||||
background-color: var(--theme-button-bg-pressed);
|
||||
border: 1px solid var(--theme-bg-accent-color);
|
||||
border-radius: 12px;
|
||||
outline: none;
|
||||
cursor: pointer;
|
||||
|
||||
.title {
|
||||
flex-grow: 1;
|
||||
text-align: left;
|
||||
color: var(--theme-caption-color);
|
||||
}
|
||||
|
||||
.icon {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
margin-left: 12px;
|
||||
opacity: .8;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
background-color: var(--theme-button-bg-pressed);
|
||||
border: 1px solid var(--theme-bg-accent-color);
|
||||
.icon {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
&:focus {
|
||||
border: 1px solid var(--primary-button-focused-border);
|
||||
box-shadow: 0 0 0 3px var(--primary-button-outline);
|
||||
.icon {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
28
packages/ui/src/components/Spinner.svelte
Normal file
28
packages/ui/src/components/Spinner.svelte
Normal file
@ -0,0 +1,28 @@
|
||||
|
||||
<div class="spinner">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
|
||||
<path d="M12 0v1c6.1 0 11 4.9 11 11s-4.9 11-11 11v1c6.6 0 12-5.4 12-12S18.6 0 12 0z" fill="#fff"/>
|
||||
<linearGradient id="a" gradientUnits="userSpaceOnUse" x1="0" y1="22" x2="0" y2="2">
|
||||
<stop offset="0" stop-color="#fff"/>
|
||||
<stop offset="1" stop-color="#fff" stop-opacity="0"/>
|
||||
</linearGradient>
|
||||
<path d="M12 23C5.9 23 1 18.1 1 12S5.9 1 12 1V0C5.4 0 0 5.4 0 12s5.4 12 12 12v-1z" fill="url(#a)"/>
|
||||
</svg>
|
||||
</div>
|
||||
|
||||
<style lang="scss">
|
||||
.spinner {
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
-webkit-animation: spinCircle 1s infinite linear;
|
||||
animation: spinCircle 1s infinite linear;
|
||||
}
|
||||
@-webkit-keyframes spinCircle {
|
||||
from { -webkit-transform: rotate(0deg); }
|
||||
to { -webkit-transform: rotate(-359deg); }
|
||||
}
|
||||
@keyframes spinCircle {
|
||||
from { transform: rotate(0deg); }
|
||||
to { transform: rotate(-359deg); }
|
||||
}
|
||||
</style>
|
48
packages/ui/src/components/StatusControl.svelte
Normal file
48
packages/ui/src/components/StatusControl.svelte
Normal file
@ -0,0 +1,48 @@
|
||||
<!--
|
||||
// Copyright © 2020 Anticrm Platform Contributors.
|
||||
//
|
||||
// Licensed under the Eclipse Public License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License. You may
|
||||
// obtain a copy of the License at https://www.eclipse.org/legal/epl-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
//
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
-->
|
||||
|
||||
<script lang="ts">
|
||||
import type { Status } from '@anticrm/platform'
|
||||
import { Severity } from '@anticrm/platform'
|
||||
|
||||
import StatusControl from './internal/Status.svelte'
|
||||
|
||||
export let status: Status
|
||||
</script>
|
||||
|
||||
{#if status.severity !== Severity.OK}
|
||||
<div class="message-container" class:error={status.severity === Severity.ERROR}>
|
||||
<StatusControl {status} />
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
<style lang="scss">
|
||||
.message-container {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
padding: 12px 16px;
|
||||
background-color: var(--theme-bg-accent-color);
|
||||
border: 1px solid var(--theme-bg-accent-hover);
|
||||
border-radius: 8px;
|
||||
}
|
||||
|
||||
.error {
|
||||
color: var(--system-error-color);
|
||||
fill: var(--system-error-color);
|
||||
background-color: var(--theme-button-bg-error);
|
||||
border-color: var(--system-error-60-color);
|
||||
}
|
||||
</style>
|
73
packages/ui/src/components/Tabs.svelte
Normal file
73
packages/ui/src/components/Tabs.svelte
Normal file
@ -0,0 +1,73 @@
|
||||
<!--
|
||||
// Copyright © 2020 Anticrm Platform Contributors.
|
||||
//
|
||||
// Licensed under the Eclipse Public License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License. You may
|
||||
// obtain a copy of the License at https://www.eclipse.org/legal/epl-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
//
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
-->
|
||||
|
||||
<script lang="ts">
|
||||
import { IntlString } from '@anticrm/platform'
|
||||
import Label from './Label.svelte'
|
||||
|
||||
interface Tab {
|
||||
title: IntlString
|
||||
}
|
||||
|
||||
export let tabs: Array<Tab> = [{ title: 'General' }, { title: 'Attachments' }]
|
||||
export let selected: IntlString = 'General'
|
||||
</script>
|
||||
|
||||
<div class="tabs-container">
|
||||
{#each tabs as tab}
|
||||
<div class="tab" class:selected={tab.title === selected}
|
||||
on:click={() => { selected = tab.title }}>
|
||||
<Label label={tab.title}/>
|
||||
</div>
|
||||
{/each}
|
||||
<div class="grow"/>
|
||||
</div>
|
||||
|
||||
<style lang="scss">
|
||||
.tabs-container {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: stretch;
|
||||
flex-wrap: nowrap;
|
||||
margin-bottom: 16px;
|
||||
width: 100%;
|
||||
height: 72px;
|
||||
min-height: 72px;
|
||||
border-bottom: 1px solid var(--theme-menu-divider);
|
||||
|
||||
.tab {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
height: 72px;
|
||||
color: var(--theme-content-trans-color);
|
||||
cursor: pointer;
|
||||
user-select: none;
|
||||
|
||||
&.selected {
|
||||
border-top: 2px solid transparent;
|
||||
border-bottom: 2px solid var(--theme-caption-color);
|
||||
color: var(--theme-caption-color);
|
||||
cursor: default;
|
||||
}
|
||||
}
|
||||
.tab + .tab {
|
||||
margin-left: 40px;
|
||||
}
|
||||
.grow {
|
||||
min-width: 40px;
|
||||
flex-grow: 1;
|
||||
}
|
||||
}
|
||||
</style>
|
73
packages/ui/src/components/TextArea.svelte
Normal file
73
packages/ui/src/components/TextArea.svelte
Normal file
@ -0,0 +1,73 @@
|
||||
<!--
|
||||
// Copyright © 2020 Anticrm Platform Contributors.
|
||||
//
|
||||
// Licensed under the Eclipse Public License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License. You may
|
||||
// obtain a copy of the License at https://www.eclipse.org/legal/epl-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
//
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
-->
|
||||
|
||||
<script lang="ts">
|
||||
import type { IntlString } from '@anticrm/platform'
|
||||
import Label from './Label.svelte'
|
||||
|
||||
export let label: IntlString | undefined
|
||||
export let width: string | undefined
|
||||
export let height: string | undefined
|
||||
export let value: string | undefined
|
||||
export let placeholder: string | undefined
|
||||
</script>
|
||||
|
||||
<div class="textarea" style="{width ? `width: ${width}px;` : ''} {height ? `height: ${height}px;` : ''}">
|
||||
{#if label}<div class="label"><Label label={label} /></div>{/if}
|
||||
<textarea bind:value {placeholder} />
|
||||
</div>
|
||||
|
||||
<style lang="scss">
|
||||
.textarea {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
min-width: 50px;
|
||||
min-height: 36px;
|
||||
|
||||
.label {
|
||||
margin-bottom: 4px;
|
||||
font-size: 12px;
|
||||
font-weight: 500;
|
||||
color: var(--theme-caption-color);
|
||||
opacity: .8;
|
||||
pointer-events: none;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
textarea {
|
||||
width: auto;
|
||||
min-height: 70px;
|
||||
margin: -3px;
|
||||
padding: 2px;
|
||||
font-family: inherit;
|
||||
font-size: 14px;
|
||||
line-height: 150%;
|
||||
color: var(--theme-caption-color);
|
||||
background-color: transparent;
|
||||
border: 1px solid transparent;
|
||||
border-radius: 2px;
|
||||
outline: none;
|
||||
overflow-y: scroll;
|
||||
resize: none;
|
||||
|
||||
&:focus {
|
||||
border-color: var(--primary-button-enabled);
|
||||
}
|
||||
&::placeholder {
|
||||
color: var(--theme-content-dark-color);
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
89
packages/ui/src/components/Toggle.svelte
Normal file
89
packages/ui/src/components/Toggle.svelte
Normal file
@ -0,0 +1,89 @@
|
||||
<!--
|
||||
// Copyright © 2020 Anticrm Platform Contributors.
|
||||
//
|
||||
// Licensed under the Eclipse Public License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License. You may
|
||||
// obtain a copy of the License at https://www.eclipse.org/legal/epl-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
//
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
-->
|
||||
|
||||
<script lang="ts">
|
||||
export let on: boolean = false
|
||||
</script>
|
||||
|
||||
<label class="toggle">
|
||||
<input class="chBox" type="checkbox" bind:checked={on}>
|
||||
<span class="toggle-switch"></span>
|
||||
</label>
|
||||
|
||||
<style lang="scss">
|
||||
.toggle {
|
||||
display: inline-block;
|
||||
height: 28px;
|
||||
line-height: 28px;
|
||||
vertical-align: middle;
|
||||
font-size: 14px;
|
||||
user-select: none;
|
||||
.chBox {
|
||||
position: absolute;
|
||||
width: 1px;
|
||||
height: 1px;
|
||||
margin: -1px;
|
||||
border: 0;
|
||||
padding: 0;
|
||||
clip: rect(0 0 0 0);
|
||||
overflow: hidden;
|
||||
|
||||
&:checked + .toggle-switch {
|
||||
background-color: var(--theme-on-color);
|
||||
&:before {
|
||||
transform: translateX(22px);
|
||||
}
|
||||
}
|
||||
&:not(:disabled) + .toggle-switch {
|
||||
cursor: pointer;
|
||||
}
|
||||
&:disabled + .toggle-switch {
|
||||
filter: grayscale(70%);
|
||||
&:before {
|
||||
background: #eee;
|
||||
}
|
||||
}
|
||||
&:focus-within + .toggle-switch {
|
||||
border: 1px solid var(--primary-button-focused-border);
|
||||
box-shadow: 0 0 0 2px var(--primary-button-outline);
|
||||
}
|
||||
}
|
||||
.toggle-switch {
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
box-sizing: border-box;
|
||||
width: 54px;
|
||||
height: 30px;
|
||||
border-radius: 50px;
|
||||
vertical-align: top;
|
||||
background-color: var(--theme-off-color);
|
||||
border: 1px solid transparent;
|
||||
transition: .2s;
|
||||
&:before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 2px;
|
||||
left: 3px;
|
||||
display: inline-block;
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
border-radius: 50%;
|
||||
background: #fff;
|
||||
box-shadow: 1px 2px 7px rgba(119, 129, 142, 0.1);
|
||||
transition: .15s;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
56
packages/ui/src/components/ToggleWithLabel.svelte
Normal file
56
packages/ui/src/components/ToggleWithLabel.svelte
Normal file
@ -0,0 +1,56 @@
|
||||
<!--
|
||||
// Copyright © 2020, 2021 Anticrm Platform Contributors.
|
||||
// Copyright © 2021 Hardcore Engineering Inc.
|
||||
//
|
||||
// Licensed under the Eclipse Public License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License. You may
|
||||
// obtain a copy of the License at https://www.eclipse.org/legal/epl-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
//
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
-->
|
||||
|
||||
<script lang="ts">
|
||||
import type { IntlString } from '@anticrm/platform'
|
||||
|
||||
import Toggle from './Toggle.svelte'
|
||||
import Label from './Label.svelte'
|
||||
|
||||
export let label: IntlString
|
||||
export let description: IntlString | undefined = undefined
|
||||
export let on: boolean = false
|
||||
</script>
|
||||
|
||||
<div class="toggleWithLabel">
|
||||
<div class="caption">
|
||||
<Label {label} />
|
||||
{#if description}
|
||||
<span><Label label={description} /></span>
|
||||
{/if}
|
||||
</div>
|
||||
<Toggle bind:on={on}/>
|
||||
</div>
|
||||
|
||||
<style lang="scss">
|
||||
.toggleWithLabel {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
.caption {
|
||||
margin-right: 16px;
|
||||
font-size: 14px;
|
||||
font-weight: 400;
|
||||
color: var(--theme-caption-color);
|
||||
user-select: none;
|
||||
span {
|
||||
display: block;
|
||||
font-size: 12px;
|
||||
opacity: .3;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
125
packages/ui/src/components/Tooltip.svelte
Normal file
125
packages/ui/src/components/Tooltip.svelte
Normal file
@ -0,0 +1,125 @@
|
||||
<!--
|
||||
// Copyright © 2020 Anticrm Platform Contributors.
|
||||
//
|
||||
// Licensed under the Eclipse Public License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License. You may
|
||||
// obtain a copy of the License at https://www.eclipse.org/legal/epl-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
//
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
-->
|
||||
|
||||
<script lang="ts">
|
||||
import type { IntlString } from '@anticrm/platform'
|
||||
import Label from './Label.svelte'
|
||||
|
||||
export let label: IntlString
|
||||
export let direction: string = 'top'
|
||||
</script>
|
||||
|
||||
<div class="container">
|
||||
<div class="trigger"><slot/></div>
|
||||
<div class="tooltip {direction}">
|
||||
<Label label={label}/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<style lang="scss">
|
||||
.container {
|
||||
position: relative;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
|
||||
.trigger:hover + .tooltip {
|
||||
opacity: 1;
|
||||
&.top {
|
||||
transform: translateY(-10px);
|
||||
}
|
||||
&.bottom {
|
||||
transform: translateY(10px);
|
||||
}
|
||||
&.right {
|
||||
transform: translateX(10px);
|
||||
}
|
||||
&.left {
|
||||
transform: translateX(-10px);
|
||||
}
|
||||
}
|
||||
|
||||
.tooltip {
|
||||
box-sizing: border-box;
|
||||
position: absolute;
|
||||
padding: 8px;
|
||||
color: var(--theme-caption-color);
|
||||
background-color: var(--theme-tooltip-color);
|
||||
border: 1px solid var(--theme-bg-accent-color);
|
||||
border-radius: 8px;
|
||||
box-shadow: 0px 8px 20px rgba(0, 0, 0, 0.25);
|
||||
opacity: 0;
|
||||
transition: transform .3s ease, opacity .2s ease-in-out;
|
||||
pointer-events: none;
|
||||
user-select: none;
|
||||
text-align: center;
|
||||
transition-delay: .2s;
|
||||
z-index: 10;
|
||||
|
||||
&::after {
|
||||
content: "";
|
||||
position: absolute;
|
||||
width: 14px;
|
||||
height: 14px;
|
||||
background-color: var(--theme-tooltip-color);
|
||||
border: 1px solid var(--theme-bg-accent-color);
|
||||
border-radius: 0 0 3px;
|
||||
mask-image: linear-gradient(-45deg, rgba(0, 0, 0, 1) 9px, rgba(0, 0, 0, 0) 9.1px);
|
||||
}
|
||||
|
||||
&.top::after, &.bottom::after {
|
||||
left: 50%;
|
||||
margin-left: -8px;
|
||||
}
|
||||
&.top {
|
||||
bottom: 100%;
|
||||
box-shadow: 0px -8px 20px rgba(0, 0, 0, 0.25);
|
||||
&::after {
|
||||
bottom: -5px;
|
||||
transform: rotate(45deg);
|
||||
}
|
||||
}
|
||||
&.bottom {
|
||||
top: 100%;
|
||||
box-shadow: 0px -8px 20px rgba(0, 0, 0, 0.25);
|
||||
&::after {
|
||||
top: -5px;
|
||||
transform: rotate(-135deg);
|
||||
}
|
||||
}
|
||||
|
||||
&.right::after, &.left::after {
|
||||
top: 50%;
|
||||
margin-top: -8px;
|
||||
}
|
||||
&.right {
|
||||
left: 100%;
|
||||
box-shadow: -8px 0px 20px rgba(0, 0, 0, 0.25);
|
||||
&::after {
|
||||
left: -5px;
|
||||
transform: rotate(135deg);
|
||||
}
|
||||
}
|
||||
&.left {
|
||||
right: 100%;
|
||||
box-shadow: 8px 0px 20px rgba(0, 0, 0, 0.25);
|
||||
&::after {
|
||||
right: -5px;
|
||||
transform: rotate(-45deg);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
11
packages/ui/src/components/icons/Add.svelte
Normal file
11
packages/ui/src/components/icons/Add.svelte
Normal file
@ -0,0 +1,11 @@
|
||||
<script lang="ts">
|
||||
import IconSize from '../IconSize.svelte'
|
||||
export let size: 'small' | 'medium' | 'large'
|
||||
const fill: string = 'var(--theme-caption-color)'
|
||||
</script>
|
||||
|
||||
<IconSize {size}>
|
||||
<svg {fill} xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16">
|
||||
<path d="M14,7.5H8.5V2c0-0.3-0.2-0.5-0.5-0.5S7.5,1.7,7.5,2v5.5H2C1.7,7.5,1.5,7.7,1.5,8S1.7,8.5,2,8.5h5.5V14 c0,0.3,0.2,0.5,0.5,0.5s0.5-0.2,0.5-0.5V8.5H14c0.3,0,0.5-0.2,0.5-0.5S14.3,7.5,14,7.5z"/>
|
||||
</svg>
|
||||
</IconSize>
|
11
packages/ui/src/components/icons/Back.svelte
Normal file
11
packages/ui/src/components/icons/Back.svelte
Normal file
@ -0,0 +1,11 @@
|
||||
<script lang="ts">
|
||||
import IconSize from '../IconSize.svelte'
|
||||
export let size: 'small' | 'medium' | 'large'
|
||||
const fill: string = 'var(--theme-caption-color)'
|
||||
</script>
|
||||
|
||||
<IconSize {size}>
|
||||
<svg {fill} viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg">
|
||||
<polygon points="10.6,14.4 4.3,8 10.6,1.6 11.4,2.4 5.7,8 11.4,13.6 "/>
|
||||
</svg>
|
||||
</IconSize>
|
13
packages/ui/src/components/icons/Calendar.svelte
Normal file
13
packages/ui/src/components/icons/Calendar.svelte
Normal file
@ -0,0 +1,13 @@
|
||||
<script lang="ts">
|
||||
import IconSize from '../IconSize.svelte'
|
||||
export let size: 'small' | 'medium' | 'large'
|
||||
const fill: string = 'var(--theme-caption-color)'
|
||||
</script>
|
||||
|
||||
<IconSize {size}>
|
||||
<svg {fill} viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
|
||||
<path
|
||||
d="M19.5,5h-2.1V4.5c0-0.3-0.2-0.5-0.5-0.5s-0.5,0.2-0.5,0.5V5H8.1V4.5C8.1,4.2,7.9,4,7.6,4S7.1,4.2,7.1,4.5V5H5 C4.2,5,3.5,5.7,3.5,6.5V19c0,0.8,0.7,1.5,1.5,1.5h14.5c0.8,0,1.5-0.7,1.5-1.5V6.5C21,5.7,20.3,5,19.5,5z M5,6h2.1v0.5 c0,0.3,0.2,0.5,0.5,0.5s0.5-0.2,0.5-0.5V6h8.3v0.5c0,0.3,0.2,0.5,0.5,0.5s0.5-0.2,0.5-0.5V6h2.1C19.7,6,20,6.3,20,6.5v3.1H4.5V6.5 C4.5,6.3,4.7,6,5,6z M19.5,19.5H5c-0.3,0-0.5-0.2-0.5-0.5v-8.3H20V19C20,19.2,19.7,19.5,19.5,19.5z"
|
||||
/>
|
||||
</svg>
|
||||
</IconSize>
|
27
packages/ui/src/components/icons/Check.svelte
Normal file
27
packages/ui/src/components/icons/Check.svelte
Normal file
@ -0,0 +1,27 @@
|
||||
<!--
|
||||
// Copyright © 2020, 2021 Anticrm Platform Contributors.
|
||||
// Copyright © 2021 Hardcore Engineering Inc.
|
||||
//
|
||||
// Licensed under the Eclipse Public License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License. You may
|
||||
// obtain a copy of the License at https://www.eclipse.org/legal/epl-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
//
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
-->
|
||||
|
||||
<script lang="ts">
|
||||
import IconSize from '../IconSize.svelte'
|
||||
export let size: 'small' | 'medium' | 'large'
|
||||
const fill: string = '#4474F6'
|
||||
</script>
|
||||
|
||||
<IconSize {size}>
|
||||
<svg {fill} xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M10,0C4.5,0,0,4.5,0,10s4.5,10,10,10s10-4.5,10-10S15.5,0,10,0z M13.7,8l-4,5c-0.1,0.1-0.3,0.2-0.5,0.2 S8.8,13.1,8.6,13l-2.3-2.5C6,10.2,6,9.7,6.3,9.4c0.3-0.3,0.8-0.3,1.1,0l1.7,1.9L12.5,7c0.3-0.3,0.7-0.4,1.1-0.1 C13.9,7.2,14,7.6,13.7,8z"/>
|
||||
</svg>
|
||||
</IconSize>
|
11
packages/ui/src/components/icons/Close.svelte
Normal file
11
packages/ui/src/components/icons/Close.svelte
Normal file
@ -0,0 +1,11 @@
|
||||
<script lang="ts">
|
||||
import IconSize from '../IconSize.svelte'
|
||||
export let size: 'small' | 'medium' | 'large'
|
||||
const fill: string = 'var(--theme-caption-color)'
|
||||
</script>
|
||||
|
||||
<IconSize {size}>
|
||||
<svg {fill} xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M8.7,8l5.6-5.6c0.2-0.2,0.2-0.5,0-0.7s-0.5-0.2-0.7,0L8,7.3L2.4,1.6c-0.2-0.2-0.5-0.2-0.7,0s-0.2,0.5,0,0.7L7.3,8l-5.6,5.6 c-0.2,0.2-0.2,0.5,0,0.7c0.1,0.1,0.2,0.1,0.4,0.1s0.3,0,0.4-0.1L8,8.7l5.6,5.6c0.1,0.1,0.2,0.1,0.4,0.1s0.3,0,0.4-0.1 c0.2-0.2,0.2-0.5,0-0.7L8.7,8z"/>
|
||||
</svg>
|
||||
</IconSize>
|
15
packages/ui/src/components/icons/Comments.svelte
Executable file
15
packages/ui/src/components/icons/Comments.svelte
Executable file
@ -0,0 +1,15 @@
|
||||
<script lang="ts">
|
||||
import IconSize from '../IconSize.svelte'
|
||||
export let size: 'small' | 'medium' | 'large'
|
||||
const fill: string = 'var(--theme-caption-color)'
|
||||
</script>
|
||||
|
||||
<IconSize {size}>
|
||||
<svg {fill} viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg">
|
||||
<g>
|
||||
<path d="M10,2.8C6,2.8,2.8,6,2.8,10S6,17.2,10,17.2h4.2c0.4,0,0.6,0,0.8,0c1.1-0.2,1.9-1,2.1-2c0-0.2,0-0.4,0-0.8V10 C17.2,6,14,2.8,10,2.8z M16.1,14.9c-0.1,0.6-0.6,1.1-1.2,1.2c-0.1,0-0.3,0-0.7,0H10c-3.4,0-6.2-2.8-6.2-6.2c0-3.4,2.8-6.2,6.2-6.2 s6.2,2.8,6.2,6.2v4.2C16.2,14.6,16.2,14.8,16.1,14.9z"/>
|
||||
<path d="M12.5,8.7h-5C7.2,8.7,7,8.9,7,9.2s0.2,0.5,0.5,0.5h5c0.3,0,0.5-0.2,0.5-0.5S12.8,8.7,12.5,8.7z"/>
|
||||
<path d="M12.5,12H10c-0.3,0-0.5,0.2-0.5,0.5S9.7,13,10,13h2.5c0.3,0,0.5-0.2,0.5-0.5S12.8,12,12.5,12z"/>
|
||||
</g>
|
||||
</svg>
|
||||
</IconSize>
|
11
packages/ui/src/components/icons/Down.svelte
Normal file
11
packages/ui/src/components/icons/Down.svelte
Normal file
@ -0,0 +1,11 @@
|
||||
<script lang="ts">
|
||||
import IconSize from '../IconSize.svelte'
|
||||
export let size: 'small' | 'medium' | 'large'
|
||||
const fill: string = 'var(--theme-caption-color)'
|
||||
</script>
|
||||
|
||||
<IconSize {size}>
|
||||
<svg {fill} viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M7.8,11.8L11.7,8H4L7.8,11.8z"/>
|
||||
</svg>
|
||||
</IconSize>
|
11
packages/ui/src/components/icons/Forward.svelte
Normal file
11
packages/ui/src/components/icons/Forward.svelte
Normal file
@ -0,0 +1,11 @@
|
||||
<script lang="ts">
|
||||
import IconSize from '../IconSize.svelte'
|
||||
export let size: 'small' | 'medium' | 'large'
|
||||
const fill: string = 'var(--theme-caption-color)'
|
||||
</script>
|
||||
|
||||
<IconSize {size}>
|
||||
<svg {fill} viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg">
|
||||
<polygon points="6.4,14.4 5.6,13.6 11.3,8 5.6,2.4 6.4,1.6 12.7,8 "/>
|
||||
</svg>
|
||||
</IconSize>
|
11
packages/ui/src/components/icons/Search.svelte
Normal file
11
packages/ui/src/components/icons/Search.svelte
Normal file
@ -0,0 +1,11 @@
|
||||
<script lang="ts">
|
||||
import IconSize from '../IconSize.svelte'
|
||||
export let size: 'small' | 'medium' | 'large'
|
||||
const fill: string = 'var(--theme-caption-color)'
|
||||
</script>
|
||||
|
||||
<IconSize {size}>
|
||||
<svg {fill} viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M14.4,13.6L11.7,11c0.8-1,1.3-2.2,1.3-3.5c0-3-2.5-5.5-5.5-5.5C4.5,2,2,4.5,2,7.5c0,3,2.5,5.5,5.5,5.5 c1.3,0,2.6-0.5,3.5-1.3l2.6,2.6c0.2,0.2,0.5,0.2,0.7,0C14.5,14.2,14.5,13.8,14.4,13.6z M3,7.5C3,5,5,3,7.5,3S12,5,12,7.5 S10,12,7.5,12S3,10,3,7.5z"/>
|
||||
</svg>
|
||||
</IconSize>
|
14
packages/ui/src/components/icons/ToDo.svelte
Normal file
14
packages/ui/src/components/icons/ToDo.svelte
Normal file
@ -0,0 +1,14 @@
|
||||
<script lang="ts">
|
||||
import IconSize from '../IconSize.svelte'
|
||||
export let size: 'small' | 'medium' | 'large'
|
||||
const fill: string = 'var(--theme-caption-color)'
|
||||
</script>
|
||||
|
||||
<IconSize {size}>
|
||||
<svg {fill} xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16">
|
||||
<g>
|
||||
<path d="M12,0H4C1.8,0,0,1.8,0,4v8c0,2.2,1.8,4,4,4h8c2.2,0,4-1.8,4-4V4C16,1.8,14.2,0,12,0z M15,12c0,1.7-1.3,3-3,3H4 c-1.7,0-3-1.3-3-3V4c0-1.7,1.3-3,3-3h8c1.7,0,3,1.3,3,3V12z"/>
|
||||
<path d="M11.6,4.7L6.8,9.8L4.4,7.3c-0.2-0.2-0.5-0.2-0.7,0C3.5,7.5,3.5,7.8,3.6,8l3.2,3.2l5.5-5.9c0.2-0.2,0.2-0.5,0-0.7 C12.1,4.4,11.8,4.5,11.6,4.7z"/>
|
||||
</g>
|
||||
</svg>
|
||||
</IconSize>
|
11
packages/ui/src/components/icons/Up.svelte
Normal file
11
packages/ui/src/components/icons/Up.svelte
Normal file
@ -0,0 +1,11 @@
|
||||
<script lang="ts">
|
||||
import IconSize from '../IconSize.svelte'
|
||||
export let size: 'small' | 'medium' | 'large'
|
||||
const fill: string = 'var(--theme-caption-color)'
|
||||
</script>
|
||||
|
||||
<IconSize {size}>
|
||||
<svg {fill} viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M7.8,7.2L4,11h7.7L7.8,7.2z"/>
|
||||
</svg>
|
||||
</IconSize>
|
33
packages/ui/src/components/internal/Clock.svelte
Normal file
33
packages/ui/src/components/internal/Clock.svelte
Normal file
@ -0,0 +1,33 @@
|
||||
<script lang="ts">
|
||||
import { onDestroy } from 'svelte'
|
||||
|
||||
let hours = ''
|
||||
let minutes = ''
|
||||
let delimiter = false
|
||||
|
||||
function updateTime () {
|
||||
const date = new Date()
|
||||
const h = date.getHours()
|
||||
hours = h < 10 ? `0${h}` : h.toString()
|
||||
const m = date.getMinutes()
|
||||
minutes = m < 10 ? `0${m}` : m.toString()
|
||||
delimiter = !delimiter
|
||||
}
|
||||
|
||||
const interval = setInterval(updateTime, 500)
|
||||
updateTime()
|
||||
|
||||
onDestroy(() => clearInterval(interval))
|
||||
</script>
|
||||
|
||||
<div>
|
||||
<span>{hours}</span>
|
||||
<span class:h={!delimiter}>:</span>
|
||||
<span>{minutes}</span>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.h {
|
||||
visibility: hidden;
|
||||
}
|
||||
</style>
|
32
packages/ui/src/components/internal/ErrorBoundary.js
Normal file
32
packages/ui/src/components/internal/ErrorBoundary.js
Normal file
@ -0,0 +1,32 @@
|
||||
//
|
||||
// Copyright © 2020 Anticrm Platform Contributors.
|
||||
//
|
||||
// Licensed under the Eclipse Public License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License. You may
|
||||
// obtain a copy of the License at https://www.eclipse.org/legal/epl-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
//
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
import ErrorComponent from './ErrorComponent.svelte'
|
||||
export default class errorBoundary extends ErrorComponent {
|
||||
constructor (config) {
|
||||
let error = null
|
||||
config.props.$$slots.default = config.props.$$slots.default.map((x) => (...args) => {
|
||||
try {
|
||||
return x(...args)
|
||||
} catch (e) {
|
||||
error = e
|
||||
}
|
||||
})
|
||||
super(config)
|
||||
if (error) {
|
||||
this.$set({ error: error })
|
||||
}
|
||||
}
|
||||
}
|
38
packages/ui/src/components/internal/ErrorComponent.svelte
Normal file
38
packages/ui/src/components/internal/ErrorComponent.svelte
Normal file
@ -0,0 +1,38 @@
|
||||
<!--
|
||||
// Copyright © 2020 Anticrm Platform Contributors.
|
||||
//
|
||||
// Licensed under the Eclipse Public License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License. You may
|
||||
// obtain a copy of the License at https://www.eclipse.org/legal/epl-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
//
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
-->
|
||||
|
||||
<script>
|
||||
export let error = null
|
||||
</script>
|
||||
<style>
|
||||
.error {
|
||||
border: 1px solid red;
|
||||
|
||||
}
|
||||
.trace {
|
||||
font-family: monospace;
|
||||
}
|
||||
</style>
|
||||
<slot>
|
||||
{#if error}
|
||||
<div class="error">
|
||||
<b>{error.message}</b>
|
||||
<pre class="trace">
|
||||
{error.stack}
|
||||
</pre>
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
</slot>
|
27
packages/ui/src/components/internal/FontSizeSelector.svelte
Normal file
27
packages/ui/src/components/internal/FontSizeSelector.svelte
Normal file
@ -0,0 +1,27 @@
|
||||
<script lang="ts">
|
||||
import { getContext } from 'svelte'
|
||||
import FontSize from './icons/FontSize.svelte'
|
||||
|
||||
const { currentFontSize, setFontSize } = getContext('fontsize')
|
||||
|
||||
const fontsizes = ['small-font', 'normal-font']
|
||||
|
||||
let current = fontsizes.indexOf(currentFontSize)
|
||||
|
||||
function changeFontSize () {
|
||||
current++
|
||||
setFontSize(fontsizes[current % fontsizes.length])
|
||||
}
|
||||
</script>
|
||||
|
||||
<div class="container" on:click={changeFontSize}>
|
||||
<FontSize size={'small'}/>
|
||||
</div>
|
||||
|
||||
<style lang="scss">
|
||||
.container {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
height: 56px;
|
||||
}
|
||||
</style>
|
129
packages/ui/src/components/internal/Root.svelte
Normal file
129
packages/ui/src/components/internal/Root.svelte
Normal file
@ -0,0 +1,129 @@
|
||||
<script lang="ts">
|
||||
import { onDestroy } from 'svelte'
|
||||
import { OK } from '@anticrm/platform'
|
||||
import { PlatformEvent, addEventListener } from '@anticrm/platform'
|
||||
import type { AnyComponent } from '../../types'
|
||||
// import { applicationShortcutKey } from '../../utils'
|
||||
import { location } from '../../location'
|
||||
|
||||
import { Theme } from '@anticrm/theme'
|
||||
import Component from '../Component.svelte'
|
||||
|
||||
import StatusComponent from './Status.svelte'
|
||||
import Clock from './Clock.svelte'
|
||||
// import Mute from './icons/Mute.svelte'
|
||||
import WiFi from './icons/WiFi.svelte'
|
||||
import ThemeSelector from './ThemeSelector.svelte'
|
||||
import FontSizeSelector from './FontSizeSelector.svelte'
|
||||
|
||||
let application: AnyComponent | undefined
|
||||
|
||||
onDestroy(location.subscribe((loc) => {
|
||||
if (loc.path[0]) {
|
||||
application = loc.path[0] as AnyComponent
|
||||
}
|
||||
}))
|
||||
|
||||
let status = OK
|
||||
|
||||
addEventListener(PlatformEvent, async (_event, _status) => {
|
||||
status = _status
|
||||
})
|
||||
</script>
|
||||
|
||||
<Theme>
|
||||
<div id="ui-root">
|
||||
<div class="status-bar">
|
||||
<div class="container">
|
||||
<div class="status-messages">
|
||||
<StatusComponent {status} />
|
||||
</div>
|
||||
<div class="widgets">
|
||||
<div class="clock">
|
||||
<Clock />
|
||||
</div>
|
||||
<div class="widget">
|
||||
<ThemeSelector />
|
||||
</div>
|
||||
<div class="widget">
|
||||
<FontSizeSelector />
|
||||
</div>
|
||||
<div class="widget">
|
||||
<WiFi size={'small'}/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="app">
|
||||
{#if application}
|
||||
<Component is={application} props={{}} />
|
||||
{:else}
|
||||
<div class="caption-1 error">
|
||||
Application not found: {application}
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
</Theme>
|
||||
|
||||
<style lang="scss">
|
||||
$status-bar-height: 32px;
|
||||
|
||||
#ui-root {
|
||||
position: relative;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
height: 100vh;
|
||||
|
||||
.status-bar {
|
||||
min-height: $status-bar-height;
|
||||
min-width: 1200px;
|
||||
|
||||
.container {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
height: 100%;
|
||||
|
||||
.status-messages {
|
||||
flex-grow: 1;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.widgets {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
flex-direction: row-reverse;
|
||||
|
||||
.clock {
|
||||
margin: 0 40px 0 24px;
|
||||
font-weight: 500;
|
||||
font-size: 12px;
|
||||
color: var(--theme-caption-color);
|
||||
opacity: 0.3;
|
||||
user-select: none;
|
||||
}
|
||||
.widget {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
opacity: 0.3;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.error {
|
||||
margin-top: 45vh;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.app {
|
||||
height: calc(100vh - #{$status-bar-height});
|
||||
min-width: 1200px;
|
||||
min-height: 600px;
|
||||
}
|
||||
}
|
||||
</style>
|
36
packages/ui/src/components/internal/Status.svelte
Normal file
36
packages/ui/src/components/internal/Status.svelte
Normal file
@ -0,0 +1,36 @@
|
||||
<script lang="ts">
|
||||
import type { Status } from '@anticrm/platform'
|
||||
import { Severity } from '@anticrm/platform'
|
||||
|
||||
import Info from './icons/Info.svelte'
|
||||
import Label from '../Label.svelte'
|
||||
|
||||
export let status: Status
|
||||
</script>
|
||||
|
||||
<div class="status">
|
||||
{#if status.severity !== Severity.OK}
|
||||
<Info size={'small'}/>
|
||||
{/if}
|
||||
{#if status.severity !== Severity.OK}
|
||||
<span><Label label={status.code} params={status.params}/></span>
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
<style lang="scss">
|
||||
.status {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
font-size: 11px;
|
||||
opacity: .3;
|
||||
user-select: none;
|
||||
|
||||
span {
|
||||
margin-left: 8px;
|
||||
}
|
||||
&:hover {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
</style>
|
27
packages/ui/src/components/internal/ThemeSelector.svelte
Normal file
27
packages/ui/src/components/internal/ThemeSelector.svelte
Normal file
@ -0,0 +1,27 @@
|
||||
<script lang="ts">
|
||||
import { getContext } from 'svelte'
|
||||
import Mute from './icons/Mute.svelte'
|
||||
|
||||
const { currentTheme, setTheme } = getContext('theme')
|
||||
|
||||
const themes = ['theme-light', 'theme-grey', 'theme-dark']
|
||||
|
||||
let current = themes.indexOf(currentTheme)
|
||||
|
||||
function changeTheme () {
|
||||
current++
|
||||
setTheme(themes[current % themes.length])
|
||||
}
|
||||
</script>
|
||||
|
||||
<div class="container" on:click={changeTheme}>
|
||||
<Mute size={'small'}/>
|
||||
</div>
|
||||
|
||||
<style lang="scss">
|
||||
.container {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
height: 56px;
|
||||
}
|
||||
</style>
|
27
packages/ui/src/components/internal/icons/Close.svelte
Normal file
27
packages/ui/src/components/internal/icons/Close.svelte
Normal file
@ -0,0 +1,27 @@
|
||||
<!--
|
||||
// Copyright © 2020, 2021 Anticrm Platform Contributors.
|
||||
// Copyright © 2021 Hardcore Engineering Inc.
|
||||
//
|
||||
// Licensed under the Eclipse Public License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License. You may
|
||||
// obtain a copy of the License at https://www.eclipse.org/legal/epl-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
//
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
-->
|
||||
|
||||
<script lang="ts">
|
||||
import IconSize from '../../IconSize.svelte'
|
||||
export let size: 'small' | 'medium' | 'large'
|
||||
const fill: string = 'var(--theme-caption-color)'
|
||||
</script>
|
||||
|
||||
<IconSize {size}>
|
||||
<svg viewBox="0 0 24 24" {fill} xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M12.8,12l7.6-7.6c0.2-0.2,0.2-0.6,0-0.8s-0.6-0.2-0.8,0L12,11.2L4.4,3.6c-0.2-0.2-0.6-0.2-0.8,0s-0.2,0.6,0,0.8 l7.6,7.6l-7.6,7.6c-0.2,0.2-0.2,0.6,0,0.8c0.1,0.1,0.3,0.2,0.4,0.2s0.3-0.1,0.4-0.2l7.6-7.6l7.6,7.6c0.1,0.1,0.3,0.2,0.4,0.2 s0.3-0.1,0.4-0.2c0.2-0.2,0.2-0.6,0-0.8L12.8,12z"/>
|
||||
</svg>
|
||||
</IconSize>
|
14
packages/ui/src/components/internal/icons/FontSize.svelte
Normal file
14
packages/ui/src/components/internal/icons/FontSize.svelte
Normal file
@ -0,0 +1,14 @@
|
||||
<script lang="ts">
|
||||
import IconSize from '../../IconSize.svelte'
|
||||
export let size: 'small' | 'medium' | 'large'
|
||||
const fill: string = 'var(--theme-caption-color)'
|
||||
</script>
|
||||
|
||||
<IconSize {size}>
|
||||
<svg {fill} viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg">
|
||||
<g>
|
||||
<path d="M3.7,3.4l-3.1,9.1h1.3l0.9-2.6h3.5l0.9,2.6h1.3L5.3,3.4H3.7z M3,8.8l1.4-4.2h0.1L6,8.8H3z"/>
|
||||
<path d="M14.7,11.4V7.9c0-0.7-0.2-1.3-0.7-1.7c-0.5-0.4-1.1-0.6-2-0.6c-0.6,0-1.1,0.1-1.5,0.4c-0.4,0.3-0.7,0.6-0.9,0.9l0.7,0.7 C10.5,7.3,10.7,7,11,6.8c0.3-0.2,0.6-0.3,1-0.3c0.5,0,0.9,0.1,1.1,0.4c0.2,0.2,0.4,0.6,0.4,1v0.6h-1.3c-1,0-1.7,0.2-2.2,0.5 c-0.5,0.3-0.7,0.8-0.7,1.5c0,0.6,0.2,1.1,0.6,1.5c0.4,0.4,0.9,0.5,1.6,0.5c0.5,0,0.9-0.1,1.2-0.3s0.6-0.5,0.7-0.9h0.1 c0,0.3,0.2,0.6,0.3,0.8c0.2,0.2,0.5,0.3,0.8,0.3h0.7v-1H14.7z M13.4,10.5c0,0.3-0.2,0.6-0.5,0.8c-0.3,0.2-0.7,0.3-1.2,0.3 c-0.4,0-0.7-0.1-0.9-0.3s-0.3-0.4-0.3-0.7v-0.3c0-0.3,0.1-0.6,0.4-0.7c0.3-0.2,0.7-0.2,1.2-0.2h1.3V10.5z"/>
|
||||
</g>
|
||||
</svg>
|
||||
</IconSize>
|
29
packages/ui/src/components/internal/icons/Info.svelte
Normal file
29
packages/ui/src/components/internal/icons/Info.svelte
Normal file
@ -0,0 +1,29 @@
|
||||
<!--
|
||||
// Copyright © 2020 Anticrm Platform Contributors.
|
||||
//
|
||||
// Licensed under the Eclipse Public License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License. You may
|
||||
// obtain a copy of the License at https://www.eclipse.org/legal/epl-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
//
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
-->
|
||||
|
||||
<script lang="ts">
|
||||
import IconSize from '../../IconSize.svelte'
|
||||
export let size: 'small' | 'medium' | 'large'
|
||||
const fill: string = 'var(--theme-caption-color)'
|
||||
</script>
|
||||
|
||||
<IconSize {size}>
|
||||
<svg {fill} viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg">
|
||||
<g opacity="0.6">
|
||||
<path d="M8,16c-4.4,0-8-3.6-8-8s3.6-8,8-8s8,3.6,8,8S12.4,16,8,16z M8,1C4.1,1,1,4.1,1,8c0,3.9,3.1,7,7,7c3.9,0,7-3.1,7-7 C15,4.1,11.9,1,8,1z"/>
|
||||
<path d="M8,12.1c0.4,0,0.8-0.3,0.8-0.8S8.4,10.5,8,10.5s-0.8,0.3-0.8,0.8S7.6,12.1,8,12.1z M7.6,9.6h0.8l0.2-6.2H7.5 L7.6,9.6z"/>
|
||||
</g>
|
||||
</svg>
|
||||
</IconSize>
|
11
packages/ui/src/components/internal/icons/Mute.svelte
Normal file
11
packages/ui/src/components/internal/icons/Mute.svelte
Normal file
@ -0,0 +1,11 @@
|
||||
<script lang="ts">
|
||||
import IconSize from '../../IconSize.svelte'
|
||||
export let size: 'small' | 'medium' | 'large'
|
||||
const fill: string = 'var(--theme-caption-color)'
|
||||
</script>
|
||||
|
||||
<IconSize {size}>
|
||||
<svg {fill} viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M11.9,21.6c-0.1,0-0.1,0-0.2,0c-5-0.2-9.1-4.3-9.3-9.3c-0.1-5.2,3.7-9.5,8.8-9.9c0.2,0,0.5,0.1,0.6,0.3 c0.1,0.2,0.1,0.5,0,0.7c-1.9,2.6-1.6,6.1,0.6,8.3c2.2,2.3,5.8,2.6,8.3,0.7c0.2-0.1,0.4-0.2,0.7,0c0.2,0.1,0.3,0.3,0.3,0.6 C21.2,17.8,16.9,21.6,11.9,21.6z M10,3.8c-3.8,0.9-6.5,4.3-6.4,8.5c0.2,4.4,3.8,7.9,8.1,8.1c4,0.1,7.6-2.6,8.5-6.4 c-2.9,1.4-6.4,0.9-8.7-1.5C9.1,10.2,8.6,6.7,10,3.8z"/>
|
||||
</svg>
|
||||
</IconSize>
|
13
packages/ui/src/components/internal/icons/WiFi.svelte
Normal file
13
packages/ui/src/components/internal/icons/WiFi.svelte
Normal file
@ -0,0 +1,13 @@
|
||||
<script lang="ts">
|
||||
import IconSize from '../../IconSize.svelte'
|
||||
export let size: 'small' | 'medium' | 'large'
|
||||
const fill: string = 'var(--theme-caption-color)'
|
||||
</script>
|
||||
|
||||
<IconSize {size}>
|
||||
<svg {fill} viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M12,11c-2.4,0-4.5,1-6,2.7c-0.2,0.3-0.2,0.6,0.1,0.8s0.6,0.2,0.8-0.1C8.1,13,10,12.2,12,12.2 c2,0,3.9,0.8,5.1,2.3c0.1,0.1,0.3,0.2,0.5,0.2c0.1,0,0.3,0,0.4-0.1c0.3-0.2,0.3-0.6,0.1-0.8C16.6,11.9,14.4,11,12,11z"/>
|
||||
<path d="M12,17.2c-1,0-2,0.4-2.6,1c-0.2,0.2-0.2,0.6,0,0.8c0.2,0.2,0.6,0.2,0.8,0c0.8-0.9,2.7-0.9,3.6,0 c0.1,0.1,0.3,0.2,0.4,0.2c0.2,0,0.3-0.1,0.4-0.2c0.2-0.2,0.2-0.6,0-0.8C14,17.6,13,17.2,12,17.2z"/>
|
||||
<path d="M22.5,9.9C19.8,6.6,16,4.7,12,4.7c-4,0-7.8,1.9-10.5,5.2c-0.2,0.3-0.2,0.6,0.1,0.8c0.3,0.2,0.6,0.2,0.8-0.1 c2.4-3,5.9-4.7,9.5-4.7c3.6,0,7.1,1.7,9.5,4.8c0.1,0.1,0.3,0.2,0.5,0.2c0.1,0,0.3,0,0.4-0.1C22.6,10.6,22.7,10.2,22.5,9.9z"/>
|
||||
</svg>
|
||||
</IconSize>
|
105
packages/ui/src/index.ts
Normal file
105
packages/ui/src/index.ts
Normal file
@ -0,0 +1,105 @@
|
||||
//
|
||||
// Copyright © 2020 Anticrm Platform Contributors.
|
||||
//
|
||||
// Licensed under the Eclipse Public License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License. You may
|
||||
// obtain a copy of the License at https://www.eclipse.org/legal/epl-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
//
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
import { SvelteComponent } from 'svelte'
|
||||
|
||||
import Root from './components/internal/Root.svelte'
|
||||
|
||||
export type { AnyComponent, AnySvelteComponent, Action } from './types'
|
||||
// export { applicationShortcutKey } from './utils'
|
||||
export { getCurrentLocation, navigate, location } from './location'
|
||||
|
||||
export { default as EditBox } from './components/EditBox.svelte'
|
||||
export { default as Label } from './components/Label.svelte'
|
||||
export { default as Button } from './components/Button.svelte'
|
||||
export { default as StatusControl } from './components/StatusControl.svelte'
|
||||
export { default as Component } from './components/Component.svelte'
|
||||
export { default as Icon } from './components/Icon.svelte'
|
||||
export { default as ActionIcon } from './components/ActionIcon.svelte'
|
||||
export { default as Toggle } from './components/Toggle.svelte'
|
||||
export { default as Dialog } from './components/Dialog.svelte'
|
||||
export { default as ToggleWithLabel } from './components/ToggleWithLabel.svelte'
|
||||
export { default as Tooltip } from './components/Tooltip.svelte'
|
||||
export { default as CheckBox } from './components/CheckBox.svelte'
|
||||
export { default as Progress } from './components/Progress.svelte'
|
||||
export { default as Tabs } from './components/Tabs.svelte'
|
||||
export { default as ScrollBox } from './components/ScrollBox.svelte'
|
||||
export { default as PopupMenu } from './components/PopupMenu.svelte'
|
||||
export { default as PopupItem } from './components/PopupItem.svelte'
|
||||
export { default as SelectBox } from './components/SelectBox.svelte'
|
||||
export { default as SelectItem } from './components/SelectItem.svelte'
|
||||
export { default as TextArea } from './components/TextArea.svelte'
|
||||
export { default as Section } from './components/Section.svelte'
|
||||
export { default as DatePicker } from './components/DatePicker.svelte'
|
||||
export { default as EditStylish } from './components/EditStylish.svelte'
|
||||
export { default as Grid } from './components/Grid.svelte'
|
||||
export { default as Row } from './components/Row.svelte'
|
||||
export { default as DialogHeader } from './components/DialogHeader.svelte'
|
||||
export { default as CheckBoxWithLabel } from './components/CheckBoxWithLabel.svelte'
|
||||
export { default as CheckBoxList } from './components/CheckBoxList.svelte'
|
||||
export { default as IconSize } from './components/IconSize.svelte'
|
||||
|
||||
export { default as IconAdd } from './components/icons/Add.svelte'
|
||||
export { default as IconSearch } from './components/icons/Search.svelte'
|
||||
export { default as IconToDo } from './components/icons/ToDo.svelte'
|
||||
export { default as IconComments } from './components/icons/Comments.svelte'
|
||||
|
||||
export function createApp (target: HTMLElement): SvelteComponent {
|
||||
return new Root({ target })
|
||||
}
|
||||
|
||||
// let documentProvider: DocumentProvider | undefined
|
||||
|
||||
// async function open (doc: Document): Promise<void> {
|
||||
// if (documentProvider != null) {
|
||||
// return await documentProvider.open(doc)
|
||||
// }
|
||||
// return await Promise.reject(new Error('Document provider is not registred'))
|
||||
// }
|
||||
|
||||
// function selection (): Document | undefined {
|
||||
// if (documentProvider != null) {
|
||||
// return documentProvider.selection()
|
||||
// }
|
||||
// return undefined
|
||||
// }
|
||||
|
||||
// function registerDocumentProvider (provider: DocumentProvider): void {
|
||||
// documentProvider = provider
|
||||
// }
|
||||
|
||||
import type { AnySvelteComponent, AnyComponent } from './types'
|
||||
import { writable } from 'svelte/store'
|
||||
|
||||
interface CompAndProps {
|
||||
is: AnySvelteComponent | AnyComponent | undefined
|
||||
props: any
|
||||
element: HTMLElement | undefined
|
||||
}
|
||||
|
||||
export const store = writable<CompAndProps>({
|
||||
is: undefined,
|
||||
props: {},
|
||||
element: undefined
|
||||
})
|
||||
|
||||
export function showModal (component: AnySvelteComponent | AnyComponent, props: any, element?: HTMLElement): void {
|
||||
store.set({ is: component, props, element: element })
|
||||
}
|
||||
|
||||
export function closeModal (): void {
|
||||
store.set({ is: undefined, props: {}, element: undefined })
|
||||
}
|
||||
|
116
packages/ui/src/location.ts
Normal file
116
packages/ui/src/location.ts
Normal file
@ -0,0 +1,116 @@
|
||||
//
|
||||
// Copyright © 2020, 2021 Anticrm Platform Contributors.
|
||||
//
|
||||
// Licensed under the Eclipse Public License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License. You may
|
||||
// obtain a copy of the License at https://www.eclipse.org/legal/epl-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
//
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
import { Location as PlatformLocation } from './types'
|
||||
import { writable, derived } from 'svelte/store'
|
||||
|
||||
export function locationToUrl (location: PlatformLocation): string {
|
||||
let result = '/'
|
||||
if (location.path != null) {
|
||||
result += location.path.map((p) => encodeURIComponent(p)).join('/')
|
||||
}
|
||||
if (location.query != null) {
|
||||
const queryValue = Object.entries(location.query)
|
||||
.map((e) => {
|
||||
if (e[1] != null) {
|
||||
// Had value
|
||||
return e[0] + '=' + e[1]
|
||||
} else {
|
||||
return e[0]
|
||||
}
|
||||
})
|
||||
.join('&')
|
||||
if (queryValue.length > 0) {
|
||||
result += '?' + queryValue
|
||||
}
|
||||
}
|
||||
if (location.fragment != null && location.fragment.length > 0) {
|
||||
result += '#' + location.fragment
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
function parseLocation (location: Location): PlatformLocation {
|
||||
return {
|
||||
path: parsePath(location.pathname),
|
||||
query: parseQuery(location.search),
|
||||
fragment: parseHash(location.hash)
|
||||
}
|
||||
}
|
||||
|
||||
function parseQuery (query: string): Record<string, string | null> {
|
||||
query = query.trim()
|
||||
if (query.length === 0 || !query.startsWith('?')) {
|
||||
return {}
|
||||
}
|
||||
query = query.substring(1)
|
||||
const vars = query.split('&')
|
||||
const result: Record<string, string | null> = {}
|
||||
for (let i = 0; i < vars.length; i++) {
|
||||
const pair = vars[i].split('=')
|
||||
const key = pair[0]
|
||||
if (key.length > 0) {
|
||||
if (pair.length > 1) {
|
||||
const value = pair[1]
|
||||
result[key] = value
|
||||
} else {
|
||||
result[key] = null
|
||||
}
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
function parsePath (path: string): string[] {
|
||||
const split = path.split('/').map((ps) => decodeURIComponent(ps))
|
||||
if (split.length >= 1) {
|
||||
if (split[0] === '') {
|
||||
split.splice(0, 1)
|
||||
}
|
||||
}
|
||||
if (split.length >= 1) {
|
||||
if (split[split.length - 1] === '') {
|
||||
split.splice(split.length - 1, 1)
|
||||
}
|
||||
}
|
||||
return split
|
||||
}
|
||||
|
||||
function parseHash (hash: string): string {
|
||||
if (hash.startsWith('#')) {
|
||||
return hash.substring(1)
|
||||
}
|
||||
return hash
|
||||
}
|
||||
|
||||
// ------------------------
|
||||
|
||||
export function getCurrentLocation (): PlatformLocation {
|
||||
return parseLocation(window.location)
|
||||
}
|
||||
|
||||
const locationWritable = writable(getCurrentLocation())
|
||||
window.addEventListener('popstate', () => {
|
||||
locationWritable.set(getCurrentLocation())
|
||||
})
|
||||
|
||||
export const location = derived(locationWritable, (loc) => loc)
|
||||
|
||||
export function navigate (location: PlatformLocation): void {
|
||||
const url = locationToUrl(location)
|
||||
history.pushState(null, '', url)
|
||||
locationWritable.set(location)
|
||||
}
|
4
packages/ui/src/svg.d.ts
vendored
Normal file
4
packages/ui/src/svg.d.ts
vendored
Normal file
@ -0,0 +1,4 @@
|
||||
declare module '*.svg' {
|
||||
const content: string
|
||||
export default content
|
||||
}
|
98
packages/ui/src/types.ts
Normal file
98
packages/ui/src/types.ts
Normal file
@ -0,0 +1,98 @@
|
||||
//
|
||||
// Copyright © 2020 Anticrm Platform Contributors.
|
||||
//
|
||||
// Licensed under the Eclipse Public License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License. You may
|
||||
// obtain a copy of the License at https://www.eclipse.org/legal/epl-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
//
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
import { /* Metadata, Plugin, plugin, */ Resource /*, Service */ } from '@anticrm/platform'
|
||||
import { /* getContext, */ SvelteComponent } from 'svelte'
|
||||
import type { Asset, IntlString } from '@anticrm/platform'
|
||||
|
||||
/**
|
||||
* Describe a browser URI location parsed to path, query and fragment.
|
||||
*/
|
||||
export interface Location {
|
||||
path: string[] // A useful path value
|
||||
query?: Record<string, string | null> // a value of query parameters, no duplication are supported
|
||||
fragment?: string // a value of fragment
|
||||
}
|
||||
|
||||
export type AnySvelteComponent = typeof SvelteComponent
|
||||
|
||||
export type Component<C extends AnySvelteComponent> = Resource<C>
|
||||
export type AnyComponent = Resource<AnySvelteComponent>
|
||||
|
||||
export const CONTEXT_PLATFORM = 'platform'
|
||||
export const CONTEXT_PLATFORM_UI = 'platform-ui'
|
||||
|
||||
export interface Document {} // eslint-disable-line @typescript-eslint/no-empty-interface
|
||||
|
||||
/**
|
||||
* Allow to control currently selected document.
|
||||
*/
|
||||
export interface DocumentProvider {
|
||||
/**
|
||||
* Opening a document
|
||||
* */
|
||||
open: (doc: Document) => Promise<void>
|
||||
|
||||
/**
|
||||
* Return currently selected document, if one.
|
||||
*/
|
||||
selection: () => Document | undefined
|
||||
}
|
||||
|
||||
export interface Action {
|
||||
label: IntlString
|
||||
icon: Asset | AnySvelteComponent
|
||||
action: () => Promise<void>
|
||||
}
|
||||
|
||||
export interface IPopupItem {
|
||||
_id?: number
|
||||
title?: IntlString | undefined
|
||||
component?: AnySvelteComponent | undefined
|
||||
props?: Object
|
||||
selected?: boolean
|
||||
action?: Function
|
||||
}
|
||||
|
||||
// export default plugin(
|
||||
// 'ui' as Plugin<UIService>,
|
||||
// {},
|
||||
// {
|
||||
// metadata: {
|
||||
// LoginApplication: '' as Metadata<string>,
|
||||
// DefaultApplication: '' as Metadata<string>
|
||||
// },
|
||||
// icon: {
|
||||
// Default: '' as Asset,
|
||||
// Error: '' as Asset,
|
||||
// Network: '' as Asset,
|
||||
// Search: '' as Asset,
|
||||
// Add: '' as Asset,
|
||||
// ArrowDown: '' as Asset,
|
||||
// Message: '' as Asset,
|
||||
// Phone: '' as Asset,
|
||||
// Mail: '' as Asset,
|
||||
// More: '' as Asset
|
||||
// },
|
||||
// component: {
|
||||
// Icon: '' as AnyComponent,
|
||||
// Spinner: '' as AnyComponent,
|
||||
// BadComponent: '' as AnyComponent
|
||||
// },
|
||||
// method: {
|
||||
// AnAction: '' as Resource<(args: any) => void>
|
||||
// }
|
||||
// }
|
||||
// )
|
102
packages/ui/src/utils.ts
Normal file
102
packages/ui/src/utils.ts
Normal file
@ -0,0 +1,102 @@
|
||||
//
|
||||
// Copyright © 2020 Anticrm Platform Contributors.
|
||||
//
|
||||
// Licensed under the Eclipse Public License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License. You may
|
||||
// obtain a copy of the License at https://www.eclipse.org/legal/epl-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
//
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
// import type { Metadata } from '@anticrm/platform'
|
||||
import type { AnyComponent /*, Location */ } from './types'
|
||||
|
||||
// import { Readable, derived, writable } from 'svelte/store'
|
||||
// import { onDestroy, getContext, setContext } from 'svelte'
|
||||
|
||||
// function windowLocation (): Location {
|
||||
// return parseLocation(window.location)
|
||||
// }
|
||||
|
||||
// const locationWritable = writable(windowLocation())
|
||||
// window.addEventListener('popstate', () => {
|
||||
// locationWritable.set(windowLocation())
|
||||
// })
|
||||
|
||||
// const location: Readable<Location> = derived(locationWritable, (loc) => loc)
|
||||
|
||||
// function subscribeLocation (listener: (location: Location) => void, destroyFactory: (op: () => void) => void): void {
|
||||
// const unsubscribe = location.subscribe((location) => {
|
||||
// listener(location)
|
||||
// })
|
||||
// destroyFactory(unsubscribe)
|
||||
// }
|
||||
|
||||
// function navigate (newUrl: string): void {
|
||||
// const curUrl = locationToUrl(windowLocation())
|
||||
// if (curUrl === newUrl) {
|
||||
// return
|
||||
// }
|
||||
// history.pushState(null, '', newUrl)
|
||||
// locationWritable.set(windowLocation())
|
||||
// }
|
||||
|
||||
// function navigateJoin (
|
||||
// path: string[] | undefined,
|
||||
// query: Record<string, string> | undefined,
|
||||
// fragment: string | undefined
|
||||
// ): void {
|
||||
// const newLocation = windowLocation()
|
||||
// if (path != null) {
|
||||
// newLocation.path = path
|
||||
// }
|
||||
// if (query != null) {
|
||||
// // For query we do replace
|
||||
// const currentQuery = newLocation.query || {}
|
||||
// for (const kv of Object.entries(query)) {
|
||||
// currentQuery[kv[0]] = kv[1]
|
||||
// }
|
||||
// }
|
||||
// if (fragment) {
|
||||
// newLocation.fragment = fragment
|
||||
// }
|
||||
// navigate(locationToUrl(newLocation))
|
||||
// }
|
||||
|
||||
// const CONTEXT_ROUTE_VALUE = 'routes.context'
|
||||
|
||||
// export function newRouter<T> (
|
||||
// pattern: string,
|
||||
// matcher: (match: T) => void,
|
||||
// defaults: T | undefined = undefined
|
||||
// ): ApplicationRouter<T> {
|
||||
// const r: Router<any> = getContext(CONTEXT_ROUTE_VALUE)
|
||||
// const navigateOp = (loc: Location): void => {
|
||||
// navigate(locationToUrl(loc))
|
||||
// }
|
||||
// const result = r ? r.newRouter<T>(pattern, defaults) : new Router<T>(pattern, r, defaults, navigateOp)
|
||||
// result.subscribe(matcher)
|
||||
// if (!r) {
|
||||
// // No parent, we need to subscribe for location changes.
|
||||
// subscribeLocation((loc) => {
|
||||
// result.update(loc)
|
||||
// }, onDestroy)
|
||||
// }
|
||||
// if (r) {
|
||||
// // We need to remove child router from parent, if component is destroyed
|
||||
// onDestroy(() => r.clearChildRouter())
|
||||
// }
|
||||
// setContext(CONTEXT_ROUTE_VALUE, result)
|
||||
// return result
|
||||
// }
|
||||
|
||||
// R O U T E R M E T A D A T A K E Y S
|
||||
|
||||
// export function applicationShortcutKey (shortcut: string): Metadata<AnyComponent> {
|
||||
// return ('shortcut:ui.' + shortcut) as Metadata<AnyComponent>
|
||||
// }
|
5
packages/ui/svelte.config.js
Normal file
5
packages/ui/svelte.config.js
Normal file
@ -0,0 +1,5 @@
|
||||
const sveltePreprocess = require('svelte-preprocess')
|
||||
|
||||
module.exports = {
|
||||
preprocess: sveltePreprocess()
|
||||
};
|
15
packages/ui/tsconfig.json
Normal file
15
packages/ui/tsconfig.json
Normal file
@ -0,0 +1,15 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"moduleResolution": "node",
|
||||
"target": "esnext",
|
||||
"module": "esnext",
|
||||
"declaration": true,
|
||||
"outDir": "./lib",
|
||||
"strict": true,
|
||||
"esModuleInterop": true,
|
||||
"lib": [
|
||||
"esnext",
|
||||
"dom"
|
||||
]
|
||||
}
|
||||
}
|
16
rush.json
16
rush.json
@ -475,6 +475,22 @@
|
||||
"packageName": "@anticrm/dev-server",
|
||||
"projectFolder": "dev/server",
|
||||
"shouldPublish": true
|
||||
},
|
||||
{
|
||||
"packageName": "@anticrm/theme",
|
||||
"projectFolder": "packages/theme",
|
||||
"shouldPublish": true
|
||||
},
|
||||
{
|
||||
"packageName": "@anticrm/ui",
|
||||
"projectFolder": "packages/ui",
|
||||
"shouldPublish": true
|
||||
},
|
||||
{
|
||||
"packageName": "prod",
|
||||
"projectFolder": "dev/prod",
|
||||
"shouldPublish": true
|
||||
}
|
||||
|
||||
]
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user