This generator creates a cohesive 15-color design system based on HSL (Hue, Saturation, Lightness) mathematics. It ensures visual harmony by shifting all three axes simultaneously.
1. The Core Palette (100 – 500)
The main 5-color scale is your primary toolkit for any web project:
Color 100 (Lightest): Best for Section Backgrounds or Disabled Button states. Very subtle and airy.
Color 200 (Soft): Perfect for Card Backgrounds, Dividers, or Secondary Buttons.
Color 300 (Base): Your Primary Brand Color. Use this for Main Actions, Active Links, and Icons.
Color 400 (Deep): Great for Hover States on primary buttons or Subheadings.
Color 500 (Darkest): High contrast. Ideal for Main Text, Deep Borders, or Dark Mode Accents.
2. Tints & Shades (XX1 – XX9)
These are “micro-adjustments” for complex UI components like inputs or layered cards:
Tints (XX1): Derived by adding +15% Lightness. Excellent for Tooltip backgrounds or Success/Info notifications.
Shades (XX9): Derived by subtracting 15% Lightness. Use these for Inner Shadows or Pressed (Active) button states.
3. Why HSL?
Unlike HEX, HSL allows you to maintain the “energy” of a color while changing its brightness. The 8° Hue Shift applied here prevents colors from looking “muddy” or “greyish” when darkened, mimicking how real-world shadows work.
Pro Tip: Use the .gpl export to import this palette into Inkscape or GIMP to keep your design mockups and code perfectly in sync!
Трябва ми лек сървар с който да управлявам едн компютър, който ползвам за нещо като локален NAS. Apache тотално не ми се вписва в сметките, защото напоследък брах ядове с пълното му деинсталиране от системата. Затова се спрях на конкурента му nginx. По-долу поствам някои интересни моменти от тестовете, които направих под Windows. За да мога да достъпвам сървара в локална мрежа, трябваше да променя настройките на Firewall-а на Windows 10. В моя случай промених настройки на firewall на Nod32, който е асоцииран по подразбиране в firewall-a на Win.
Изтеглих Mainline version на nginx от тук: nginx download
Разархивирах го в една директория и му промених conf/nginx.conf така, че да отговаря на моите нужди. Важно е да се отбележи, че предварително имам инсталиран PHP 7.2, който е добавен в променливите на обкръжението на Win10.
казва на сървара първо да потърси файл, след това директория и най-накрая ако не намери предните две да потърси index.php, като всичко след името на домейна го постави като аргумент. Примерно: https://localhost/system-info ще се преобразува в: https://localhost/index.php?/system-info По този начин мога да ползвам френдли адресиране, вместо да изписвам остарелите GET променливи. В Apache се ползва .htaccess за тая цел. Но в nginx тези инструкции се поместват в основния кофигурационен файл.
За да спирам и пускам сървара използвах batch код, който намерих някъде в мрежата. Коментирал съм с REM кодове в скрипта, които могат да са полезни след време, но които не са ми необходими, като спиране и пускане на MySQL. Напоследък за леки проекти ползвам основно SQLite с RedBeanPHP като ORM:
@echo off
REM cd C:\WebServer\nginx
IF "%1" == "stop" (
GOTO STOPSERVER
)else IF "%1" == "start" (
GOTO STARTSERVER
)else (
echo Use these commands:
echo.
echo myserver start
echo myserver stop
)
GOTO END
:STARTSERVER
REM QPROCESS * | find /I /N "mysqld.exe">NUL
REM IF "%ERRORLEVEL%"=="0" (
REM echo MYSQLD is already running.
REM )else (
REM RunHiddenConsole.exe mysqld --console
REM echo MYSQLD is now running.
REM )
QPROCESS * | find /I /N "nginx.exe">NUL
IF "%ERRORLEVEL%"=="0" (
echo NGINX is already running.
)else (
RunHiddenConsole.exe nginx
echo NGINX is now running.
)
QPROCESS * | find /I /N "php-cgi.exe">NUL
IF "%ERRORLEVEL%"=="0" (
echo PHP-CGI is already running.
)else (
RunHiddenConsole.exe php-cgi -b 127.0.0.1:9000
echo PHP-CGI is now running.
)
echo.
echo To stop, type "myserver stop"
GOTO END
:STOPSERVER
REM QPROCESS * | find /I /N "mysqld.exe">NUL
REM IF "%ERRORLEVEL%"=="0" (
REM taskkill /F /IM mysqld.exe>NUL
REM echo MYSQLD ended successfully.
REM )else (
REM echo MYSQLD is not running
REM )
QPROCESS * | find /I /N "nginx.exe">NUL
IF "%ERRORLEVEL%"=="0" (
::nginx -s stop
taskkill /F /IM nginx.exe>NUL
echo NGINX ended successfully.
)else (
echo NGINX is not running
)
QPROCESS * | find /I /N "php-cgi.exe">NUL
IF "%ERRORLEVEL%"=="0" (
taskkill /F /IM php-cgi.exe>NUL
echo PHP-CGI ended successfully.
)else (
echo PHP-CGI is not running
)
:END
Запазих по-горния код в директорията с exe-то на nginx в файла myserver.bat. Пускане и спиране на сървара става с командите:
myserver start
myserver stop
За файлов фмениджър на NAS-чето за сега съм се спрял на Tiny File Manager. Този файлов мениджър е поместен само в един файл и има достатъчно опции за редактиране, които са ми напълно достатъчни.
Ще се опитам да опиша простичко, как се разработва прост extension add-on за Chrome. Понякога е много полезно да се работи с подобни скриптове, особено при скрапване на web-съдържание, когато конвенционалните методи не работят или изискват прекалено много усилия.
За да се създаде подобен скрипт с потребителски интерфейс ще са ни необходими няколко файла: manifest.json – всяка добавка (extension) за Chrome (а и за другите браузери) съдържа подобен скрипт, който предоставя важна информация на браузера. Повече тук: Manifest File Format popup.html – стандартно наименование на файла с потребителския интерфейс, който се появява при клик с мишката върху добавката. Разбира се, можем да създадем добавка, която няма нужда от потребителски интерфейс, но в случая аз искам да имам. Името на този файл се посочва в manifest.json. popup.js – файл, който се зарежда чрез popup.html. Можем и да нямаме подобен файл и да поместим javascript кода направо в popup.html. Но тенденциите в модерното програмиране съветват да се диференцира всичко – стилове, скриптове, html. В моя случай popup.js е двигателя на Chrome добавката. Той посочва какво, кога и къде да се активира. getPagesSource.js – файл за инжектиране в web-страницата и извлича информацията от нея. Този файл се зарежда от popup.js. icon.png – някаква иконка, която да се показва в листата с добавките на Chrome.
Нека създадем скрипт, който извлиза съдържанието на определени тагове, като използваме javascript функцията querySelectorAll(). Много приятна функция, която заменя в известна степен нуждата от XPath при web-скрапинга.
Да започваме! Първо създаваме manifest.json, като описваме какво прави тая добавка:
1
2
3
4
5
6
7
8
9
10
11
{
"name": "Simple web scraper",
"version": "1.0",
"manifest_version": 2,
"description": "Get content from tags through querySelector",
"browser_action": {
"default_icon": "icon.png",
"default_popup": "popup.html"
},
"permissions": ["tabs", "<all_urls>"]
}
{
"name": "Simple web scraper",
"version": "1.0",
"manifest_version": 2,
"description": "Get content from tags through querySelector",
"browser_action": {
"default_icon": "icon.png",
"default_popup": "popup.html"
},
"permissions": ["tabs", "<all_urls>"]
}
След това си правим потребителския интерфейс popup.html – бутончета, поленца, форми, стилове, каквото ни е кеф. В случая ще се огранича на минимума за моите нужди – текстово поле, бутон, слой за резултата:
chrome.runtime.onMessage.addListener(function(request, sender){
selElements(document, request.customSelector);});function selElements(document_root, s){// Tova go dobaviam zaradi kefa da polzvam foreach() v JavaScriptvar forEach =function(array, callback, scope){for(var i =0; i < array.length; i++){
callback.call(scope, i, array[i]);}};var myNodeList = document.querySelectorAll(s);var concatenateall ='';
forEach(myNodeList,function(index, value){
concatenateall = concatenateall + value.innerHTML+"<hr />";});// return concatenateall;
chrome.runtime.sendMessage({
action:"getSlectedContent",
source: concatenateall
});}
chrome.runtime.onMessage.addListener(function(request, sender) {
selElements(document, request.customSelector);
});
function selElements(document_root, s){
// Tova go dobaviam zaradi kefa da polzvam foreach() v JavaScript
var forEach = function (array, callback, scope) {
for (var i = 0; i < array.length; i++) {
callback.call(scope, i, array[i]);
}
};
var myNodeList = document.querySelectorAll(s);
var concatenateall = '';
forEach(myNodeList, function (index, value) {
concatenateall = concatenateall + value.innerHTML + "<hr />";
});
// return concatenateall;
chrome.runtime.sendMessage({
action: "getSlectedContent",
source: concatenateall
});
}
Това е.
Сега остава да заредим добавката в Chrome. Това става като отворим More Tools -> Extensions. След това кликаме на бутона Load unpacked и избираме директорията с файловете на нашата добавка.
На базата на тази добавка могат да се направят много други, тъй като съдържа базата за писане на добавки за Chrome.
Bootstrap и tinyMCE са ми редовна комбинация. И за да не откривам топлата вода всеки път, ще постна малко подсетки с прост мой плъгин за tinyMCE.
Важно е да се промени javascript променливата current_host. Demo Download
В програмирането има едно правило, което перефразирано гласи да не търсиш топлата вода всеки път. За това качвам няколко базови кода за Bootstrap 3, които съм писал или копирал и променял. Помогнал съм си леко с Less за някои стилове.
Custom menu
Нищо ново. Добавено е само малко CSS-кодиране на менюто, което се предлага стандартно с Bootstrap.
От известно време се каня да променя логин формата за админ панела на проектите, които правя. Направих една форма, която не знам дали ще ползвам, но ще ми е полезна като отправна точка. За да си помогна за стиловете използвах Less (език за стилови множества или CSS) и GUI-то SimpLESS – портабъл е и работи доста леко за разлика от други подобни.
Търсих си неразкрасена логин форма за Bootstrap 3. Трябваше да я набутам в бутон на на nav-панела. Не намерих нищо свястно, ам тя работата е елементарна. Ще покажа 2 различни примера. BS3 Login form с popover и html код разположен някъде в страницата:
Javascript – поставя се най-долу в кода на страницата
1
2
3
4
5
6
7
$('button[data-toggle=popover]').popover({
html :true,//trigger: "click", // може да се смени
content:function(){return $('#popover_content_wrapper').html();}});
$('button[data-toggle=popover]').popover({
html : true,
//trigger: "click", // може да се смени
content: function() {
return $('#popover_content_wrapper').html();
}
});
CSS разполага с няколко “странни” символа, които в други езици са известни като wildcards. Тези символи представляват селектори на текст и могат да съвпадат с части от текста.
[att^=val] – започва с “val”
[att$=val] – завършва с “val”
[att*=val] – съдържа “val”
Атрибут селекторите могат да се използват за всякакви атрибути на таговете, като класове (.class1, class2…) или идентификатори(#id1, id2…), href, title, name и т.н.
Прост, базов RTF редактор за сайт
Дълго съм се чудил кой е най-подходящия JavaScript Wysiwyg редактор с най-много възможности за напасване към сайт. Ползвал съм NicEdit, TinyMCE и други, които сам съм писал, неподдържащи rich text format (RTF). Обаче напасването на тези редактори към различни дизайни е развибащо от към бачкане и тестване в различните браузери. Реших да почопля няколко такива редактора и да разбера кое е толкова загадъчно и сложно, за да се напише подобен редактор. Истината е тривиална и се казва – iFrame. Този таг се ползва в почти всички подобни редактори, точно заради поддръжката му на RTF. При събмитване на формата, цялото съдържание на iform се подава на textarea, който си седи удобно скрит.
Това е моят редактор, без CSS-форматиране, като в примера добавям и опция за обработка на текста от базата данни, където присъства без тагове, с ексейпнати малко по-рискови символи.
<?php$field='<a href="aloooha">Test\'ed. kavicha</a> dyra, byra.<br />Още текст и още "кирилица".';$clearpost=$field;if(isset($_POST['button'])){echo$_POST['myTextArea'];$clearpost=$_POST['myTextArea'];}//$clearpost = preg_replace('@delete|select|insert|update|where@i',"", $clearpost); // Почистване на //$clearpost = preg_replace('/[\x7f-\xff]/', "", $clearpost); // Clear Dirty Data$clearpost=preg_replace("/;/",";",$clearpost);$clearpost=preg_replace("/\*/","*",$clearpost);$clearpost=preg_replace("/\r\n/","<br />",$clearpost);$clearpost=preg_replace("/\r/","<br />",$clearpost);$clearpost=preg_replace("/\n/","<br />",$clearpost);$clearpost=preg_replace("/</","<",$clearpost);$clearpost=preg_replace("/=/","=",$clearpost);$clearpost=preg_replace("/>/",">",$clearpost);$clearpost=preg_replace("/\'/","'",$clearpost);$clearpost=preg_replace("/\`/","`",$clearpost);$clearpost=preg_replace("/\"/",""",$clearpost);if(!get_magic_quotes_gpc())$clearpost=preg_replace('@\\\@',"\",$clearpost);else{$clearpost=stripslashes($clearpost);$clearpost=preg_replace('@\\\@',"\",$clearpost);}$clearpost=preg_replace("/'/","\'",$clearpost);// Ескейпване на единичната кавичка, за да може да се показва в iframe!!!?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<meta http-equiv="content-type" content="text/html; charset=windows-1251" />
<script src="wiswyg_ned/nedEditor.js"></script>
<script type="text/javascript">
window.onload=function(){
iFrameOn();
if(isIE){
var myFrame = document.getElementById('richTextField');
var frameDoc = myFrame.contentDocument || myFrame.contentWindow;
if (frameDoc.document){
frameDoc = frameDoc.document;
}
frameDoc.write ('<?phpechohtml_entity_decode($clearpost,ENT_QUOTES);?>') ;
} else {
window.frames['richTextField'].document.body.innerHTML = '<?phpechohtml_entity_decode($clearpost,ENT_QUOTES);?>' ;
}
}
</script>
</head>
<!-- <body onLoad="iFrameOn();" > -->
<body>
<form action="" enctype="multipart/form-data" name="myForm" id="myform" method="post">
<div id="wysiwyg_cp" style="padding:8px; width:700px;">
<input type="button" onClick="iBold()" value="B">
<input type="button" onClick="iUnderline()" value="U">
<input type="button" onClick="iItalic()" value="I">
<input type="button" onClick="iFontSize()" value="Text Size">
<input type="button" onClick="iForeColor()" value="Text Color">
<input type="button" onClick="iHorizontalRule()" value="HR">
<input type="button" onClick="iUnorderedList()" value="UL"><br />
<input type="button" onClick="iOrderedList()" value="OL">
<input type="button" onClick="iLink()" value="Link">
<input type="button" onClick="iUnLink()" value="UnLink">
<input type="button" onClick="iImage()" value="Image">
<input type="button" onClick="iRemoveFormat()" value="Remove Format">
</div>
<!-- Hide(but keep)your normal textarea and place in the iFrame replacement for it -->
<textarea style="display:none;" name="myTextArea" id="myTextArea" cols="100" rows="14"></textarea>
<iframe name="richTextField" id="richTextField" ></iframe>
<br />
<input type="submit" name="button" id="button" value="Make Changes" onClick="javascript:submit_form();"/>
</form>
</body>
</html>
// Check Browservar isOpera =!!(window.opera&& window.opera.version);// Opera 8.0+var isFirefox = testCSS('MozBoxSizing');// FF 0.8+var isSafari =Object.prototype.toString.call(window.HTMLElement).indexOf('Constructor')>0;// At least Safari 3+: "[object HTMLElementConstructor]"var isChrome =!isSafari && testCSS('WebkitTransform');// Chrome 1+var isIE =/*@cc_on!@*/false|| testCSS('msTransform');// At least IE6function testCSS(prop){return prop in document.documentElement.style;}//====================function iFrameOn(){
richTextField.document.designMode='On';//window.frames['richTextField'].document.body.innerHTML = '<a href="aloooha">Aloha</a> dyra, byra.<br />Още текст има тук.'; }function iRemoveFormat(){
richTextField.document.execCommand('removeformat',false,null);}function iBold(){
richTextField.document.execCommand('bold',false,null);}function iUnderline(){
richTextField.document.execCommand('underline',false,null);}function iItalic(){
richTextField.document.execCommand('italic',false,null);}function iFontSize(){var size = prompt('Enter a size 1 - 7','');
richTextField.document.execCommand('FontSize',false,size);}function iForeColor(){var color = prompt('Define a basic color or apply a hexadecimal color code for advanced colors:','');
richTextField.document.execCommand('ForeColor',false,color);}function iHorizontalRule(){
richTextField.document.execCommand('inserthorizontalrule',false,null);}function iUnorderedList(){
richTextField.document.execCommand("InsertOrderedList",false,"newOL");}function iOrderedList(){
richTextField.document.execCommand("InsertUnorderedList",false,"newUL");}function iLink(){var linkURL = prompt("Enter the URL for this link:","http://");
richTextField.document.execCommand("CreateLink",false, linkURL);}function iUnLink(){
richTextField.document.execCommand("Unlink",false,null);}function iImage(){var imgSrc = prompt('Enter image location','');if(imgSrc !=null){
richTextField.document.execCommand('insertimage',false, imgSrc);}}function submit_form(){var theForm = document.getElementById("myform");
theForm.elements["myTextArea"].value= window.frames['richTextField'].document.body.innerHTML;
theForm.submit();}
// Check Browser
var isOpera = !!(window.opera && window.opera.version); // Opera 8.0+
var isFirefox = testCSS('MozBoxSizing'); // FF 0.8+
var isSafari = Object.prototype.toString.call(window.HTMLElement).indexOf('Constructor') > 0;
// At least Safari 3+: "[object HTMLElementConstructor]"
var isChrome = !isSafari && testCSS('WebkitTransform'); // Chrome 1+
var isIE = /*@cc_on!@*/false || testCSS('msTransform'); // At least IE6
function testCSS(prop) {
return prop in document.documentElement.style;
}
//====================
function iFrameOn(){
richTextField.document.designMode = 'On';
//window.frames['richTextField'].document.body.innerHTML = '<a href="aloooha">Aloha</a> dyra, byra.<br />Още текст има тук.';
}
function iRemoveFormat(){
richTextField.document.execCommand('removeformat',false,null);
}
function iBold(){
richTextField.document.execCommand('bold',false,null);
}
function iUnderline(){
richTextField.document.execCommand('underline',false,null);
}
function iItalic(){
richTextField.document.execCommand('italic',false,null);
}
function iFontSize(){
var size = prompt('Enter a size 1 - 7', '');
richTextField.document.execCommand('FontSize',false,size);
}
function iForeColor(){
var color = prompt('Define a basic color or apply a hexadecimal color code for advanced colors:', '');
richTextField.document.execCommand('ForeColor',false,color);
}
function iHorizontalRule(){
richTextField.document.execCommand('inserthorizontalrule',false,null);
}
function iUnorderedList(){
richTextField.document.execCommand("InsertOrderedList", false,"newOL");
}
function iOrderedList(){
richTextField.document.execCommand("InsertUnorderedList", false,"newUL");
}
function iLink(){
var linkURL = prompt("Enter the URL for this link:", "http://");
richTextField.document.execCommand("CreateLink", false, linkURL);
}
function iUnLink(){
richTextField.document.execCommand("Unlink", false, null);
}
function iImage(){
var imgSrc = prompt('Enter image location', '');
if(imgSrc != null){
richTextField.document.execCommand('insertimage', false, imgSrc);
}
}
function submit_form(){
var theForm = document.getElementById("myform");
theForm.elements["myTextArea"].value = window.frames['richTextField'].document.body.innerHTML;
theForm.submit();
}
This website uses cookies to improve your experience. We'll assume you're ok with this, but you can opt-out if you wish.AcceptRead More
Privacy & Cookies Policy
Privacy Overview
This website uses cookies to improve your experience while you navigate through the website. Out of these, the cookies that are categorized as necessary are stored on your browser as they are essential for the working of basic functionalities of the website. We also use third-party cookies that help us analyze and understand how you use this website. These cookies will be stored in your browser only with your consent. You also have the option to opt-out of these cookies. But opting out of some of these cookies may affect your browsing experience.
Necessary cookies are absolutely essential for the website to function properly. This category only includes cookies that ensures basic functionalities and security features of the website. These cookies do not store any personal information.
Any cookies that may not be particularly necessary for the website to function and is used specifically to collect user personal data via analytics, ads, other embedded contents are termed as non-necessary cookies. It is mandatory to procure user consent prior to running these cookies on your website.