1
0
Fork 0
mirror of synced 2024-06-28 11:10:46 +12:00

Merge branch 'master' of github.com:appwrite/appwrite into team-features

This commit is contained in:
Eldad Fux 2020-06-10 22:08:00 +03:00
commit f3c8e57e70
39 changed files with 389 additions and 163 deletions

0
.gitattributes vendored Normal file
View file

View file

@ -2,8 +2,10 @@
## Features ## Features
- Added a new route in Locale API to fetch a list of languages - New route in Locale API to fetch a list of languages
- Added option to force HTTPS connection to the Appwrite server (_APP_OPTIONS_FORCE_HTTPS)
- Added Google Fonts to Appwrite for offline availability - Added Google Fonts to Appwrite for offline availability
- Added a new route in the Avatars API to get user initials avatar
- Added option to delete team from the console - Added option to delete team from the console
- Added option to view team members from the console - Added option to view team members from the console
- Added option to join a user to any team from the console - Added option to join a user to any team from the console
@ -12,6 +14,8 @@
- Fixed output of /v1/health/queue/certificates returning wrong data - Fixed output of /v1/health/queue/certificates returning wrong data
- Fixed bug where team members count was wrong in some cases - Fixed bug where team members count was wrong in some cases
- Fixed network calculation for uploaded files
- Fixed a UI bug preventing float values in numeric fields
## Security ## Security

View file

@ -51,6 +51,7 @@ ENV TZ=Asia/Tel_Aviv \
_APP_HOME=https://appwrite.io \ _APP_HOME=https://appwrite.io \
_APP_EDITION=community \ _APP_EDITION=community \
_APP_OPTIONS_ABUSE=enabled \ _APP_OPTIONS_ABUSE=enabled \
_APP_OPTIONS_FORCE_HTTPS=disabled \
_APP_OPENSSL_KEY_V1=your-secret-key \ _APP_OPENSSL_KEY_V1=your-secret-key \
_APP_STORAGE_LIMIT=104857600 \ _APP_STORAGE_LIMIT=104857600 \
_APP_STORAGE_ANTIVIRUS=enabled \ _APP_STORAGE_ANTIVIRUS=enabled \

View file

@ -82,6 +82,14 @@ $utopia->init(function () use ($utopia, $request, $response, &$user, $project, $
* As recommended at: * As recommended at:
* @see https://www.owasp.org/index.php/List_of_useful_HTTP_headers * @see https://www.owasp.org/index.php/List_of_useful_HTTP_headers
*/ */
if ($request->getServer('_APP_OPTIONS_FORCE_HTTPS', 'disabled') === 'enabled') { // Force HTTPS
if(Config::getParam('protocol') !== 'https') {
return $response->redirect('https://' . Config::getParam('domain').$request->getServer('REQUEST_URI'));
}
$response->addHeader('Strict-Transport-Security', 'max-age='.(60 * 60 * 24 * 126)); // 126 days
}
$response $response
->addHeader('Server', 'Appwrite') ->addHeader('Server', 'Appwrite')
->addHeader('X-XSS-Protection', '1; mode=block; report=/v1/xss?url='.urlencode($request->getServer('REQUEST_URI'))) ->addHeader('X-XSS-Protection', '1; mode=block; report=/v1/xss?url='.urlencode($request->getServer('REQUEST_URI')))
@ -236,12 +244,12 @@ $utopia->shutdown(function () use ($response, $request, $webhook, $audit, $usage
} }
$route = $utopia->match($request); $route = $utopia->match($request);
if($project->getId() if($project->getId()
&& $mode !== APP_MODE_ADMIN && $mode !== APP_MODE_ADMIN
&& !empty($route->getLabel('sdk.namespace', null))) { // Don't calculate console usage and admin mode && !empty($route->getLabel('sdk.namespace', null))) { // Don't calculate console usage and admin mode
$usage $usage
->setParam('request', $request->getSize()) ->setParam('request', $request->getSize() + $usage->getParam('storage'))
->setParam('response', $response->getSize()) ->setParam('response', $response->getSize())
->trigger() ->trigger()
; ;

View file

@ -16,6 +16,7 @@ use BaconQrCode\Renderer\Image\ImagickImageBackEnd;
use BaconQrCode\Renderer\RendererStyle\RendererStyle; use BaconQrCode\Renderer\RendererStyle\RendererStyle;
use BaconQrCode\Writer; use BaconQrCode\Writer;
use Utopia\Config\Config; use Utopia\Config\Config;
use Utopia\Validator\HexColor;
include_once __DIR__ . '/../shared/api.php'; include_once __DIR__ . '/../shared/api.php';
@ -385,7 +386,83 @@ $utopia->get('/v1/avatars/qr')
$response $response
->addHeader('Expires', date('D, d M Y H:i:s', time() + (60 * 60 * 24 * 45)).' GMT') // 45 days cache ->addHeader('Expires', date('D, d M Y H:i:s', time() + (60 * 60 * 24 * 45)).' GMT') // 45 days cache
->setContentType('image/png') ->setContentType('image/png')
->send('', $writer->writeString($text)) ->send($writer->writeString($text))
;
}
);
$utopia->get('/v1/avatars/initials')
->desc('Get User Initials')
->param('name', '', function () { return new Text(512); }, 'Full Name. When empty, current user name or email will be used.', true)
->param('width', 500, function () { return new Range(0, 2000); }, 'Image width. Pass an integer between 0 to 2000. Defaults to 100.', true)
->param('height', 500, function () { return new Range(0, 2000); }, 'Image height. Pass an integer between 0 to 2000. Defaults to 100.', true)
->param('color', '', function () { return new HexColor(); }, 'Changes text color. By default a random color will be picked and stay will persistent to the given name.', true)
->param('background', '', function () { return new HexColor(); }, 'Changes background color. By default a random color will be picked and stay will persistent to the given name.', true)
->label('scope', 'avatars.read')
->label('sdk.platform', [APP_PLATFORM_CLIENT, APP_PLATFORM_SERVER])
->label('sdk.namespace', 'avatars')
->label('sdk.method', 'getInitials')
->label('sdk.methodType', 'location')
->label('sdk.description', '/docs/references/avatars/get-initials.md')
->action(
function ($name, $width, $height, $color, $background) use ($response, $user) {
$themes = [
['color' => '#27005e', 'background' => '#e1d2f6'], // VIOLET
['color' => '#5e2700', 'background' => '#f3d9c6'], // ORANGE
['color' => '#006128', 'background' => '#c9f3c6'], // GREEN
['color' => '#580061', 'background' => '#f2d1f5'], // FUSCHIA
['color' => '#00365d', 'background' => '#c6e1f3'], // BLUE
['color' => '#00075c', 'background' => '#d2d5f6'], // INDIGO
['color' => '#610038', 'background' => '#f5d1e6'], // PINK
['color' => '#386100', 'background' => '#dcf1bd'], // LIME
['color' => '#615800', 'background' => '#f1ecba'], // YELLOW
['color' => '#610008', 'background' => '#f6d2d5'] // RED
];
$rand = rand(0, count($themes)-1);
$name = (!empty($name)) ? $name : $user->getAttribute('name', $user->getAttribute('email', ''));
$words = explode(' ', strtoupper($name));
$initials = null;
$code = 0;
foreach ($words as $key => $w) {
$initials .= (isset($w[0])) ? $w[0] : '';
$code += (isset($w[0])) ? ord($w[0]) : 0;
if($key == 1) {
break;
}
}
$length = count($words);
$rand = substr($code,-1);
$background = (!empty($background)) ? '#'.$background : $themes[$rand]['background'];
$color = (!empty($color)) ? '#'.$color : $themes[$rand]['color'];
$image = new \Imagick();
$draw = new \ImagickDraw();
$fontSize = min($width, $height) / 2;
$draw->setFont(__DIR__."/../../../public/fonts/poppins-v9-latin-600.ttf");
$image->setFont(__DIR__."/../../../public/fonts/poppins-v9-latin-600.ttf");
$draw->setFillColor(new \ImagickPixel($color));
$draw->setFontSize($fontSize);
$draw->setTextAlignment(\Imagick::ALIGN_CENTER);
$draw->annotation($width / 1.97, ($height / 2) + ($fontSize / 3), $initials);
$image->newImage($width, $height, $background);
$image->setImageFormat("png");
$image->drawImage($draw);
//$image->setImageCompressionQuality(9 - round(($quality / 100) * 9));
$response
->addHeader('Expires', date('D, d M Y H:i:s', time() + (60 * 60 * 24 * 45)).' GMT') // 45 days cache
->setContentType('image/png')
->send($image->getImageBlob())
; ;
} }
); );

View file

@ -424,6 +424,10 @@ $utopia->delete('/v1/projects/:projectId')
} }
} }
} }
if (!$consoleDB->deleteDocument($project->getAttribute('teamId', null))) {
throw new Exception('Failed to remove project team from DB', 500);
}
if (!$consoleDB->deleteDocument($projectId)) { if (!$consoleDB->deleteDocument($projectId)) {
throw new Exception('Failed to remove project from DB', 500); throw new Exception('Failed to remove project from DB', 500);

View file

@ -1,6 +1,6 @@
<div class="cover"> <div class="cover">
<h1 class="zone xl margin-bottom-large"> <h1 class="zone xl margin-bottom-large">
<a data-ls-attrs="href=/console" class="back text-size-small"><i class="icon-left-open"></i> Home</a> <a data-ls-attrs="href=/console" class="back text-size-small link-return-animation--start"><i class="icon-left-open"></i> Home</a>
<br /> <br />
<span>Your Account</span> <span>Your Account</span>
@ -26,7 +26,7 @@
<br /> <br />
<a href="https://en.gravatar.com/gravatars/new/" rel="noopener" class="button margin-bottom-small" target="_blank"><i class="icon-upload"></i> Upload</a> <a href="https://en.gravatar.com/gravatars/new/" rel="noopener" class="button margin-bottom-small link-animation-disabled" target="_blank"><i class="icon-upload"></i> Upload</a>
<br /> <br />
@ -317,4 +317,4 @@
</div> </div>
</li> </li>
</ul> </ul>
</div> </div>

View file

@ -1,5 +1,5 @@
<header class="clear"> <header class="clear">
<a href="/console" class="logo pull-start"> <a href="/console" class="logo pull-start link-animation-disabled">
<img src="/images/appwrite.svg" alt="Appwrite Light Logo" class="force-light" /> <img src="/images/appwrite.svg" alt="Appwrite Light Logo" class="force-light" />
<img src="/images/appwrite-footer-dark.svg" alt="Appwrite Dark Logo" class="force-dark" /> <img src="/images/appwrite-footer-dark.svg" alt="Appwrite Dark Logo" class="force-dark" />
</a> </a>
@ -34,10 +34,10 @@
data-failure-param-trigger-events="account.deleteSession"> data-failure-param-trigger-events="account.deleteSession">
<div class="console-back"> <div class="console-back">
<a href="/console">Back to Console &nbsp;<i class="icon-right-open"></i></a> <a href="/console" class="link-return-animation--end">Back to Console &nbsp;<i class="icon-right-open"></i></a>
</div> </div>
<div class="account link pull-end clear"> <div class="account link link-animation-disabled pull-end clear">
<img src="" data-ls-attrs="src={{account|gravatar}}" alt="User Avatar" class="avatar margin-start pull-end" /> <img src="" data-ls-attrs="src={{account|gravatar}}" alt="User Avatar" class="avatar margin-start pull-end" />
<span class="name pull-end desktops-only" data-ls-bind="{{account.name}}"></span> <span class="name pull-end desktops-only" data-ls-bind="{{account.name}}"></span>
</div> </div>
@ -45,10 +45,10 @@
<div class="console-index drop-list bottom end" data-ls-ui-open="" data-button-text="" data-button-icon="" data-button-selector="[data-toggler]" data-button-class="account-button" data-blur="1" tabindex="1"> <div class="console-index drop-list bottom end" data-ls-ui-open="" data-button-text="" data-button-icon="" data-button-selector="[data-toggler]" data-button-class="account-button" data-blur="1" tabindex="1">
<ul class="margin-top-large arrow-end"> <ul class="margin-top-large arrow-end">
<li> <li>
<a href="/console/account"><i class="icon-user"></i> &nbsp; Your Account</a> <a href="/console/account" class="link-animation-disabled"><i class="icon-user"></i> &nbsp; Your Account</a>
</li> </li>
<li> <li>
<span class="link"><i class="icon-sun-inv force-dark pull-start"></i><i class="icon-moon-inv force-light pull-start"></i> &nbsp; Change Theme <span class="link link-animation-disabled"><i class="icon-sun-inv force-dark pull-start"></i><i class="icon-moon-inv force-light pull-start"></i> &nbsp; Change Theme
<div class="pull-end switch-theme"> <div class="pull-end switch-theme">
<button data-general-theme <button data-general-theme
data-analytics-event="click" data-analytics-event="click"
@ -66,7 +66,7 @@
</div> </div>
<nav class="project-only" data-ls-ui-open="" data-button-class="round icon-btn phones-only tablets-only" data-button-icon="icon-dot-3"> <nav class="project-only" data-ls-ui-open="" data-button-class="round icon-btn phones-only tablets-only" data-button-icon="icon-dot-3">
<a class="logo" href="/console" <a class="logo link-animation-disabled" href="/console"
data-analytics-event="click" data-analytics-event="click"
data-analytics-category="console/navigation" data-analytics-category="console/navigation"
data-analytics-label="Logo Link"> data-analytics-label="Logo Link">
@ -83,7 +83,8 @@
<a data-ls-attrs="href=/console/home?project={{router.params.project}}" <a data-ls-attrs="href=/console/home?project={{router.params.project}}"
data-analytics-event="click" data-analytics-event="click"
data-analytics-category="console/navigation" data-analytics-category="console/navigation"
data-analytics-label="Home Link"> data-analytics-label="Home Link"
class="link-animation-disabled">
<i class="icon-home"></i> <i class="icon-home"></i>
Home Home
</a> </a>
@ -97,7 +98,8 @@
<a data-ls-attrs="href=/console/database?project={{router.params.project}}" <a data-ls-attrs="href=/console/database?project={{router.params.project}}"
data-analytics-event="click" data-analytics-event="click"
data-analytics-category="console/navigation" data-analytics-category="console/navigation"
data-analytics-label="Database Link"> data-analytics-label="Database Link"
class="link-animation-disabled">
<i class="icon-database"></i> <i class="icon-database"></i>
Database Database
</a> </a>
@ -106,7 +108,8 @@
<a data-ls-attrs="href=/console/storage?project={{router.params.project}}" <a data-ls-attrs="href=/console/storage?project={{router.params.project}}"
data-analytics-event="click" data-analytics-event="click"
data-analytics-category="console/navigation" data-analytics-category="console/navigation"
data-analytics-label="Storage Link"> data-analytics-label="Storage Link"
class="link-animation-disabled">
<i class="icon-folder"></i> <i class="icon-folder"></i>
Storage Storage
</a> </a>
@ -115,7 +118,8 @@
<a data-ls-attrs="href=/console/users?project={{router.params.project}}" <a data-ls-attrs="href=/console/users?project={{router.params.project}}"
data-analytics-event="click" data-analytics-event="click"
data-analytics-category="console/navigation" data-analytics-category="console/navigation"
data-analytics-label="Users Link"> data-analytics-label="Users Link"
class="link-animation-disabled">
<i class="icon-users"></i> <i class="icon-users"></i>
Users Users
</a> </a>
@ -129,7 +133,8 @@
<a data-ls-attrs="href=/console/tasks?project={{router.params.project}}" <a data-ls-attrs="href=/console/tasks?project={{router.params.project}}"
data-analytics-event="click" data-analytics-event="click"
data-analytics-category="console/navigation" data-analytics-category="console/navigation"
data-analytics-label="Tasks Link"> data-analytics-label="Tasks Link"
class="link-animation-disabled">
<i class="icon-clock"></i> <i class="icon-clock"></i>
Tasks Tasks
</a> </a>
@ -138,7 +143,8 @@
<a data-ls-attrs="href=/console/webhooks?project={{router.params.project}}" <a data-ls-attrs="href=/console/webhooks?project={{router.params.project}}"
data-analytics-event="click" data-analytics-event="click"
data-analytics-category="console/navigation" data-analytics-category="console/navigation"
data-analytics-label="Webhooks Links"> data-analytics-label="Webhooks Links"
class="link-animation-disabled">
<i class="icon-link"></i> <i class="icon-link"></i>
Webhooks Webhooks
</a> </a>
@ -147,7 +153,8 @@
<a data-ls-attrs="href=/console/keys?project={{router.params.project}}" <a data-ls-attrs="href=/console/keys?project={{router.params.project}}"
data-analytics-event="click" data-analytics-event="click"
data-analytics-category="console/navigation" data-analytics-category="console/navigation"
data-analytics-label="API Keys Link"> data-analytics-label="API Keys Link"
class="link-animation-disabled">
<i class="icon-key-inv"></i> <i class="icon-key-inv"></i>
API Keys API Keys
</a> </a>
@ -160,7 +167,8 @@
<a data-ls-attrs="href=/console/settings?project={{router.params.project}}" <a data-ls-attrs="href=/console/settings?project={{router.params.project}}"
data-analytics-event="click" data-analytics-event="click"
data-analytics-category="console/navigation" data-analytics-category="console/navigation"
data-analytics-label="Settings Link"> data-analytics-label="Settings Link"
class="link-animation-disabled">
<i class="icon-cog"></i> Settings</a> <i class="icon-cog"></i> Settings</a>
</li> </li>
</ul> </ul>
@ -214,4 +222,4 @@
<button type="submit">Create</button> &nbsp; <button data-ui-modal-close="" type="button" class="reverse">Cancel</button> <button type="submit">Create</button> &nbsp; <button data-ui-modal-close="" type="button" class="reverse">Cancel</button>
</footer> </footer>
</form> </form>
</div> </div>

View file

@ -12,7 +12,7 @@ $rules = $collection->getAttribute('rules', []);
<div class="cover"> <div class="cover">
<h1 class="zone xl margin-bottom-large"> <h1 class="zone xl margin-bottom-large">
<a data-ls-attrs="href=/console/database?project={{router.params.project}}" class="back text-size-small"><i class="icon-left-open"></i> Database</a> <a data-ls-attrs="href=/console/database?project={{router.params.project}}" class="back text-size-small link-return-animation--start"><i class="icon-left-open"></i> Database</a>
<br /> <br />
@ -457,7 +457,7 @@ $rules = $collection->getAttribute('rules', []);
<script type="text/html" id="template-validation-numeric"> <script type="text/html" id="template-validation-numeric">
<div class="margin-bottom"> <div class="margin-bottom">
<label data-ls-attrs="for=rule-default-{{rule.$id}}">Default Value</label> <label data-ls-attrs="for=rule-default-{{rule.$id}}">Default Value</label>
<input name="default" type="number" data-ls-bind="{{rule.default}}" data-cast-to="integer" placeholder="0" /> <input name="default" type="number" data-ls-bind="{{rule.default}}" data-cast-to="numeric" placeholder="0" step="any" />
</div> </div>
</script> </script>
@ -516,4 +516,4 @@ $rules = $collection->getAttribute('rules', []);
data-event="load,database.createCollection,database.updateCollection,database.deleteCollection" data-event="load,database.createCollection,database.updateCollection,database.deleteCollection"
data-scope="sdk" data-scope="sdk"
data-name="project-collections"> data-name="project-collections">
</div> </div>

View file

@ -20,7 +20,7 @@ $collections = [];
$key = (isset($rule['key'])) ? $rule['key'] : ''; $key = (isset($rule['key'])) ? $rule['key'] : '';
$label = (isset($rule['label'])) ? $rule['label'] : ''; $label = (isset($rule['label'])) ? $rule['label'] : '';
$type = (isset($rule['type'])) ? $rule['type'] : ''; $type = (isset($rule['type'])) ? $rule['type'] : '';
$list = (isset($rule['list'])) ? $rule['list'] : []; $list = (isset($rule['list']) && !empty($list)) ? $rule['list'] : [];
?> ?>
<?php foreach($list as $item): <?php foreach($list as $item):
if($item === $collection->getId()) { if($item === $collection->getId()) {
@ -51,7 +51,7 @@ $collections = [];
$key = (isset($rule['key'])) ? $rule['key'] : ''; $key = (isset($rule['key'])) ? $rule['key'] : '';
$label = (isset($rule['label'])) ? $rule['label'] : ''; $label = (isset($rule['label'])) ? $rule['label'] : '';
$type = (isset($rule['type'])) ? $rule['type'] : ''; $type = (isset($rule['type'])) ? $rule['type'] : '';
$list = (isset($rule['list'])) ? $rule['list'] : false; $list = (isset($rule['list'])) ? $rule['list'] : [];
$array = (isset($rule['array'])) ? $rule['array'] : false; $array = (isset($rule['array'])) ? $rule['array'] : false;
?> ?>
@ -163,7 +163,7 @@ $collections = [];
<div class="cover"> <div class="cover">
<h1 class="zone xl margin-bottom-large"> <h1 class="zone xl margin-bottom-large">
<a data-ls-attrs="href=/console/database/collection?id={{router.params.collection}}&project={{router.params.project}}" class="back text-size-small"><i class="icon-left-open"></i> <?php echo $this->escape($name); ?></a> <a data-ls-attrs="href=/console/database/collection?id={{router.params.collection}}&project={{router.params.project}}" class="back text-size-small link-return-animation--start"><i class="icon-left-open"></i> <?php echo $this->escape($name); ?></a>
<br /> <br />
@ -315,4 +315,4 @@ $collections = [];
</li> --> </li> -->
</ul> </ul>
</div> </div>
</div> </div>

View file

@ -1,6 +1,6 @@
<div class="cover"> <div class="cover">
<h1 class="zone xl margin-bottom-large"> <h1 class="zone xl margin-bottom-large">
<a data-ls-attrs="href=/console/home?project={{router.params.project}}" class="back text-size-small"><i class="icon-left-open"></i> Home</a> <a data-ls-attrs="href=/console/home?project={{router.params.project}}" class="back text-size-small link-return-animation--start"><i class="icon-left-open"></i> Home</a>
<br /> <br />
<span>Database</span> <span>Database</span>
@ -65,7 +65,7 @@
<div data-ls-if="0 != {{project-collections.sum}}"> <div data-ls-if="0 != {{project-collections.sum}}">
<ul data-ls-loop="project-collections.collections" data-ls-as="collection" data-ls-append="" class="tiles cell-3 margin-bottom-small" style="visibility: hidden"> <ul data-ls-loop="project-collections.collections" data-ls-as="collection" data-ls-append="" class="tiles cell-3 margin-bottom-small" style="visibility: hidden">
<li class="margin-bottom"> <li class="margin-bottom">
<a data-ls-attrs="href=/console/database/collection?id={{collection.$id}}&project={{router.params.project}}" class="box"> <a data-ls-attrs="href=/console/database/collection?id={{collection.$id}}&project={{router.params.project}}" class="box link-animation-disabled">
<div data-ls-bind="{{collection.name}}" class="text-one-liner margin-bottom text-bold">&nbsp;</div> <div data-ls-bind="{{collection.name}}" class="text-one-liner margin-bottom text-bold">&nbsp;</div>
<i class="icon-right-open"></i> <i class="icon-right-open"></i>
@ -109,4 +109,4 @@
</li> --> </li> -->
</ul> </ul>
</div> </div>
</div> </div>

View file

@ -4,4 +4,4 @@ $required = $this->getParam('required', '');
$namespace = $this->getParam('namespace', ''); $namespace = $this->getParam('namespace', '');
?> ?>
<input name="<?php echo $this->escape($key); ?>" type="number" autocomplete="off" data-ls-bind="{{<?php echo $this->escape($namespace); ?>}}" data-cast-to="integer"<?php if($required): ?> required<?php endif; ?> class="margin-bottom-no" /> <input name="<?php echo $this->escape($key); ?>" type="number" autocomplete="off" data-ls-bind="{{<?php echo $this->escape($namespace); ?>}}" data-cast-to="numeric"<?php if($required): ?> required<?php endif; ?> class="margin-bottom-no" step=any />

View file

@ -33,7 +33,7 @@ $home = $this->getParam('home', '');
<ul data-ls-loop="console-projects" data-ls-as="project" data-ls-append="" class="tiles cell-3" style="visibility: hidden"> <ul data-ls-loop="console-projects" data-ls-as="project" data-ls-append="" class="tiles cell-3" style="visibility: hidden">
<li class="margin-bottom"> <li class="margin-bottom">
<a data-ls-attrs="href=/console/home?project={{project.$id}}" class="box"> <a data-ls-attrs="href=/console/home?project={{project.$id}}" class="box link-animation-disabled">
<div data-ls-bind="{{project.name}}" class="text-one-liner margin-bottom-tiny text-bold">&nbsp;</div> <div data-ls-bind="{{project.name}}" class="text-one-liner margin-bottom-tiny text-bold">&nbsp;</div>
<p data-ls-if="({{project.platforms.length}})" class="text-fade text-size-small" data-ls-bind="{{project.platforms.length}} apps"></p> <p data-ls-if="({{project.platforms.length}})" class="text-fade text-size-small" data-ls-bind="{{project.platforms.length}} apps"></p>
@ -102,4 +102,4 @@ $home = $this->getParam('home', '');
</div> </div>
</div> </div>
</div> </div>
</section> </section>

View file

@ -3,7 +3,7 @@ $scopes = $this->getParam('scopes', []);
?> ?>
<div class="cover margin-bottom-large"> <div class="cover margin-bottom-large">
<h1 class="zone xl margin-bottom-large"> <h1 class="zone xl margin-bottom-large">
<a data-ls-attrs="href=/console/home?project={{router.params.project}}" class="back text-size-small"><i class="icon-left-open"></i> Home</a> <a data-ls-attrs="href=/console/home?project={{router.params.project}}" class="back text-size-small link-return-animation--start"><i class="icon-left-open"></i> Home</a>
<br /> <br />
<span>API Keys</span> <span>API Keys</span>
@ -167,4 +167,4 @@ $scopes = $this->getParam('scopes', []);
</form> </form>
</div> </div>
</div> </div>
</div> </div>

View file

@ -6,7 +6,7 @@ $customDomainsTarget = $this->getParam('customDomainsTarget', false);
?> ?>
<div class="cover"> <div class="cover">
<h1 class="zone xl margin-bottom-large"> <h1 class="zone xl margin-bottom-large">
<a data-ls-attrs="href=/console/home?project={{router.params.project}}" class="back text-size-small"><i class="icon-left-open"></i> Home</a> <a data-ls-attrs="href=/console/home?project={{router.params.project}}" class="back text-size-small link-return-animation--start"><i class="icon-left-open"></i> Home</a>
<br /> <br />
<span>Settings</span> <span>Settings</span>
@ -27,8 +27,10 @@ $customDomainsTarget = $this->getParam('customDomainsTarget', false);
<li data-state="/console/settings?project={{router.params.project}}"> <li data-state="/console/settings?project={{router.params.project}}">
<h2>Overview</h2> <h2>Overview</h2>
<div class="row responsive"> <div class="row responsive margin-top-negative">
<div class="col span-8 margin-bottom"> <div class="col span-8 margin-bottom">
<label>&nbsp;</label>
<div class="box margin-bottom-large"> <div class="box margin-bottom-large">
<form <form
data-analytics-event="submit" data-analytics-event="submit"
@ -500,4 +502,4 @@ $customDomainsTarget = $this->getParam('customDomainsTarget', false);
</li> </li>
</ul> </ul>
</div> </div>
</div> </div>

View file

@ -5,7 +5,7 @@ $fileLimitHuman = $this->getParam('fileLimitHuman', 0);
?> ?>
<div class="cover"> <div class="cover">
<h1 class="zone xl margin-bottom-large"> <h1 class="zone xl margin-bottom-large">
<a data-ls-attrs="href=/console/home?project={{router.params.project}}" class="back text-size-small"><i class="icon-left-open"></i> Home</a> <a data-ls-attrs="href=/console/home?project={{router.params.project}}" class="back text-size-small link-return-animation--start"><i class="icon-left-open"></i> Home</a>
<br /> <br />
<span>Storage</span> <span>Storage</span>
@ -36,7 +36,7 @@ $fileLimitHuman = $this->getParam('fileLimitHuman', 0);
data-failure="alert" data-failure="alert"
data-failure-param-alert-text="Failed to upload file" data-failure-param-alert-text="Failed to upload file"
data-failure-param-alert-classname="error"> data-failure-param-alert-classname="error">
<input type="hidden" name="folderId" id="files-folderId" data-cast-to="int" value="1"> <input type="hidden" name="folderId" id="files-folderId" data-cast-to="integer" value="1">
<label for="file-read">File</label> <label for="file-read">File</label>
<input type="file" name="file" id="file-file" size="1" required> <input type="file" name="file" id="file-file" size="1" required>
@ -141,7 +141,7 @@ $fileLimitHuman = $this->getParam('fileLimitHuman', 0);
<div class="input-copy"> <div class="input-copy">
<input data-forms-copy type="text" data-ls-attrs="id=file-id-{{file.$id}}" name="fileId" disabled data-ls-bind="{{file.$id}}" /> <input data-forms-copy type="text" data-ls-attrs="id=file-id-{{file.$id}}" name="fileId" disabled data-ls-bind="{{file.$id}}" />
</div> </div>
<input type="hidden" data-ls-attrs="id=file-folderId-{{file.$id}}" name="folderId" data-cast-to="int" value="1"> <input type="hidden" data-ls-attrs="id=file-folderId-{{file.$id}}" name="folderId" data-cast-to="integer" value="1">
<label for="file-read">Read Access (<a data-ls-attrs="href={{env.HOME}}/docs/permissions" target="_blank">Learn more</a>)</label> <label for="file-read">Read Access (<a data-ls-attrs="href={{env.HOME}}/docs/permissions" target="_blank">Learn more</a>)</label>
<input type="hidden" data-ls-attrs="id=file-read-{{file.$id}}" name="read" data-forms-tags data-cast-to="json" data-ls-bind="{{file.$permissions.read}}" placeholder="User ID, Team ID or Role" /> <input type="hidden" data-ls-attrs="id=file-read-{{file.$id}}" name="read" data-forms-tags data-cast-to="json" data-ls-bind="{{file.$permissions.read}}" placeholder="User ID, Team ID or Role" />
@ -240,4 +240,4 @@ $fileLimitHuman = $this->getParam('fileLimitHuman', 0);
</div> </div>
</li> </li>
</ul> </ul>
</div> </div>

View file

@ -1,6 +1,6 @@
<div class="cover margin-bottom-large"> <div class="cover margin-bottom-large">
<h1 class="zone xl margin-bottom-large"> <h1 class="zone xl margin-bottom-large">
<a data-ls-attrs="href=/console/home?project={{router.params.project}}" class="back text-size-small"><i class="icon-left-open"></i> Home</a> <a data-ls-attrs="href=/console/home?project={{router.params.project}}" class="back text-size-small link-return-animation--start"><i class="icon-left-open"></i> Home</a>
<br /> <br />
<span>Tasks</span> <span>Tasks</span>
@ -346,4 +346,4 @@
</form> </form>
</div> </div>
</div> </div>
</div> </div>

View file

@ -4,7 +4,7 @@ $providers = $this->getParam('providers', []);
<div class="cover"> <div class="cover">
<h1 class="zone xl margin-bottom-large"> <h1 class="zone xl margin-bottom-large">
<a data-ls-attrs="href=/console/home?project={{router.params.project}}" class="back text-size-small"><i class="icon-left-open"></i> Home</a> <a data-ls-attrs="href=/console/home?project={{router.params.project}}" class="back text-size-small link-return-animation--start"><i class="icon-left-open"></i> Home</a>
<br /> <br />
<span>Users</span> <span>Users</span>
@ -387,4 +387,4 @@ $providers = $this->getParam('providers', []);
</div> </div>
</li> </li>
</ul> </ul>
</div> </div>

View file

@ -8,7 +8,7 @@
<div class="cover"> <div class="cover">
<h1 class="zone xl margin-bottom-large"> <h1 class="zone xl margin-bottom-large">
<a data-ls-attrs="href=/console/users?project={{router.params.project}}" class="back text-size-small"><i class="icon-left-open"></i> Users</a> <a data-ls-attrs="href=/console/users?project={{router.params.project}}" class="back text-size-small link-return-animation--start"><i class="icon-left-open"></i> Users</a>
<br /> <br />
<span data-ls-bind="{{user.name}}">&nbsp;</span> <span data-ls-bind="{{user.name}}">&nbsp;</span>
@ -255,4 +255,4 @@
</li> </li>
</ul> </ul>
</div> </div>
</div> </div>

View file

@ -5,7 +5,7 @@ $events = array_keys($this->getParam('events', []));
?> ?>
<div class="cover margin-bottom-large"> <div class="cover margin-bottom-large">
<h1 class="zone xl margin-bottom-large"> <h1 class="zone xl margin-bottom-large">
<a data-ls-attrs="href=/console/home?project={{router.params.project}}" class="back text-size-small"><i class="icon-left-open"></i> Home</a> <a data-ls-attrs="href=/console/home?project={{router.params.project}}" class="back text-size-small link-return-animation--start"><i class="icon-left-open"></i> Home</a>
<br /> <br />
<span>Webhooks</span> <span>Webhooks</span>
@ -227,4 +227,4 @@ $events = array_keys($this->getParam('events', []));
</form> </form>
</div> </div>
</div> </div>
</div> </div>

View file

@ -1,6 +1,6 @@
<div class="logo text-align-center margin-bottom-xl"> <div class="logo text-align-center margin-bottom-xl">
<a href="/"> <a href="/" class="link-animation-disabled">
<img src="/images/appwrite.svg" alt="Appwrite Light Logo" class="force-light" /> <img src="/images/appwrite.svg" alt="Appwrite Light Logo" class="force-light" />
<img src="/images/appwrite-footer-dark.svg" alt="Appwrite Dark Logo" class="force-dark" /> <img src="/images/appwrite-footer-dark.svg" alt="Appwrite Dark Logo" class="force-dark" />
</a> </a>
</div> </div>

View file

@ -1,6 +1,3 @@
#!/bin/bash #!/bin/bash
export PHP_VERSION=$PHP_VERSION
# Init server settings
php /usr/share/nginx/html/app/tasks/migrate.php run php /usr/share/nginx/html/app/tasks/migrate.php run

View file

@ -66,6 +66,7 @@ services:
#- _APP_ENV=production #- _APP_ENV=production
- _APP_ENV=development - _APP_ENV=development
- _APP_OPTIONS_ABUSE=disabled - _APP_OPTIONS_ABUSE=disabled
- _APP_OPTIONS_FORCE_HTTPS=disabled
- _APP_OPENSSL_KEY_V1=your-secret-key - _APP_OPENSSL_KEY_V1=your-secret-key
- _APP_DOMAIN=demo.appwrite.io - _APP_DOMAIN=demo.appwrite.io
- _APP_DOMAIN_TARGET=demo.appwrite.io - _APP_DOMAIN_TARGET=demo.appwrite.io

View file

@ -0,0 +1,3 @@
Use this endpoint to show your user initials avatar icon on your website or app. By default, this route will try to print your logged-in user name or email initials. You can also overwrite the user name if you pass the 'name' parameter. If no name is given and no user is logged, an empty avatar will be returned.
You can use the color and background params to change the avatar colors. By default, a random theme will be selected. The random theme will persist for the user's initials when reloading the same theme will always return for the same initials.

View file

@ -10,7 +10,11 @@ Set your server running environment. By default, the var is set to 'development'
### _APP_OPTIONS_ABUSE ### _APP_OPTIONS_ABUSE
Allows you to disable abuse checks and API rate limiting. By default, set to 'enabled'. To cancel the abuse checking, set to 'disabled'. It is not recommended to disable this check-in a production environment. Allows you to disable abuse checks and API rate limiting. By default, set to 'enabled'. To cancel the abuse checking, set to 'disabled'. It is not recommended to disable this feature in a production environment.
### _APP_OPTIONS_FORCE_HTTPS
Allows you to force HTTPS connection to your API. This feature redirects any HTTP call to HTTPS and adds the 'Strict-Transport-Security' header to all HTTP responses. By default, set to 'disabled'. To enable, set to 'enabled'. This feature will work only when your ports are set to default 80 and 443.
### _APP_OPENSSL_KEY_V1 ### _APP_OPENSSL_KEY_V1

View file

@ -2511,7 +2511,7 @@ match=text.match(new RegExp(regex,'gi'))
if(!match){return fail} if(!match){return fail}
for(i=0,len=match.length;i<len;i++){if(!process(match[i])){return fail}} for(i=0,len=match.length;i<len;i++){if(!process(match[i])){return fail}}
return(date.getTime()/1000)} return(date.getTime()/1000)}
return{format:format,strtotime:strtotime}}(),true);})(window);(function(window){"use strict";window.ls.container.set('env',function(){return APP_ENV;},true);})(window);(function(window){"use strict";window.ls.container.set('form',function(){function cast(value,to){switch(to){case'int':case'integer':value=parseInt(value);break;case'string':value=value.toString();break;case'json':value=(value)?JSON.parse(value):[];break;case'array':value=(value&&value.constructor&&value.constructor===Array)?value:[value];break;case'array-empty':value=[];break;case'bool':case'boolean':value=(value==='false')?false:value;value=!!value;break;} return{format:format,strtotime:strtotime}}(),true);})(window);(function(window){"use strict";window.ls.container.set('env',function(){return APP_ENV;},true);})(window);(function(window){"use strict";window.ls.container.set('form',function(){function cast(value,to){switch(to){case'int':case'integer':value=parseInt(value);break;case'numeric':value=Number(value);break;case'string':value=value.toString();break;case'json':value=(value)?JSON.parse(value):[];break;case'array':value=(value&&value.constructor&&value.constructor===Array)?value:[value];break;case'array-empty':value=[];break;case'bool':case'boolean':value=(value==='false')?false:value;value=!!value;break;}
return value;} return value;}
function toJson(element,json){json=json||{};let name=element.getAttribute('name');let type=element.getAttribute('type');let castTo=element.getAttribute('data-cast-to');let ref=json;if(name&&'FORM'!==element.tagName){if('FIELDSET'===element.tagName){if(castTo==='object'){if(json[name]===undefined){json[name]={};} function toJson(element,json){json=json||{};let name=element.getAttribute('name');let type=element.getAttribute('type');let castTo=element.getAttribute('data-cast-to');let ref=json;if(name&&'FORM'!==element.tagName){if('FIELDSET'===element.tagName){if(castTo==='object'){if(json[name]===undefined){json[name]={};}
ref=json[name];} ref=json[name];}
@ -2553,15 +2553,10 @@ return k;}
function J(k){k=k.replace(/rn/g,"n");let d="";for(let F=0;F<k.length;F++){let x=k.charCodeAt(F);if(x<128){d+=String.fromCharCode(x);}else{if(x>127&&x<2048){d+=String.fromCharCode((x>>6)|192);d+=String.fromCharCode((x&63)|128);}else{d+=String.fromCharCode((x>>12)|224);d+=String.fromCharCode(((x>>6)&63)|128);d+=String.fromCharCode((x&63)|128);}}} function J(k){k=k.replace(/rn/g,"n");let d="";for(let F=0;F<k.length;F++){let x=k.charCodeAt(F);if(x<128){d+=String.fromCharCode(x);}else{if(x>127&&x<2048){d+=String.fromCharCode((x>>6)|192);d+=String.fromCharCode((x&63)|128);}else{d+=String.fromCharCode((x>>12)|224);d+=String.fromCharCode(((x>>6)&63)|128);d+=String.fromCharCode((x&63)|128);}}}
return d;} return d;}
let C=Array();let P,h,E,v,g,Y,X,W,V;let S=7,Q=12,N=17,M=22;let A=5,z=9,y=14,w=20;let o=4,m=11,l=16,j=23;let U=6,T=10,R=15,O=21;s=J(s);C=e(s);Y=1732584193;X=4023233417;W=2562383102;V=271733878;for(P=0;P<C.length;P+=16){h=Y;E=X;v=W;g=V;Y=u(Y,X,W,V,C[P+0],S,3614090360);V=u(V,Y,X,W,C[P+1],Q,3905402710);W=u(W,V,Y,X,C[P+2],N,606105819);X=u(X,W,V,Y,C[P+3],M,3250441966);Y=u(Y,X,W,V,C[P+4],S,4118548399);V=u(V,Y,X,W,C[P+5],Q,1200080426);W=u(W,V,Y,X,C[P+6],N,2821735955);X=u(X,W,V,Y,C[P+7],M,4249261313);Y=u(Y,X,W,V,C[P+8],S,1770035416);V=u(V,Y,X,W,C[P+9],Q,2336552879);W=u(W,V,Y,X,C[P+10],N,4294925233);X=u(X,W,V,Y,C[P+11],M,2304563134);Y=u(Y,X,W,V,C[P+12],S,1804603682);V=u(V,Y,X,W,C[P+13],Q,4254626195);W=u(W,V,Y,X,C[P+14],N,2792965006);X=u(X,W,V,Y,C[P+15],M,1236535329);Y=f(Y,X,W,V,C[P+1],A,4129170786);V=f(V,Y,X,W,C[P+6],z,3225465664);W=f(W,V,Y,X,C[P+11],y,643717713);X=f(X,W,V,Y,C[P+0],w,3921069994);Y=f(Y,X,W,V,C[P+5],A,3593408605);V=f(V,Y,X,W,C[P+10],z,38016083);W=f(W,V,Y,X,C[P+15],y,3634488961);X=f(X,W,V,Y,C[P+4],w,3889429448);Y=f(Y,X,W,V,C[P+9],A,568446438);V=f(V,Y,X,W,C[P+14],z,3275163606);W=f(W,V,Y,X,C[P+3],y,4107603335);X=f(X,W,V,Y,C[P+8],w,1163531501);Y=f(Y,X,W,V,C[P+13],A,2850285829);V=f(V,Y,X,W,C[P+2],z,4243563512);W=f(W,V,Y,X,C[P+7],y,1735328473);X=f(X,W,V,Y,C[P+12],w,2368359562);Y=D(Y,X,W,V,C[P+5],o,4294588738);V=D(V,Y,X,W,C[P+8],m,2272392833);W=D(W,V,Y,X,C[P+11],l,1839030562);X=D(X,W,V,Y,C[P+14],j,4259657740);Y=D(Y,X,W,V,C[P+1],o,2763975236);V=D(V,Y,X,W,C[P+4],m,1272893353);W=D(W,V,Y,X,C[P+7],l,4139469664);X=D(X,W,V,Y,C[P+10],j,3200236656);Y=D(Y,X,W,V,C[P+13],o,681279174);V=D(V,Y,X,W,C[P+0],m,3936430074);W=D(W,V,Y,X,C[P+3],l,3572445317);X=D(X,W,V,Y,C[P+6],j,76029189);Y=D(Y,X,W,V,C[P+9],o,3654602809);V=D(V,Y,X,W,C[P+12],m,3873151461);W=D(W,V,Y,X,C[P+15],l,530742520);X=D(X,W,V,Y,C[P+2],j,3299628645);Y=t(Y,X,W,V,C[P+0],U,4096336452);V=t(V,Y,X,W,C[P+7],T,1126891415);W=t(W,V,Y,X,C[P+14],R,2878612391);X=t(X,W,V,Y,C[P+5],O,4237533241);Y=t(Y,X,W,V,C[P+12],U,1700485571);V=t(V,Y,X,W,C[P+3],T,2399980690);W=t(W,V,Y,X,C[P+10],R,4293915773);X=t(X,W,V,Y,C[P+1],O,2240044497);Y=t(Y,X,W,V,C[P+8],U,1873313359);V=t(V,Y,X,W,C[P+15],T,4264355552);W=t(W,V,Y,X,C[P+6],R,2734768916);X=t(X,W,V,Y,C[P+13],O,1309151649);Y=t(Y,X,W,V,C[P+4],U,4149444226);V=t(V,Y,X,W,C[P+11],T,3174756917);W=t(W,V,Y,X,C[P+2],R,718787259);X=t(X,W,V,Y,C[P+9],O,3951481745);Y=K(Y,h);X=K(X,E);W=K(W,v);V=K(V,g);} let C=Array();let P,h,E,v,g,Y,X,W,V;let S=7,Q=12,N=17,M=22;let A=5,z=9,y=14,w=20;let o=4,m=11,l=16,j=23;let U=6,T=10,R=15,O=21;s=J(s);C=e(s);Y=1732584193;X=4023233417;W=2562383102;V=271733878;for(P=0;P<C.length;P+=16){h=Y;E=X;v=W;g=V;Y=u(Y,X,W,V,C[P+0],S,3614090360);V=u(V,Y,X,W,C[P+1],Q,3905402710);W=u(W,V,Y,X,C[P+2],N,606105819);X=u(X,W,V,Y,C[P+3],M,3250441966);Y=u(Y,X,W,V,C[P+4],S,4118548399);V=u(V,Y,X,W,C[P+5],Q,1200080426);W=u(W,V,Y,X,C[P+6],N,2821735955);X=u(X,W,V,Y,C[P+7],M,4249261313);Y=u(Y,X,W,V,C[P+8],S,1770035416);V=u(V,Y,X,W,C[P+9],Q,2336552879);W=u(W,V,Y,X,C[P+10],N,4294925233);X=u(X,W,V,Y,C[P+11],M,2304563134);Y=u(Y,X,W,V,C[P+12],S,1804603682);V=u(V,Y,X,W,C[P+13],Q,4254626195);W=u(W,V,Y,X,C[P+14],N,2792965006);X=u(X,W,V,Y,C[P+15],M,1236535329);Y=f(Y,X,W,V,C[P+1],A,4129170786);V=f(V,Y,X,W,C[P+6],z,3225465664);W=f(W,V,Y,X,C[P+11],y,643717713);X=f(X,W,V,Y,C[P+0],w,3921069994);Y=f(Y,X,W,V,C[P+5],A,3593408605);V=f(V,Y,X,W,C[P+10],z,38016083);W=f(W,V,Y,X,C[P+15],y,3634488961);X=f(X,W,V,Y,C[P+4],w,3889429448);Y=f(Y,X,W,V,C[P+9],A,568446438);V=f(V,Y,X,W,C[P+14],z,3275163606);W=f(W,V,Y,X,C[P+3],y,4107603335);X=f(X,W,V,Y,C[P+8],w,1163531501);Y=f(Y,X,W,V,C[P+13],A,2850285829);V=f(V,Y,X,W,C[P+2],z,4243563512);W=f(W,V,Y,X,C[P+7],y,1735328473);X=f(X,W,V,Y,C[P+12],w,2368359562);Y=D(Y,X,W,V,C[P+5],o,4294588738);V=D(V,Y,X,W,C[P+8],m,2272392833);W=D(W,V,Y,X,C[P+11],l,1839030562);X=D(X,W,V,Y,C[P+14],j,4259657740);Y=D(Y,X,W,V,C[P+1],o,2763975236);V=D(V,Y,X,W,C[P+4],m,1272893353);W=D(W,V,Y,X,C[P+7],l,4139469664);X=D(X,W,V,Y,C[P+10],j,3200236656);Y=D(Y,X,W,V,C[P+13],o,681279174);V=D(V,Y,X,W,C[P+0],m,3936430074);W=D(W,V,Y,X,C[P+3],l,3572445317);X=D(X,W,V,Y,C[P+6],j,76029189);Y=D(Y,X,W,V,C[P+9],o,3654602809);V=D(V,Y,X,W,C[P+12],m,3873151461);W=D(W,V,Y,X,C[P+15],l,530742520);X=D(X,W,V,Y,C[P+2],j,3299628645);Y=t(Y,X,W,V,C[P+0],U,4096336452);V=t(V,Y,X,W,C[P+7],T,1126891415);W=t(W,V,Y,X,C[P+14],R,2878612391);X=t(X,W,V,Y,C[P+5],O,4237533241);Y=t(Y,X,W,V,C[P+12],U,1700485571);V=t(V,Y,X,W,C[P+3],T,2399980690);W=t(W,V,Y,X,C[P+10],R,4293915773);X=t(X,W,V,Y,C[P+1],O,2240044497);Y=t(Y,X,W,V,C[P+8],U,1873313359);V=t(V,Y,X,W,C[P+15],T,4264355552);W=t(W,V,Y,X,C[P+6],R,2734768916);X=t(X,W,V,Y,C[P+13],O,1309151649);Y=t(Y,X,W,V,C[P+4],U,4149444226);V=t(V,Y,X,W,C[P+11],T,3174756917);W=t(W,V,Y,X,C[P+2],R,718787259);X=t(X,W,V,Y,C[P+9],O,3951481745);Y=K(Y,h);X=K(X,E);W=K(W,v);V=K(V,g);}
let i=B(Y)+B(X)+B(W)+B(V);return i.toLowerCase();};let size=element.dataset["size"]||80;let email=$value.email||$value||"";let name=$value.name||$value||"";name=(typeof name!=='string')?'':name;let theme=name.split("").map(char=>char.charCodeAt(0)).reduce((a,b)=>a+b,0).toString();let themes=[{color:"27005e",background:"e1d2f6"},{color:"5e2700",background:"f3d9c6"},{color:"006128",background:"c9f3c6"},{color:"580061",background:"f2d1f5"},{color:"00365d",background:"c6e1f3"},{color:"00075c",background:"d2d5f6"},{color:"610038",background:"f5d1e6"},{color:"386100",background:"dcf1bd"},{color:"615800",background:"f1ecba"},{color:"610008",background:"f6d2d5"}];name=name.split(" ").map(function(n){if(!isNaN(parseFloat(n))&&isFinite(n)){return"";} let i=B(Y)+B(X)+B(W)+B(V);return i.toLowerCase();};let size=element.dataset["size"]||80;let email=$value.email||$value||"";let name=$value.name||$value||"";name=(typeof name!=='string')?'--':name;let def="/v1/avatars/initials?project=console"+"&name="+
return n[0];}).join("")||"--";let background=themes[theme[theme.length-1]]["background"];let color=themes[theme[theme.length-1]]["color"];let def="https://ui-avatars.com/api/"+ encodeURIComponent(name)+"&width="+
encodeURIComponent(name)+"/"+ size+"&height="+
size+"/"+ size;return def;}).add("selectedCollection",function($value,router){return $value===router.params.collectionId?"selected":"";}).add("selectedDocument",function($value,router){return $value===router.params.documentId?"selected":"";}).add("localeString",function($value){$value=parseInt($value);return!Number.isNaN($value)?$value.toLocaleString():"";}).add("date",function($value,date){return date.format("Y-m-d",$value);}).add("date-time",function($value,date){return date.format("Y-m-d H:i",$value);}).add("date-text",function($value,date){return date.format("d M Y",$value);}).add("ms2hum",function($value){let temp=$value;const years=Math.floor(temp/31536000),days=Math.floor((temp%=31536000)/86400),hours=Math.floor((temp%=86400)/3600),minutes=Math.floor((temp%=3600)/60),seconds=temp%60;if(days||hours||seconds||minutes){return((years?years+"y ":"")+
encodeURIComponent(background)+"/"+
encodeURIComponent(color);return("//www.gravatar.com/avatar/"+
MD5(email)+".jpg?s="+
size+"&d="+
encodeURIComponent(def));}).add("selectedCollection",function($value,router){return $value===router.params.collectionId?"selected":"";}).add("selectedDocument",function($value,router){return $value===router.params.documentId?"selected":"";}).add("localeString",function($value){$value=parseInt($value);return!Number.isNaN($value)?$value.toLocaleString():"";}).add("date",function($value,date){return date.format("Y-m-d",$value);}).add("date-time",function($value,date){return date.format("Y-m-d H:i",$value);}).add("date-text",function($value,date){return date.format("d M Y",$value);}).add("ms2hum",function($value){let temp=$value;const years=Math.floor(temp/31536000),days=Math.floor((temp%=31536000)/86400),hours=Math.floor((temp%=86400)/3600),minutes=Math.floor((temp%=3600)/60),seconds=temp%60;if(days||hours||seconds||minutes){return((years?years+"y ":"")+
(days?days+"d ":"")+ (days?days+"d ":"")+
(hours?hours+"h ":"")+ (hours?hours+"h ":"")+
(minutes?minutes+"m ":"")+ (minutes?minutes+"m ":"")+

View file

@ -225,7 +225,7 @@ match=text.match(new RegExp(regex,'gi'))
if(!match){return fail} if(!match){return fail}
for(i=0,len=match.length;i<len;i++){if(!process(match[i])){return fail}} for(i=0,len=match.length;i<len;i++){if(!process(match[i])){return fail}}
return(date.getTime()/1000)} return(date.getTime()/1000)}
return{format:format,strtotime:strtotime}}(),true);})(window);(function(window){"use strict";window.ls.container.set('env',function(){return APP_ENV;},true);})(window);(function(window){"use strict";window.ls.container.set('form',function(){function cast(value,to){switch(to){case'int':case'integer':value=parseInt(value);break;case'string':value=value.toString();break;case'json':value=(value)?JSON.parse(value):[];break;case'array':value=(value&&value.constructor&&value.constructor===Array)?value:[value];break;case'array-empty':value=[];break;case'bool':case'boolean':value=(value==='false')?false:value;value=!!value;break;} return{format:format,strtotime:strtotime}}(),true);})(window);(function(window){"use strict";window.ls.container.set('env',function(){return APP_ENV;},true);})(window);(function(window){"use strict";window.ls.container.set('form',function(){function cast(value,to){switch(to){case'int':case'integer':value=parseInt(value);break;case'numeric':value=Number(value);break;case'string':value=value.toString();break;case'json':value=(value)?JSON.parse(value):[];break;case'array':value=(value&&value.constructor&&value.constructor===Array)?value:[value];break;case'array-empty':value=[];break;case'bool':case'boolean':value=(value==='false')?false:value;value=!!value;break;}
return value;} return value;}
function toJson(element,json){json=json||{};let name=element.getAttribute('name');let type=element.getAttribute('type');let castTo=element.getAttribute('data-cast-to');let ref=json;if(name&&'FORM'!==element.tagName){if('FIELDSET'===element.tagName){if(castTo==='object'){if(json[name]===undefined){json[name]={};} function toJson(element,json){json=json||{};let name=element.getAttribute('name');let type=element.getAttribute('type');let castTo=element.getAttribute('data-cast-to');let ref=json;if(name&&'FORM'!==element.tagName){if('FIELDSET'===element.tagName){if(castTo==='object'){if(json[name]===undefined){json[name]={};}
ref=json[name];} ref=json[name];}
@ -267,15 +267,10 @@ return k;}
function J(k){k=k.replace(/rn/g,"n");let d="";for(let F=0;F<k.length;F++){let x=k.charCodeAt(F);if(x<128){d+=String.fromCharCode(x);}else{if(x>127&&x<2048){d+=String.fromCharCode((x>>6)|192);d+=String.fromCharCode((x&63)|128);}else{d+=String.fromCharCode((x>>12)|224);d+=String.fromCharCode(((x>>6)&63)|128);d+=String.fromCharCode((x&63)|128);}}} function J(k){k=k.replace(/rn/g,"n");let d="";for(let F=0;F<k.length;F++){let x=k.charCodeAt(F);if(x<128){d+=String.fromCharCode(x);}else{if(x>127&&x<2048){d+=String.fromCharCode((x>>6)|192);d+=String.fromCharCode((x&63)|128);}else{d+=String.fromCharCode((x>>12)|224);d+=String.fromCharCode(((x>>6)&63)|128);d+=String.fromCharCode((x&63)|128);}}}
return d;} return d;}
let C=Array();let P,h,E,v,g,Y,X,W,V;let S=7,Q=12,N=17,M=22;let A=5,z=9,y=14,w=20;let o=4,m=11,l=16,j=23;let U=6,T=10,R=15,O=21;s=J(s);C=e(s);Y=1732584193;X=4023233417;W=2562383102;V=271733878;for(P=0;P<C.length;P+=16){h=Y;E=X;v=W;g=V;Y=u(Y,X,W,V,C[P+0],S,3614090360);V=u(V,Y,X,W,C[P+1],Q,3905402710);W=u(W,V,Y,X,C[P+2],N,606105819);X=u(X,W,V,Y,C[P+3],M,3250441966);Y=u(Y,X,W,V,C[P+4],S,4118548399);V=u(V,Y,X,W,C[P+5],Q,1200080426);W=u(W,V,Y,X,C[P+6],N,2821735955);X=u(X,W,V,Y,C[P+7],M,4249261313);Y=u(Y,X,W,V,C[P+8],S,1770035416);V=u(V,Y,X,W,C[P+9],Q,2336552879);W=u(W,V,Y,X,C[P+10],N,4294925233);X=u(X,W,V,Y,C[P+11],M,2304563134);Y=u(Y,X,W,V,C[P+12],S,1804603682);V=u(V,Y,X,W,C[P+13],Q,4254626195);W=u(W,V,Y,X,C[P+14],N,2792965006);X=u(X,W,V,Y,C[P+15],M,1236535329);Y=f(Y,X,W,V,C[P+1],A,4129170786);V=f(V,Y,X,W,C[P+6],z,3225465664);W=f(W,V,Y,X,C[P+11],y,643717713);X=f(X,W,V,Y,C[P+0],w,3921069994);Y=f(Y,X,W,V,C[P+5],A,3593408605);V=f(V,Y,X,W,C[P+10],z,38016083);W=f(W,V,Y,X,C[P+15],y,3634488961);X=f(X,W,V,Y,C[P+4],w,3889429448);Y=f(Y,X,W,V,C[P+9],A,568446438);V=f(V,Y,X,W,C[P+14],z,3275163606);W=f(W,V,Y,X,C[P+3],y,4107603335);X=f(X,W,V,Y,C[P+8],w,1163531501);Y=f(Y,X,W,V,C[P+13],A,2850285829);V=f(V,Y,X,W,C[P+2],z,4243563512);W=f(W,V,Y,X,C[P+7],y,1735328473);X=f(X,W,V,Y,C[P+12],w,2368359562);Y=D(Y,X,W,V,C[P+5],o,4294588738);V=D(V,Y,X,W,C[P+8],m,2272392833);W=D(W,V,Y,X,C[P+11],l,1839030562);X=D(X,W,V,Y,C[P+14],j,4259657740);Y=D(Y,X,W,V,C[P+1],o,2763975236);V=D(V,Y,X,W,C[P+4],m,1272893353);W=D(W,V,Y,X,C[P+7],l,4139469664);X=D(X,W,V,Y,C[P+10],j,3200236656);Y=D(Y,X,W,V,C[P+13],o,681279174);V=D(V,Y,X,W,C[P+0],m,3936430074);W=D(W,V,Y,X,C[P+3],l,3572445317);X=D(X,W,V,Y,C[P+6],j,76029189);Y=D(Y,X,W,V,C[P+9],o,3654602809);V=D(V,Y,X,W,C[P+12],m,3873151461);W=D(W,V,Y,X,C[P+15],l,530742520);X=D(X,W,V,Y,C[P+2],j,3299628645);Y=t(Y,X,W,V,C[P+0],U,4096336452);V=t(V,Y,X,W,C[P+7],T,1126891415);W=t(W,V,Y,X,C[P+14],R,2878612391);X=t(X,W,V,Y,C[P+5],O,4237533241);Y=t(Y,X,W,V,C[P+12],U,1700485571);V=t(V,Y,X,W,C[P+3],T,2399980690);W=t(W,V,Y,X,C[P+10],R,4293915773);X=t(X,W,V,Y,C[P+1],O,2240044497);Y=t(Y,X,W,V,C[P+8],U,1873313359);V=t(V,Y,X,W,C[P+15],T,4264355552);W=t(W,V,Y,X,C[P+6],R,2734768916);X=t(X,W,V,Y,C[P+13],O,1309151649);Y=t(Y,X,W,V,C[P+4],U,4149444226);V=t(V,Y,X,W,C[P+11],T,3174756917);W=t(W,V,Y,X,C[P+2],R,718787259);X=t(X,W,V,Y,C[P+9],O,3951481745);Y=K(Y,h);X=K(X,E);W=K(W,v);V=K(V,g);} let C=Array();let P,h,E,v,g,Y,X,W,V;let S=7,Q=12,N=17,M=22;let A=5,z=9,y=14,w=20;let o=4,m=11,l=16,j=23;let U=6,T=10,R=15,O=21;s=J(s);C=e(s);Y=1732584193;X=4023233417;W=2562383102;V=271733878;for(P=0;P<C.length;P+=16){h=Y;E=X;v=W;g=V;Y=u(Y,X,W,V,C[P+0],S,3614090360);V=u(V,Y,X,W,C[P+1],Q,3905402710);W=u(W,V,Y,X,C[P+2],N,606105819);X=u(X,W,V,Y,C[P+3],M,3250441966);Y=u(Y,X,W,V,C[P+4],S,4118548399);V=u(V,Y,X,W,C[P+5],Q,1200080426);W=u(W,V,Y,X,C[P+6],N,2821735955);X=u(X,W,V,Y,C[P+7],M,4249261313);Y=u(Y,X,W,V,C[P+8],S,1770035416);V=u(V,Y,X,W,C[P+9],Q,2336552879);W=u(W,V,Y,X,C[P+10],N,4294925233);X=u(X,W,V,Y,C[P+11],M,2304563134);Y=u(Y,X,W,V,C[P+12],S,1804603682);V=u(V,Y,X,W,C[P+13],Q,4254626195);W=u(W,V,Y,X,C[P+14],N,2792965006);X=u(X,W,V,Y,C[P+15],M,1236535329);Y=f(Y,X,W,V,C[P+1],A,4129170786);V=f(V,Y,X,W,C[P+6],z,3225465664);W=f(W,V,Y,X,C[P+11],y,643717713);X=f(X,W,V,Y,C[P+0],w,3921069994);Y=f(Y,X,W,V,C[P+5],A,3593408605);V=f(V,Y,X,W,C[P+10],z,38016083);W=f(W,V,Y,X,C[P+15],y,3634488961);X=f(X,W,V,Y,C[P+4],w,3889429448);Y=f(Y,X,W,V,C[P+9],A,568446438);V=f(V,Y,X,W,C[P+14],z,3275163606);W=f(W,V,Y,X,C[P+3],y,4107603335);X=f(X,W,V,Y,C[P+8],w,1163531501);Y=f(Y,X,W,V,C[P+13],A,2850285829);V=f(V,Y,X,W,C[P+2],z,4243563512);W=f(W,V,Y,X,C[P+7],y,1735328473);X=f(X,W,V,Y,C[P+12],w,2368359562);Y=D(Y,X,W,V,C[P+5],o,4294588738);V=D(V,Y,X,W,C[P+8],m,2272392833);W=D(W,V,Y,X,C[P+11],l,1839030562);X=D(X,W,V,Y,C[P+14],j,4259657740);Y=D(Y,X,W,V,C[P+1],o,2763975236);V=D(V,Y,X,W,C[P+4],m,1272893353);W=D(W,V,Y,X,C[P+7],l,4139469664);X=D(X,W,V,Y,C[P+10],j,3200236656);Y=D(Y,X,W,V,C[P+13],o,681279174);V=D(V,Y,X,W,C[P+0],m,3936430074);W=D(W,V,Y,X,C[P+3],l,3572445317);X=D(X,W,V,Y,C[P+6],j,76029189);Y=D(Y,X,W,V,C[P+9],o,3654602809);V=D(V,Y,X,W,C[P+12],m,3873151461);W=D(W,V,Y,X,C[P+15],l,530742520);X=D(X,W,V,Y,C[P+2],j,3299628645);Y=t(Y,X,W,V,C[P+0],U,4096336452);V=t(V,Y,X,W,C[P+7],T,1126891415);W=t(W,V,Y,X,C[P+14],R,2878612391);X=t(X,W,V,Y,C[P+5],O,4237533241);Y=t(Y,X,W,V,C[P+12],U,1700485571);V=t(V,Y,X,W,C[P+3],T,2399980690);W=t(W,V,Y,X,C[P+10],R,4293915773);X=t(X,W,V,Y,C[P+1],O,2240044497);Y=t(Y,X,W,V,C[P+8],U,1873313359);V=t(V,Y,X,W,C[P+15],T,4264355552);W=t(W,V,Y,X,C[P+6],R,2734768916);X=t(X,W,V,Y,C[P+13],O,1309151649);Y=t(Y,X,W,V,C[P+4],U,4149444226);V=t(V,Y,X,W,C[P+11],T,3174756917);W=t(W,V,Y,X,C[P+2],R,718787259);X=t(X,W,V,Y,C[P+9],O,3951481745);Y=K(Y,h);X=K(X,E);W=K(W,v);V=K(V,g);}
let i=B(Y)+B(X)+B(W)+B(V);return i.toLowerCase();};let size=element.dataset["size"]||80;let email=$value.email||$value||"";let name=$value.name||$value||"";name=(typeof name!=='string')?'':name;let theme=name.split("").map(char=>char.charCodeAt(0)).reduce((a,b)=>a+b,0).toString();let themes=[{color:"27005e",background:"e1d2f6"},{color:"5e2700",background:"f3d9c6"},{color:"006128",background:"c9f3c6"},{color:"580061",background:"f2d1f5"},{color:"00365d",background:"c6e1f3"},{color:"00075c",background:"d2d5f6"},{color:"610038",background:"f5d1e6"},{color:"386100",background:"dcf1bd"},{color:"615800",background:"f1ecba"},{color:"610008",background:"f6d2d5"}];name=name.split(" ").map(function(n){if(!isNaN(parseFloat(n))&&isFinite(n)){return"";} let i=B(Y)+B(X)+B(W)+B(V);return i.toLowerCase();};let size=element.dataset["size"]||80;let email=$value.email||$value||"";let name=$value.name||$value||"";name=(typeof name!=='string')?'--':name;let def="/v1/avatars/initials?project=console"+"&name="+
return n[0];}).join("")||"--";let background=themes[theme[theme.length-1]]["background"];let color=themes[theme[theme.length-1]]["color"];let def="https://ui-avatars.com/api/"+ encodeURIComponent(name)+"&width="+
encodeURIComponent(name)+"/"+ size+"&height="+
size+"/"+ size;return def;}).add("selectedCollection",function($value,router){return $value===router.params.collectionId?"selected":"";}).add("selectedDocument",function($value,router){return $value===router.params.documentId?"selected":"";}).add("localeString",function($value){$value=parseInt($value);return!Number.isNaN($value)?$value.toLocaleString():"";}).add("date",function($value,date){return date.format("Y-m-d",$value);}).add("date-time",function($value,date){return date.format("Y-m-d H:i",$value);}).add("date-text",function($value,date){return date.format("d M Y",$value);}).add("ms2hum",function($value){let temp=$value;const years=Math.floor(temp/31536000),days=Math.floor((temp%=31536000)/86400),hours=Math.floor((temp%=86400)/3600),minutes=Math.floor((temp%=3600)/60),seconds=temp%60;if(days||hours||seconds||minutes){return((years?years+"y ":"")+
encodeURIComponent(background)+"/"+
encodeURIComponent(color);return("//www.gravatar.com/avatar/"+
MD5(email)+".jpg?s="+
size+"&d="+
encodeURIComponent(def));}).add("selectedCollection",function($value,router){return $value===router.params.collectionId?"selected":"";}).add("selectedDocument",function($value,router){return $value===router.params.documentId?"selected":"";}).add("localeString",function($value){$value=parseInt($value);return!Number.isNaN($value)?$value.toLocaleString():"";}).add("date",function($value,date){return date.format("Y-m-d",$value);}).add("date-time",function($value,date){return date.format("Y-m-d H:i",$value);}).add("date-text",function($value,date){return date.format("d M Y",$value);}).add("ms2hum",function($value){let temp=$value;const years=Math.floor(temp/31536000),days=Math.floor((temp%=31536000)/86400),hours=Math.floor((temp%=86400)/3600),minutes=Math.floor((temp%=3600)/60),seconds=temp%60;if(days||hours||seconds||minutes){return((years?years+"y ":"")+
(days?days+"d ":"")+ (days?days+"d ":"")+
(hours?hours+"h ":"")+ (hours?hours+"h ":"")+
(minutes?minutes+"m ":"")+ (minutes?minutes+"m ":"")+

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View file

@ -3,7 +3,7 @@ window.ls.filter
if (!$value) { if (!$value) {
return ""; return "";
} }
// MD5 (Message-Digest Algorithm) by WebToolkit // MD5 (Message-Digest Algorithm) by WebToolkit
let MD5 = function(s) { let MD5 = function(s) {
function L(k, d) { function L(k, d) {
@ -216,59 +216,68 @@ window.ls.filter
let email = $value.email || $value || ""; let email = $value.email || $value || "";
let name = $value.name || $value || ""; let name = $value.name || $value || "";
name = (typeof name !== 'string') ? '' : name; name = (typeof name !== 'string') ? '--' : name;
let theme = name // let theme = name
.split("") // .split("")
.map(char => char.charCodeAt(0)) // .map(char => char.charCodeAt(0))
.reduce((a, b) => a + b, 0) // .reduce((a, b) => a + b, 0)
.toString(); // .toString();
let themes = [ // let themes = [
{ color: "27005e", background: "e1d2f6" }, // VIOLET // { color: "27005e", background: "e1d2f6" }, // VIOLET
{ color: "5e2700", background: "f3d9c6" }, // ORANGE // { color: "5e2700", background: "f3d9c6" }, // ORANGE
{ color: "006128", background: "c9f3c6" }, // GREEN // { color: "006128", background: "c9f3c6" }, // GREEN
{ color: "580061", background: "f2d1f5" }, // FUSCHIA // { color: "580061", background: "f2d1f5" }, // FUSCHIA
{ color: "00365d", background: "c6e1f3" }, // BLUE // { color: "00365d", background: "c6e1f3" }, // BLUE
{ color: "00075c", background: "d2d5f6" }, // INDIGO // { color: "00075c", background: "d2d5f6" }, // INDIGO
{ color: "610038", background: "f5d1e6" }, // PINK // { color: "610038", background: "f5d1e6" }, // PINK
{ color: "386100", background: "dcf1bd" }, // LIME // { color: "386100", background: "dcf1bd" }, // LIME
{ color: "615800", background: "f1ecba" }, // YELLOW // { color: "615800", background: "f1ecba" }, // YELLOW
{ color: "610008", background: "f6d2d5" } // RED // { color: "610008", background: "f6d2d5" } // RED
]; // ];
name = // name =
name // name
.split(" ") // .split(" ")
.map(function(n) { // .map(function(n) {
if (!isNaN(parseFloat(n)) && isFinite(n)) { // if (!isNaN(parseFloat(n)) && isFinite(n)) {
return ""; // return "";
} // }
return n[0]; // return n[0];
}) // })
.join("") || "--"; // .join("") || "--";
let background = themes[theme[theme.length - 1]]["background"]; // let background = themes[theme[theme.length - 1]]["background"];
let color = themes[theme[theme.length - 1]]["color"]; // let color = themes[theme[theme.length - 1]]["color"];
let def = let def =
"https://ui-avatars.com/api/" + "/v1/avatars/initials?project=console"+
"&name=" +
encodeURIComponent(name) + encodeURIComponent(name) +
"/" + "&width=" +
size + size +
"/" + "&height=" +
encodeURIComponent(background) + size;
"/" +
encodeURIComponent(color);
return ( return def;
"//www.gravatar.com/avatar/" + // let def =
MD5(email) + // "https://ui-avatars.com/api/" +
".jpg?s=" + // encodeURIComponent(name) +
size + // "/" +
"&d=" + // size +
encodeURIComponent(def) // "/" +
); // encodeURIComponent(background) +
// "/" +
// encodeURIComponent(color);
// return (
// "//www.gravatar.com/avatar/" +
// MD5(email) +
// ".jpg?s=" +
// size +
// "&d=" +
// encodeURIComponent(def)
// );
}) })
.add("selectedCollection", function($value, router) { .add("selectedCollection", function($value, router) {
return $value === router.params.collectionId ? "selected" : ""; return $value === router.params.collectionId ? "selected" : "";

View file

@ -9,6 +9,9 @@
case 'integer': case 'integer':
value = parseInt(value); value = parseInt(value);
break; break;
case 'numeric':
value = Number(value);
break;
case 'string': case 'string':
value = value.toString(); value = value.toString();
break; break;

View file

@ -334,9 +334,6 @@ a.box {
} }
a.box:hover { a.box:hover {
border-bottom: none;
border-right: none;
border-left: none;
box-shadow: 0 0 1px rgba(0, 0, 0, .2); box-shadow: 0 0 1px rgba(0, 0, 0, .2);
opacity: .7; opacity: .7;
} }
@ -362,4 +359,4 @@ a.box:hover {
bottom: 0; bottom: 0;
.func-start(-6px); .func-start(-6px);
} }
} }

View file

@ -16,10 +16,6 @@ header {
margin: 7px 0; margin: 7px 0;
display: block; display: block;
&:hover {
border-bottom: none;
}
img { img {
display: block; display: block;
} }
@ -35,10 +31,6 @@ header {
.account { .account {
.func-margin-start(25px); .func-margin-start(25px);
&:hover {
border-bottom: none;
}
} }
.avatar { .avatar {
@ -113,4 +105,4 @@ header {
} }
} }
} }
} }

View file

@ -14,6 +14,8 @@ https://prismjs.com/download.html#themes=prism-okaidia&languages=markup+css+clik
box-shadow: 0 2px 4px 0 rgba(50,50,93,.3); box-shadow: 0 2px 4px 0 rgba(50,50,93,.3);
border-radius: 10px; border-radius: 10px;
margin-bottom: 30px; margin-bottom: 30px;
&:extend(.force-left);
&:extend(.force-ltr);
* { * {
font-family: 'Source Code Pro', monospace; font-family: 'Source Code Pro', monospace;

View file

@ -36,7 +36,6 @@ button,
&:hover, &:hover,
&:focus { &:focus {
background: var(--config-color-focus-hover); background: var(--config-color-focus-hover);
border-bottom: none;
} }
&.fly { &.fly {
@ -175,10 +174,6 @@ button,
padding: 0; padding: 0;
.func-padding-end(0) !important; .func-padding-end(0) !important;
&:hover {
border-bottom: dotted 1px var(--config-color-link);
}
&:focus { &:focus {
box-shadow: inherit; box-shadow: inherit;
} }
@ -1300,4 +1295,4 @@ ol {
.pull-start; .pull-start;
} }
} }
} }

View file

@ -130,10 +130,6 @@
.account { .account {
.func-margin-start(25px); .func-margin-start(25px);
.text-one-liner; .text-one-liner;
&:hover {
border-bottom: none;
}
} }
.switch-theme { .switch-theme {
@ -189,11 +185,6 @@
height: 39px; height: 39px;
padding: 15px 20px; padding: 15px 20px;
display: block; display: block;
border-bottom: none;
&:hover {
border-bottom: none;
}
img { img {
display: inline-block; display: inline-block;
@ -364,7 +355,6 @@
&:hover, &:hover,
&.selected { &.selected {
color: #e4e4e4; color: #e4e4e4;
font-weight: 500;
} }
} }
} }
@ -548,6 +538,7 @@
@media @tablets, @phones { @media @tablets, @phones {
width: 100%; width: 100%;
padding-bottom: 32%;
float: none; float: none;
margin-bottom: 20px; margin-bottom: 20px;
} }

View file

@ -7,11 +7,9 @@ html.home {
.logo { .logo {
a { a {
display: block; display: block;
border-bottom: none;
&:hover { &:hover {
opacity: .8; opacity: .8;
border-bottom: none;
} }
} }
@ -30,4 +28,4 @@ html.home {
main { main {
min-height: 400px; min-height: 400px;
} }
} }

View file

@ -17,11 +17,12 @@ a, .link {
text-decoration: none; text-decoration: none;
border-left: 2px solid transparent; border-left: 2px solid transparent;
border-right: 2px solid transparent; border-right: 2px solid transparent;
border-bottom: solid 1px transparent; transition: 200ms;
display: inline-block;
cursor: pointer;
&:hover { &:hover {
border-bottom: dotted 1px var(--config-color-link); transform: translateY(-2px);
cursor: pointer;
} }
&.disabled { &.disabled {
@ -29,11 +30,11 @@ a, .link {
} }
&.disabled:hover { &.disabled:hover {
border-bottom: none; .link.link-animation-disabled();
} }
&.tag:hover { &.tag:hover {
border-bottom: none; .link.link-animation-disabled();
opacity: .9; opacity: .9;
} }
@ -42,6 +43,46 @@ a, .link {
} }
} }
a.link-animation-disabled,
.link.link-animation-disabled {
&:hover {
transform: translateY(0);
}
}
.func-link-return-animation(@pos) {
.link.link-animation-disabled();
& > i {
display: inline-block;
transition: 200ms;
}
&:hover > i {
transform: translateX(@pos);
}
}
@link-return-animation-offset: 2px;
.link-return-animation--start {
.func-link-return-animation(
if((@config-start = right),
@link-return-animation-offset,
-@link-return-animation-offset
)
);
}
.link-return-animation--end {
.func-link-return-animation(
if((@config-start = right),
-@link-return-animation-offset,
@link-return-animation-offset
)
);
}
b, strong { b, strong {
font-weight: 500; font-weight: 500;
} }
@ -196,4 +237,12 @@ small {
.icon-dot-3:before { .icon-dot-3:before {
.func-rotate(90deg); .func-rotate(90deg);
} }
// fix icons vertical alignment
i[class^='icon-'], i[class*=' icon-']{
&:before {
display: inline;
line-height: unset;
}
}

View file

@ -411,4 +411,95 @@ trait AvatarsBase
return []; return [];
} }
public function testGetInitials()
{
/**
* Test for SUCCESS
*/
$response = $this->client->call(Client::METHOD_GET, '/avatars/initials', [
'x-appwrite-project' => $this->getProject()['$id'],
]);
$this->assertEquals(200, $response['headers']['status-code']);
$this->assertEquals('image/png; charset=UTF-8', $response['headers']['content-type']);
$this->assertNotEmpty($response['body']);
$response = $this->client->call(Client::METHOD_GET, '/avatars/initials', [
'x-appwrite-project' => $this->getProject()['$id'],
], [
'width' => 200,
'height' => 200,
]);
$this->assertEquals(200, $response['headers']['status-code']);
$this->assertEquals('image/png; charset=UTF-8', $response['headers']['content-type']);
$this->assertNotEmpty($response['body']);
$response = $this->client->call(Client::METHOD_GET, '/avatars/initials', [
'x-appwrite-project' => $this->getProject()['$id'],
], [
'name' => 'W W',
'width' => 200,
'height' => 200,
]);
$this->assertEquals(200, $response['headers']['status-code']);
$this->assertEquals('image/png; charset=UTF-8', $response['headers']['content-type']);
$this->assertNotEmpty($response['body']);
$response = $this->client->call(Client::METHOD_GET, '/avatars/initials', [
'x-appwrite-project' => $this->getProject()['$id'],
], [
'name' => 'W W',
'width' => 200,
'height' => 200,
'color' => 'ffffff',
'background' => '000000',
]);
$this->assertEquals(200, $response['headers']['status-code']);
$this->assertEquals('image/png; charset=UTF-8', $response['headers']['content-type']);
$this->assertNotEmpty($response['body']);
/**
* Test for FAILURE
*/
$response = $this->client->call(Client::METHOD_GET, '/avatars/initials', [
'x-appwrite-project' => $this->getProject()['$id'],
], [
'name' => 'W W',
'width' => 200000,
'height' => 200,
'color' => 'ffffff',
'background' => '000000',
]);
$this->assertEquals(400, $response['headers']['status-code']);
$response = $this->client->call(Client::METHOD_GET, '/avatars/initials', [
'x-appwrite-project' => $this->getProject()['$id'],
], [
'name' => 'W W',
'width' => 200,
'height' => 200,
'color' => 'white',
'background' => '000000',
]);
$this->assertEquals(400, $response['headers']['status-code']);
$response = $this->client->call(Client::METHOD_GET, '/avatars/initials', [
'x-appwrite-project' => $this->getProject()['$id'],
], [
'name' => 'W W',
'width' => 200,
'height' => 200,
'color' => 'ffffff',
'background' => 'black',
]);
$this->assertEquals(400, $response['headers']['status-code']);
}
} }