mirror of
https://github.com/hcengineering/platform.git
synced 2026-08-17 18:05:42 +02:00
iniital ui contribution
Signed-off-by: Andrey Platov <andrey@hardcoreeng.com>
This commit is contained in:
Generated
+2397
-5
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,3 @@
|
||||
stats.json
|
||||
dist/
|
||||
|
||||
@@ -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"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
module.exports = {
|
||||
plugins: [
|
||||
require('autoprefixer')
|
||||
]
|
||||
}
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 3.1 KiB |
@@ -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>
|
||||
@@ -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)
|
||||
@@ -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'))
|
||||
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"outDir": "./dist/",
|
||||
"noImplicitAny": true,
|
||||
"module": "esnext",
|
||||
"target": "esnext",
|
||||
"allowJs": true,
|
||||
"sourceMap": true,
|
||||
"moduleResolution": "node",
|
||||
"allowSyntheticDefaultImports": true,
|
||||
"lib": [
|
||||
"esnext",
|
||||
"dom"
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -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"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
module.exports = {
|
||||
plugins: [
|
||||
require('autoprefixer')
|
||||
]
|
||||
}
|
||||
@@ -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/>
|
||||
@@ -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'
|
||||
Vendored
+5
@@ -0,0 +1,5 @@
|
||||
declare module '*.svelte' {
|
||||
import { SvelteComponent } from 'svelte'
|
||||
const Component: SvelteComponent
|
||||
export default Component
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
const sveltePreprocess = require('svelte-preprocess')
|
||||
|
||||
module.exports = {
|
||||
preprocess: sveltePreprocess()
|
||||
};
|
||||
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"target": "esnext",
|
||||
"module": "esnext",
|
||||
"declaration": true,
|
||||
"outDir": "./lib",
|
||||
"rootDir": "./src",
|
||||
"strict": true
|
||||
}
|
||||
}
|
||||
Executable
BIN
Binary file not shown.
|
After Width: | Height: | Size: 33 KiB |
Executable
BIN
Binary file not shown.
|
After Width: | Height: | Size: 38 KiB |
Executable
BIN
Binary file not shown.
|
After Width: | Height: | Size: 186 KiB |
Executable
BIN
Binary file not shown.
|
After Width: | Height: | Size: 40 KiB |
Executable
BIN
Binary file not shown.
|
After Width: | Height: | Size: 34 KiB |
@@ -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"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
module.exports = {
|
||||
plugins: [
|
||||
require('autoprefixer')
|
||||
]
|
||||
}
|
||||
@@ -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')
|
||||
})
|
||||
})
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
Executable
+34
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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}
|
||||
|
||||
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
Executable
+27
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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 })
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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 })
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
Vendored
+4
@@ -0,0 +1,4 @@
|
||||
declare module '*.svg' {
|
||||
const content: string
|
||||
export default content
|
||||
}
|
||||
@@ -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>
|
||||
// }
|
||||
// }
|
||||
// )
|
||||
@@ -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>
|
||||
// }
|
||||
@@ -0,0 +1,5 @@
|
||||
const sveltePreprocess = require('svelte-preprocess')
|
||||
|
||||
module.exports = {
|
||||
preprocess: sveltePreprocess()
|
||||
};
|
||||
@@ -0,0 +1,15 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"moduleResolution": "node",
|
||||
"target": "esnext",
|
||||
"module": "esnext",
|
||||
"declaration": true,
|
||||
"outDir": "./lib",
|
||||
"strict": true,
|
||||
"esModuleInterop": true,
|
||||
"lib": [
|
||||
"esnext",
|
||||
"dom"
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
|
||||
]
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user