diff --git a/composer.json b/composer.json index 51af502..b0e617d 100644 --- a/composer.json +++ b/composer.json @@ -2,11 +2,10 @@ "name": "picocms/pico-composer", "type": "project", "description": "Pico is a flat file CMS, this means there is no administration backend and database to deal with. You simply create .md files in the \"content\" folder and that becomes a page.", - "keywords": [ "pico", "picocms", "pico-cms", "simple", "flat-file", "cms", "content-management", "website", "markdown-to-html", "php", "markdown", "yaml", "twig", "composer-project" ], + "keywords": ["pico", "picocms", "pico-cms", "simple", "flat-file", "cms", "content-management", "website", "markdown-to-html", "php", "markdown", "yaml", "twig", "composer-project"], "homepage": "http://picocms.org/", "license": "MIT", - "authors": [ - { + "authors": [{ "name": "Daniel Rudolf", "email": "picocms.org@daniel-rudolf.de", "role": "Lead Developer" @@ -34,4 +33,4 @@ }, "minimum-stability": "beta", "prefer-stable": true -} +} \ No newline at end of file diff --git a/content/blog/2020/20200121.hallo-welt.md b/content/blog/2020/20200121.hallo-welt.md index dc1d738..bc97ddb 100644 --- a/content/blog/2020/20200121.hallo-welt.md +++ b/content/blog/2020/20200121.hallo-welt.md @@ -5,7 +5,7 @@ Author: Christian Seyfferth Date: 2020-01-21 17:00 Robots: noindex,nofollow Template: templates/blog/item -image: %assets_url%/logo.svg +image: %theme_url%/img/logo.svg image_alt: Logo der Website category: Test --- diff --git a/content/config/index.md b/content/config/index.md new file mode 100644 index 0000000..3e06568 --- /dev/null +++ b/content/config/index.md @@ -0,0 +1,12 @@ +--- +Title: Konfiguration +Description: Konfigurationsseite +Author: Christian Seyfferth +Date: 2020-01-21 +Robots: noindex,nofollow +Template: templates/index +--- + +# Kontakt-Konfiguration + +(% contact_admin_config %) \ No newline at end of file diff --git a/content/index.md b/content/index.md index 46b503f..4e673c5 100644 --- a/content/index.md +++ b/content/index.md @@ -13,4 +13,14 @@ Willkommen auf meiner Seite. Ich hoffe sie gefällt dir. Sieh dich in Ruhe um, zum Beispiel was ich so zuletzt geschrieben habe, oder an was ich gerade arbeite. -Wenn du dir verloren vorkommst oder einfach nur etwas loswerden möchtest, bekommst du hier die Möglichkeit. \ No newline at end of file +Wenn du dir verloren vorkommst oder einfach nur etwas loswerden möchtest, bekommst du hier die Möglichkeit. + +(% contact de : + subject => Kontaktanfrage, + radio "Ich möchte eine Anfrage stellen zu" = einer App | der Webseite |: irgendwas anderes, + select "Ministerium" = Silly walks :| Strange Things, + email!, + message =< Meine Nachricht an dich, + checkbox! Ich weiß was ich tue, + askcopy +%) diff --git a/index.php b/index.php index f80fdca..c6df000 100644 --- a/index.php +++ b/index.php @@ -1,8 +1,10 @@ - * @@ -12,13 +14,13 @@ // load dependencies // pico-composer MUST be installed as root package -if (is_file(__DIR__ . '/vendor/autoload.php')) { - require_once(__DIR__ . '/vendor/autoload.php'); +if (is_file(__DIR__.'/vendor/autoload.php')) { + require_once __DIR__.'/vendor/autoload.php'; } else { die("Cannot find 'vendor/autoload.php'. Run `composer install`."); } -setlocale(LC_ALL, "de_DE@euro", 'de_DE', 'deu_deu'); +setlocale(LC_ALL, 'de_DE@euro', 'de_DE', 'deu_deu'); // instance Pico $pico = new Pico( diff --git a/plugins/PicoContact/.htaccess b/plugins/PicoContact/.htaccess new file mode 100644 index 0000000..60476d3 --- /dev/null +++ b/plugins/PicoContact/.htaccess @@ -0,0 +1,6 @@ +Order deny,allow +Deny from all + + + Allow from all + diff --git a/plugins/PicoContact/PicoContact.php b/plugins/PicoContact/PicoContact.php new file mode 100644 index 0000000..4fb7dd3 --- /dev/null +++ b/plugins/PicoContact/PicoContact.php @@ -0,0 +1,103 @@ +P01contact = new P01C\P01contact(); + + if (!empty($config['default_language'])) { + $this->P01contact->default_lang = $config['default_language']; + } + } + /** + * Replace (% contact %) tags and contact_admin tags in pages content + * + * Triggered after Pico has prepared the raw file contents for parsing + * + * @see Pico::parseFileContent() + * @see DummyPlugin::onContentParsed() + * @param string &$content prepared file contents for parsing + * @return void + */ + public function onContentPrepared(&$content) + { + // replace config panel (% contact_admin_config %) + $content = preg_replace_callback('`\(%\s*contact_admin_config\s*%\)`', function () { + return '
' . $this->P01contact->panel(). '
'; + }, $content, 1); + + // replace debug report (% contact_admin_debug %) + $content = preg_replace_callback('`\(%\s*contact_admin_debug\s*%\)`', function () { + if (!$this->P01contact->config('debug')) { + return ''; + } + return '
' . $this->P01contact->debugReport() .'
'; + }, $content, 1); + + // replace forms (% contact ... %) + $content = $this->P01contact->parse($content); + } + /** + * Add {{ contact() }} and {{ contact_admin() }} twig functions + * For outputing forms and admin panels from themes templates + * + * Triggered when Pico registers the twig template engine + * + * @see Pico::getTwig() + * @param Twig_Environment &$twig Twig instance + * @return void + */ + public function onTwigRegistered(Twig_Environment &$twig) + { + // {{ contact() }} output the default form + // {{ contact('parameters') }} custom parameters + // {{ contact('fr', 'parameters') }} custom parameters and form-specific language + // {{ contact('fr', null) }} default form with form-specific language + $twig->addFunction(new Twig_SimpleFunction('contact', function ($a = null, $b = null) { + if ($b) { + return $this->P01contact->newForm($b, $a); + } + return $this->P01contact->newForm($a); + })); + + // {{ contact_admin('debug') }} output the debug report + // {{ contact_admin('config') }} output the config panel + $twig->addFunction(new Twig_SimpleFunction('contact_admin', function ($type) { + if ($type == 'debug' && $this->P01contact->config('debug')) { + return $this->P01contact->debugReport(); + } + if ($type == 'config') { + return $this->P01contact->panel(); + } + })); + } +} diff --git a/plugins/PicoContact/config.json b/plugins/PicoContact/config.json new file mode 100644 index 0000000..c9388de --- /dev/null +++ b/plugins/PicoContact/config.json @@ -0,0 +1,31 @@ +{ + "default_email": "info@chrosey.de", + "lang": "de", + "message_len": "", + "default_params": "name!, email!, subject!, message!", + "separator": ",", + "logs_count": "10", + "checklist": [ + { + "name": "", + "type": "blacklist", + "content": "" + }, + { + "name": "", + "type": "blacklist", + "content": "" + }, + { + "name": "", + "type": "blacklist", + "content": "" + } + ], + "use_honeypot": "on", + "min_sec_after_load": "3", + "min_sec_between_posts": "5", + "max_posts_by_hour": "10", + "recaptcha_public_key": "", + "recaptcha_secret_key": "" +} \ No newline at end of file diff --git a/plugins/PicoContact/lang/bg.yml b/plugins/PicoContact/lang/bg.yml new file mode 100644 index 0000000..3778f64 --- /dev/null +++ b/plugins/PicoContact/lang/bg.yml @@ -0,0 +1,86 @@ +--- +# Bulgarian language file for p01-contact +key: bg +name: Bulgarian +english_name: Bulgarian +authors: Panayot Kuyvliev +date: "2011-10-22" +compatibility: 1.1 +strings: + # fields + name: Име + email: Email + address: Адрес + tel: Телефон + url: Уебсайт + subject: Относно + message: Съобщение + file: Прикачи + captcha: Captcha + reload: Презареди + fieldcaptcha: Грешен код + askcopy: Прати ми копие на това съобщение + send: Прати + + # email words + askedcopy: Поискано е копие на това съобщение + anonymous: Анонимен + nosubject: (Няма тема) + email_title: Съобщението е изпратено от + + # status messages + sent: Съобщението е изпратено. + error: "Грешка : съобщението не е изпратено." + disable: Контактната форма е недостъпна. + error_notarget: Тази контактна форма няма получател. + token: Съобщението вече е изпратено. + + # fields errors + field_required: Това поле е задължително + field_email: Моля използвайте валиден имейл адрес + field_tel: Моля използвайте валиден телефонен номер + field_url: Моля напишете валиден уеб адрес + field_message: Моля напишете по дълго съобщение + field_captcha: Моля копирайте следния текст + field_fieldcaptcha: Моля не попълвайте това поле + field_password: Грешна парола + + # configuration panel + + config_title: p01contact Настройки + + # messages + config_updated: Твоите промени са запазени успешно. + + config_error_open: "Конфигуриращият файл не може да бъде отворен. Проверете дали файла съществува и неговата достъпност :" + + # New release alert + new_release: Има нова версия! + download: Свали последната версия + + # Links + doc: Документация + forum: Форум + + # Parameters + enable: Пусни + enable_sub: Пускане и спиране изпращането на съобщения (без да се скрива контактната форма). + + default_email: Емейл по подразбиране + default_email_sub: Оставете празно, за да го настроите да + + lang: Език + lang_sub: Езикът по подразбиране е + + default_params: Параметри по подразбиране + + message_len: Минимална големина на съобщението + + blacklist: Черен списък + whitelist: Бял списък + checklists_sub: "Черен списък: стойности, които не трябва да присъстват в областта за изпращане на имейл
. Бял списък: Възможните стойности от значение за областта, за да изпратите имейл
. Разделени със запетаи." + + general_fields: Общи полета + special_fields: Специални полета + + debug_sub: Изключване на изпращането на съобщения, display p01-contact data structure, data sent by POST and the email that would have been sent. diff --git a/plugins/PicoContact/lang/cz.yml b/plugins/PicoContact/lang/cz.yml new file mode 100644 index 0000000..0f9ad69 --- /dev/null +++ b/plugins/PicoContact/lang/cz.yml @@ -0,0 +1,128 @@ +--- +# Czech language file for p01-contact +key: cz +name: Czech +english_name: Czech +authors: Seva, princezna +date: "2017-10-31" +compatibility: 1.1 +strings: + # basic fields + text: text + textarea: textové pole + password: heslo + file: příloha + # html5 inputs types + color: barva + date: datum + email: email + month: měsíc + number: číslo + range: rozsah + search: hledání + tel: telefonní číslo + time: čas + url: URL + week: týden + # other fields + name: jméno + subject: předmět + message: zpráva + address: poštovní adresa + askcopy: pošlete mi kopii tohoto mailu + captcha: captcha + # actions + send: Odeslat + reload: Znovu načíst + reset: Vyresetovat + # received email + askedcopy: Kopie tohoto e-mailu je požadována + anonymous: Anonym + nosubject: (Bez předmětu) + email_title: E-mail odeslán z + + # confirmations + sent: Email byl odeslán. + sent_debug: Email byl virtuálně odeslán (je zapnutý debug mode). + sent_copy: Email byl odeslán. Kopie byla zaslána na zadanou adresu. + sent_copy_error: Email byl odeslán, ale nepovedlo se zaslat kopii. + sent_already: Zpráva již byla odeslána. + # errors + error: "Chyba : žádná zpráva se neposlala." + error_notarget: Tento kontaktní formulář nemá žádného příjemce. + error_honeypot: Blip. Blop. Blup. Byl jste rozpoznán jako robot. + error_pageload: Blip. Blop. Blup. Odesíláte zprávy tak často, jako robot. Počkejte prosím pár vteřin. + error_lastpost: Odeslal jste email před chvilkou. Počkejte prosím chvíli. + error_postcount: Odeslal jste příliš mnoho emailů během poslední hodiny. + # fields errors + field_required: Musíte vyplnit toto pole + field_email: Prosím vložte platný e-mail + field_tel: Prosím vložte platné telefonní číslo + field_url: Prosím vložte platnou webovou adresu + field_message: Prosím napište delší zprávu + field_captcha: Prosím vyplňte captchu + field_password: Špatné heslo + field_blacklist: Toto pole obsahovalo zakázané slova + field_whitelist: V tomto poli něco chybí + + # configuration panel + config_title: p01contact konfigurace + config_updated: Změny byly úspěšně uloženy. + config_error_open: Nepovedlo se otevřít konfigurační soubor. Ověřte, jestli existuje a jeho přístupová práva + config_error_modify: Nepovedlo se změnit konfigurační soubor. Ověřte jeho přístupová práva" + # infos + new_release: Existuje vydána nová verze! + download: Stáhnout poslední verzi + repo: Github + wiki: Dokumentace / Wiki + issues: Nápověda / nahlásit chybu + + # settings + + disable: Vypnout všechny formuláře + disable_sub: Vypne posílání emailu, ale neskryje kontaktní formuláře. + + default_email: Výchozí emaily + default_email_sub: Jedna nebo více emailových adres, oddělených čárkou, na které přijdou zprávy ze všech formulářů. + + default_params: Výchozí parametry + default_params_sub: Výchozí struktura formuláře. Více detailů v dokumentaci. + + lang: Jazyk + lang_sub: Výchozí jazyk je nastaven na + + message_len: Minimální délka zprávy + message_len_sub: Minimální počet znaků znaků pro políčka se zprávou. + + separator: Oddělovač + separator_sub: "Oddělovač v definici formulářů. Např. čárka, středník, dvě svislítka..." + + logs_count: Velikost logu + logs_count_sub: Maximální počet položek které mají být uchovány v logu. + + checklists: Checklisty + blacklist: Blacklist + whitelist: Whitelist + checklists_sub: Blacklist je seznam zakázaných hodnot v daném typu pole, a whitelist je seznam jediných povolených hodnot pro daný typ pole. Položky by měly být odděleny čárkou. + + use_honeypot: Použít skryté honeypot políčko + use_honeypot_sub: Přidá do každého formuláře skryté pole, které lidé neuvidí, ale většina spam botů ho vyplní a spadnou tak do pasti. + + min_sec_after_load: Minimální čas po načtení stránky + min_sec_after_load_sub: Minimální počet sekund mezi načtením stránky a odesláním formuláře. Lidé potřebují čas, aby si formulář přečetli, roboti nikoliv. + + min_sec_between_posts: Minimální čas mezi dvěma odesláními + min_sec_between_posts_sub: Minimální počet sekund mezi dvěma odesláními formuláře (od stejného člověka). + + max_posts_by_hour: Maximální počet odeslání za hodinu + max_posts_by_hour_sub: Limituje počet odeslaných zpráv jedním člověkem. + + captcha_info: Nativní anti-spam and anti-error mechanismy by měly zabránit všem podezřelým zprávám. Pokud potřebujete ještě vyšší úrove ochrany, můžete vytvořit vlastní captchu přidáním pole s povinnou odpovědí. Můžete také vložit Google reCaptcha použitím captcha pole s následujícím nastavením. + recaptcha_public_key: reCaptcha public key + recaptcha_public_key_sub: Google reCaptcha public key. + recaptcha_secret_key: reCaptcha secret key + recaptcha_secret_key_sub: Google reCaptcha secret key. + + debug: Debug mód + debug_sub: Vypne odesílání e-mailu a zobrazí strukturu p01-contact pluginu, data odeslaná přes POST a email co by byl poslán. + debug_warn: Neaktivujte na veřejně přístupné stránce! diff --git a/plugins/PicoContact/lang/da.yml b/plugins/PicoContact/lang/da.yml new file mode 100644 index 0000000..90ebdae --- /dev/null +++ b/plugins/PicoContact/lang/da.yml @@ -0,0 +1,93 @@ +--- +# Danish language file for p01-contact +key: da +name: Danish +english_name: Danish +authors: Christian Sand +date: "2011-10-27" +compatibility: 1.1 +strings: + # fields + name: Navn + email: Mail + address: Addresse + tel: Telefon + url: Hjemmeside + subject: Emne + message: Besked + file: Tilføj + captcha: Captcha + reload: Genindlæs + fieldcaptcha: "Undlad at udfylde følgende felt:" + askcopy: Send kopi af mail + send: Afsend + + # email words + askedcopy: Der er blevet bedt om en kopi af denne mail + anonymous: Uden afsender + nosubject: (Intet emne) + email_title: Mail afsendt fra + + # status messages + sent: Mail afsendt. + error: "Fejl: Beskeden blev ikke afsendt." + disable: Kontaktformularen er slået fra. + error_notarget: Kontaktformularen indeholder ingen modtager. + token: Beskeden er allerede afsendt. + + # fields errors + field_required: Udfyld dette tekstfelt + field_email: Benyt en gyldig mailadresse + field_tel: Benyt et gyldigt telefonnummer + field_url: Skriv en gyldig hjemmesideadresse + field_message: Skriv en længere meddelelse + field_captcha: Kopier den følgende tekst + field_fieldcaptcha: Undlad at udfylde dette tekstfelt + field_password: Ugyldigt kodeord + + # configuration panel + + config_title: Opsætning + + # messages + config_updated: Dine ændringer blev gemt. + + config_error_open: "Opsætningsfilen kan ikke læses. Undersøg at filen eksisterer, og at du har rettigheder til filen:" + + config_error_modify: "Opsætningsfilen kan ikke ændres. Undersøg, at du har rettigheder til filen:" + + # New release alert + new_release: Der er kommet en ny version! + download: Hent den seneste version + + # Links + doc: Dokumentation + forum: Hjælp + + # Parameters + enable: Afsendelse af mail + enable_sub: Aktiver eller afbryd afsendelse af mail (skjuler ikke kontaktformularen). + + default_email: Webstedet standardmail + default_email_sub: Undlad at udfylde for at benytte + + lang: Sprog + lang_sub: "Standardsproget er indstillet til:" + + default_params: Udformning af kontaktformular + default_params_sub: Benyt etikettesyntaks som beskrevet i dokumentation. + + message_len: Beskedens mindstelængde + message_len_sub: Mindste antal karakterer i beskedfelt. + + checklists: Tjekliste + blacklist: Bandlyst + whitelist: Påkrævet + checklists_sub: Rediger tjeklisten med bandlyste værdier, som mailen ikke må indeholde, eller med værdier som er påkrævede for afsendelse af mail.
De enkelte værdier separeres med komma. + + general_fields: Generelle værdier + special_fields: Specifikke værdier + + debug: Fejlfindingstilstand + debug_sub: Afbryd afsendelse af mail. Gennemse filstrukturen for p01-kontaktdata; revider data sendt af POST og data for mailen, som skulle være afsendt. + debug_warn: Aktiver ikke fejlfinding på et fungerende websted! diff --git a/plugins/PicoContact/lang/de.yml b/plugins/PicoContact/lang/de.yml new file mode 100644 index 0000000..1fcbb92 --- /dev/null +++ b/plugins/PicoContact/lang/de.yml @@ -0,0 +1,126 @@ +--- +# German language file for p01-contact +key: de +name: Deutsch +english_name: German +authors: Martin Köhler, sonst-was +date: "2011-10-27" +compatibility: 1.1 +strings: + # basic fields + text: Text + textarea: Textbereich + password: Passwort + file: Anhang + # html5 inputs types + color: Farbe + date: Datum + email: E-Mail + month: Monat + number: Nummer + range: Bereich + search: Suche + tel: Telefonnummer + time: Zeit + url: Website + week: Woche + # other fields + name: Name + subject: Betreff + message: Nachricht + address: Anschrift + captcha: Captcha + askcopy: Eine Kopie an mich senden + # actions + send: Senden + reload: Neu laden + reset: Zurücksetzen + # received email + askedcopy: Eine Kopie wurde angefordert + anonymous: Anonym + nosubject: (kein Betreff) + email_title: Nachricht gesendet von + # confirmations + sent: Nachricht verschickt. + sent_debug: Nachricht virtuell verschickt (Debugmodus ist aktiviert). + sent_copy: Nachricht verschickt. Eine Kopie wurde an die angegebene Adresse geschickt. + sent_copy_error: Nachricht verschickt, beim Senden der Kopie gab es jedoch einen Fehler. + sent_already: Die Nachricht wurde bereits verschickt. + # errors + error: "Fehler : Nachricht wurde nicht verschickt." + error_notarget: Das Kontaktformular hat keinen Empfänger. + error_honeypot: Blubber di blubb, Sie sind in den Honigtopf für Roboter gefallen. + error_pageload: Blubber di blubb, Sie sind schnell wie ein Robter, bitte warten Sie einige Sekunden. + error_lastpost: Sie haben erst vor kurzem abgeschickt, bitte einen Moment warten. + error_postcount: Sie haben innerhalb einer Stunde zu häufig abgeschickt. + # fields errors + field_required: Dieses Feld ist obligatorisch + field_email: Bitte korrekte E-Mail-Adresse verwenden + field_tel: Bitte korrekte Telefonnummer verwenden + field_url: Bitte korrekte Internetadresse angeben + field_message: Bitte umfangreichere Nachricht schreiben + field_captcha: Folgendes bitte abschreiben + field_password: Passwort falsch + field_blacklist: Dieses Feld enthält nicht erlaubte Worte. + field_whitelist: Dieses Feld enthält erforderliche Worte nicht. + # configuration panel + config_title: p01contact Konfiguration + config_updated: Änderungen wurden gespeichert. + config_error_open: Kann Konfiguration nicht öffnen. Bitte überprüfen ob Datei vorhanden ist und korrekte Berechtigungen hat + config_error_modify: Kann Konfiguration nicht ändern. Bitte Berechtigungen überprüfen + # infos + new_release: Es gibt eine neue Version! + download: Aktuelle Version herunterladen + repo: Github + wiki: Dokumentation / Wiki + issues: Hilfe / Fehler melden + + # settings + + disable: Alle Formulare deaktivieren + disable_sub: Deaktiviert E-Mail-Versand ohne das Kontaktformular zu verstecken. + + default_email: Standard-E-Mail-Adresse + default_email_sub: Eine oder mehrere E-Mail-Adressen (durch Komma separiert), welche E-Mails aller Formulare erhalten. + + default_params: Standardwerte + default_params_sub: Standardstruktur. Bitte Syntax laut Dokumentation verwenden. + + lang: Sprache + lang_sub: Standardsprache ist + + message_len: Mindestzeichenzahl + message_len_sub: Mindestanzahl an Zeichen im Nachrichtenfeld. + + separator: Trennzeichen + separator_sub: "Trennzeichen für Formular-MarkUp. Zum Beispiel Komma, Semikolon, ..." + + logs_count: Anzahl Logs + logs_count_sub: Maximale Anzahl an Einträgen in Logs. + + checklists: Feldercheckliste + blacklist: Blacklist + whitelist: Whitelist + checklists_sub: Eine Blacklist ist eine Liste verbotener Werte im jeweiligen Feldtyp und eine Whitelist ist eine Liste mit Werten ausschließlich erlaubt sind. Durch Kommata abgetrennt. + + use_honeypot: Verstecktes Feld nutzen (Honigtopf) + use_honeypot_sub: Fügt ein verstecktes Feld zu jedem Formular hinzu, welches von Menschen nicht ausgefüllt werden kann. Viele Roboter füllen es jedoch aus. + + min_sec_after_load: Minimale Zeit seit Seitenaufruf + min_sec_after_load_sub: Minimale Anzahl Sekunden die zwischen Seitenaufruf und Abschicken vergangen sein muss. Menschen brauchen einige Zeit um das Formular auszufüllen und abzuschicken, Roboter dagegen nicht. + + min_sec_between_posts: Minimale Zeit zwischen Einsendungen + min_sec_between_posts_sub: Minimale Anzahl Sekunden zwischen zwei Einsendungen des gleichen Nutzers. + + max_posts_by_hour: Maximale Einsendungen pro Stunde + max_posts_by_hour_sub: Maximale Einsendungen pro Stunde und Nutzer + + captcha_info: Die nativen Anti-Spam Mechanismen sollten alle unerwünschte Einsendungen blockieren. Wenn mehr Sicherheit benötigt wird, kann ein benutzerdefiniertes Feld genutzt werden mit einer erforderlichen Antwort. Alternativ kann ein Google reCaptcha mit captcha und unten aufgeführten Einstellungen eingefügt werden. + recaptcha_public_key: reCaptcha öffentlicher Schlüssel + recaptcha_public_key_sub: Google reCaptcha öffentlicher Schlüssel. + recaptcha_secret_key: reCaptcha geheimer Schlüssel + recaptcha_secret_key_sub: Google reCaptcha geheimer Schlüssel. + + debug: Debugmodus + debug_sub: E-Mail versand deaktiveren, Datenstruktur von p01-contact anzeigen, Daten per POST verschickt und die E-Mail, die verschickt worden waere. + debug_warn: Nicht im Produktivbetrieb verwenden! diff --git a/plugins/PicoContact/lang/en.yml b/plugins/PicoContact/lang/en.yml new file mode 100644 index 0000000..5bfcdbd --- /dev/null +++ b/plugins/PicoContact/lang/en.yml @@ -0,0 +1,126 @@ +--- +# English language file for p01contact +key: en +name: English +english_name: English +authors: Nicolas Liautaud +date: "2011-10-23" +compatibility: 1.1 +strings: + # basic fields + text: text + textarea: text area + password: password + file: attachment + # html5 inputs types + color: color + date: date + email: email + month: month + number: number + range: range + search: search + tel: phone number + time: time + url: URL + week: week + # other fields + name: name + subject: subject + message: message + address: postal address + askcopy: send me a copy of this email + captcha: captcha + # actions + send: Send + reload: Reload + reset: Clear this form + # received email + askedcopy: A copy of this email have been requested + anonymous: Anonymous + nosubject: (No subject) + email_title: Mail sent from + # confirmations + sent: Email sent. + sent_debug: Email virtually sent (debug mode enabled). + sent_copy: Email sent. A copy have been sent to the specified address. + sent_copy_error: Email sent, but there was an issue when sending you the copy. + sent_already: The message have already been sent. + # errors + error: "Error : no message was sent." + error_notarget: This contact form has no recipient. + error_honeypot: Blip. Blop. Blup. You felt in the honeypot for robots. + error_pageload: Blip. Blop. Blup. You're as fast as a robot. Please wait a few seconds. + error_lastpost: You submitted just recently. Please wait a bit. + error_postcount: You submitted too much times this hour. + # fields errors + field_required: This field is required + field_email: Please use a valid email address + field_tel: Please use a valid phone number + field_url: Please write a valid web address + field_message: Please write a longer message + field_captcha: Please answer correctly the following captcha + field_password: Wrong password + field_blacklist: This field contains prohibited terms + field_whitelist: An expected value is missing + # configuration panel + config_title: p01contact configuration + config_updated: Your changes were saved successfully. + config_error_open: Unable to open config file. Check if the file exists and its permissions + config_error_modify: Unable to modify config file. Check the file permissions" + # infos + new_release: There is a new release! + download: Download the last version + repo: Github + wiki: Documentation / Wiki + issues: Help / report a bug + + # settings + + disable: Disable all forms + disable_sub: Disable mail sending, without hiding the contact forms. + + default_email: Default emails + default_email_sub: One ore more email addresses, separated by commas, that will receive mails from every forms. + + default_params: Default parameters + default_params_sub: Default form structure. Use syntax described in documentation. + + lang: Language + lang_sub: Default language is set to + + message_len: Messages minimum length + message_len_sub: Minimum number of characters for message fields. + + separator: Separator + separator_sub: "Parameters separator in forms markup. Ex: comma, semicolon, double-pipe..." + + logs_count: Logs number + logs_count_sub: Maximum number of entries to keep on logs. + + checklists: Fields checklists + blacklist: Blacklist + whitelist: Whitelist + checklists_sub: A blacklist is a list of prohibited values in the given field type, and a whitelist is a list of the only possible values for the given field type. Each term should be separated by commas. + + use_honeypot: Use hidden honeypot field + use_honeypot_sub: Add to every forms a hidden field that should not be filled. Humans won't see it, but most spam bots will fell in the trap. + + min_sec_after_load: Minimum time after page load + min_sec_after_load_sub: Minimum number of seconds between a page load and a form submission. Fellow humans need at least a few seconds to read, fill and submit a form. Robots don't. + + min_sec_between_posts: Minimum time between two submissions + min_sec_between_posts_sub: Minimum number of seconds between two form submissions by a same user. + + max_posts_by_hour: Maximum submissions by hour + max_posts_by_hour_sub: Maximum number of submissions every hour by user. + + captcha_info: The native anti-spam and anti-error mechanisms should prevent all undesirable submissions. If you need a higher level of security you can create a custom captcha by adding a field with a required answer. Finally, you can insert a Google reCaptcha by using a captcha field with the below settings. + recaptcha_public_key: reCaptcha public key + recaptcha_public_key_sub: Google reCaptcha public key. + recaptcha_secret_key: reCaptcha secret key + recaptcha_secret_key_sub: Google reCaptcha secret key. + + debug: Debug mode + debug_sub: Disable mail sending, display p01-contact data structure, data sent by POST and the email that would have been sent. + debug_warn: Don't active that on production website! diff --git a/plugins/PicoContact/lang/es.yml b/plugins/PicoContact/lang/es.yml new file mode 100644 index 0000000..085a5a9 --- /dev/null +++ b/plugins/PicoContact/lang/es.yml @@ -0,0 +1,92 @@ +--- +# Spanish language file for p01-contact +key: es +name: Spanish +english_name: Spanish +authors: Carlos Navarro, Daniel A. Rodriguez +date: "2011-10-27" +compatibility: 1.1 +strings: + # fields + name: Nombre + email: Correo electrónico + address: Dirección postal + tel: Teléfono + url: Sitio web + subject: Asunto + message: Mensaje + file: Archivo adjunto + captcha: Captcha + reload: Recargar + askcopy: Enviar copia por Correo electrónico + send: Enviar + + # email words + askedcopy: Se ha solicitado una copia de este mensaje + anonymous: Anónimo + nosubject: (Sin asunto) + email_title: Correo electrónico enviado desde + + # status messages + sent: Correo electrónico enviado. + error: "Error: mensaje no enviado." + disable: Plugin de Contacto desactivado. + error_notarget: Este formulario de contacto no tiene destinatario. + token: El mensaje ya ha sido enviado. + + # fields errors + field_required: Campo obligatorio + field_email: Es necesaria una dirección de correo electrónico válida + field_tel: Es necesario un número de teléfono válido + field_url: Es necesaria una dirección web válida + field_message: El mensaje ha de ser más largo + field_captcha: Copiar el siguiente texto + field_fieldcaptcha: Por favor, no complete este campo + field_password: Clave incorrecta + + # configuration panel + + config_title: Configuración de p01contact + + # messages + config_updated: Sus cambios han sido guardados. + + config_error_open: "No se puede abrir el archivo de configuración. Verifique que el archivo exista y sus permisos:" + + config_error_modify: "No se puede modificar el archivo de configuración. Verifique los permisos:" + + # New release alert + new_release: Nueva versión disponible! + download: Descargue la última versión + + # Links + doc: Documentación + forum: Foro + + # Parameters + enable: Habilitar + enable_sub: Habilitar o desabilitar el envío de correo (no oculta el formulario). + + default_email: Remitente predeterminado + default_email_sub: Dejar en blanco para autocompletado + + lang: Idioma + lang_sub: El idioma predeterminado se ha establecido a + + default_params: Parámetros predeterminados + default_params_sub: Etiqueta predeterminado para estructura de formulario. Use la sintáxis descrita en la documentación. + + message_len: Longitud mínima del mensaje + message_len_sub: Cantidad mínima de caracteres para los campos del mensaje. + + checklists: Checklists + blacklist: Lista negra + whitelist: Lista blanca + checklists_sub: "Lista negra : valores que no deben estar presentes en el campo para envío de mensajes.
Lista blanca : posibles valores requeridos para el campo de envío de mensajes.
Separados por comas" + + general_fields: Campos generales + special_fields: Campos escpeciales + + debug: Modo debug + debug_sub: Deshabilitar envío de mensajes, mostrar la estructura de datos de display p01-contact, datos enviados por POST y el mensaje que debería haber sido enviado. + debug_warn: No activar en sitios en producción! diff --git a/plugins/PicoContact/lang/fr.yml b/plugins/PicoContact/lang/fr.yml new file mode 100644 index 0000000..52b1d83 --- /dev/null +++ b/plugins/PicoContact/lang/fr.yml @@ -0,0 +1,117 @@ +--- +# French language file for p01contact" +key: fr +name: Français +english_name: French +authors: Nicolas Liautaud +date: "2011-10-23" +compatibility: 1.1 +strings: + # basic fields + text: texte + textarea: champ de texte + password: mot de passe + file: pièce jointe + # html5 inputs types + color: couleur + date: date + email: adresse email + month: mois + number: nombre + range: valeur + search: recherche + tel: numéro de téléphone + time: heure + url: URL + week: semaine + # other fields + name: nom + subject: objet + message: message + address: adresse postale + askcopy: envoyez-moi une copie de cet email + captcha: captcha + # actions + send: envoyer + reload: recharger + reset: remettre à zéro + # received email + askedcopy: Une copie de cet email a été demandée + anonymous: Anonyme + nosubject: (Pas d'objet) + email_title: Email envoyé depuis + # confirmations + sent: Email envoyé. + sent_debug: Email virtuellement envoyé (mode debug actif). + sent_copy: Email envoyé. Une copie a été envoyée à l'addresse spécifiée. + sent_copy_error: Email envoyé, mais il y a eu un problème lors de l'envoie de votre copie. + sent_already: Le formulaire a déjà été envoyé. + # errors + error: "Erreur : aucun message n'a été envoyé." + error_notarget: Ce formulaire de contact n'a pas de destinataire. + error_honeypot: Blip. Blop. Blup. Vous êtes tombé dans le piège à robot. + error_pageload: Blip. Blop. Blup. Vous êtes aussi rapide qu'un robot. Veuillez attendre quelques secondes. + error_lastpost: Vous venez d'utiliser ce formulaire. Merci d'attendre un peu. + error_postcount: Vous avez trop utilisé ce formulaire cette heure ci. + # fields errors + field_required: Ce champ est obligatoire + field_email: Veuillez entrer une adresse email valide + field_tel: Veuillez entrer un numéro de téléphone valide + field_url: Veuillez entrer une adresse internet valide + field_message: Veuillez écrire un message plus long + field_captcha: Veuillez recopier le texte ci-dessous + field_password: Mot de passe incorrect + field_blacklist: Ce champ contiens des termes prohibés + field_whitelist: Une valeur attendue est manquante + # configuration panel + config_title: Configuration de p01contact + config_updated: Vos modifications ont été enregistrées avec succès. + config_error_open: Impossible d'ouvrir le fichier de configuration. Vérifiez s'il existe et ses permissions + config_error_modify: Impossible de modifier le fichier de configuration. Vérifiez ses permissions + # infos + new_release: Il y a une nouvelle version! + download: Télécharger la dernière version + repo: Github + wiki: Documentation / Wiki + issues: Aide / rapporter un bug + + # settings + + disable: Désactiver tous les formulaires + disable_sub: Désactive l'envoi de mail, sans cacher les formulaires. + + default_email: Emails par défaut + default_email_sub: Une addresse email ou plus, séparées par des virgules, qui reçevront les mails de tous les formulaires. + + default_params: Paramètres par défaut + default_params_sub: Structure des formulaires pour les balises par défaut. Utilisez la syntaxe décrite dans la documentation. + + lang: Langue + lang_sub: La langue par défaut est définie à + message_len: Longueur minimum des messages + message_len_sub: Nombre minimum de caractères authorisé pour les champs message + + checklists: Listes de vérification des champs + blacklist: Liste noire + whitelist: Liste blanche + checklists_sub: Une liste noire est une liste de valeurs qui ne doivent pas être présentes dans un champ pour envoyer le mail, une liste blanche est une liste de valeurs possibles devant être présentes dans un champ pour envoyer le mail. Chaque terme est séparé par des virgules. + + use_honeypot: Utiliser le champ honeypot + use_honeypot_sub: Ajoute à chaque formulaire un champ caché qui ne doit pas être rempli. Les humains ne le voient pas, mais les robots de spam tombent dans le piège. + + min_sec_after_load: Temps minimium au chargement de la page + min_sec_after_load_sub: Nombre minimum de secondes entre le chargement de la page et l'envoi d'un formulaire. Les humains ont besoin d'au moins quelques secondes pour lire, remplir et valider un formulaire. Pas les robots. + min_sec_between_posts: Temps minimum entre deux envois + min_sec_between_posts_sub: Nombre minimum de secondes entre deux envois de formulaires par un même visiteur. + + max_posts_by_hour: Nombre d'envoi maximum par heure + max_posts_by_hour_sub: Nombre maximum de soumission d'un formulaire par heure et par visiteur. + + captcha_info: Les mécanismes anti-spam et anti-erreurs devraient prévenir l'intégralité des envois indésirables. En cas de besoin d'un niveau de sécurité supérieur, vous pouvez créer un champ personnalisé avec une valeur requise. Finalement, vous pouvez insérer un reCaptcha Google en utilisant un champ captcha avec les paramètres suivants. + recaptcha_public_key: Clé publique reCaptcha + recaptcha_public_key_sub: Clé publique Google reCaptcha. + recaptcha_secret_key: Clé secrète reCaptcha + recaptcha_secret_key_sub: Clé secrète Google reCaptcha. + debug: Mode debug + debug_sub: Désactive l'envoi de mails, affiche les structures de données de P01contact, les données envoyées par POST et les mails qui auraient été envoyés. + debug_warn: A ne pas activer sur un site en production ! diff --git a/plugins/PicoContact/lang/it.yml b/plugins/PicoContact/lang/it.yml new file mode 100644 index 0000000..bda0d23 --- /dev/null +++ b/plugins/PicoContact/lang/it.yml @@ -0,0 +1,126 @@ +--- +# Italian language file for p01-contact +key: it +name: Italiano +english_name: Italian +authors: Nicola Sarti, Nicola Scattaglia +date: "2017-10-23" +compatibility: 1.1 +strings: + # basic fields + text: testo + textarea: area di testo + password: password + file: file + # html5 inputs types + color: colore + date: data + email: email + month: mese + number: numero + range: range + search: cerca + tel: telefono + time: orario + url: URL + week: settimana + # other fields + name: nome + subject: soggetto + message: messaggio + address: indirizzo postale + askcopy: invia anche a me una copia + captcha: captcha + # actions + send: invia + reload: ricarica + reset: Pulisci il form + # received email + askedcopy: È stata richiesta una copia di questa email + anonymous: Anonimo + nosubject: (Nessun oggetto) + email_title: Inviata da + # confirmations + sent: Email inviata. + sent_debug: Email virtualmente inviata (abilitata modalità debug). + sent_copy: Email inviata. Una copia è stata inviata all'indirizzo specificato. + sent_copy_error: Email inviata, ma si è verificato un errore nell'invio della copia. + sent_already: Il messaggio è già stato inviato. + # errors + error: "Errore : nessun messaggio inviato." + error_notarget: Questo form di contatto non ha nessun destinatario. + error_honeypot: Blip. Blop. Blup. Sei caduto nell'honeypot per i robot. + error_pageload: Blip. Blop. Blup. Sei veloce quanto un robot. Attendi per favore. + error_lastpost: Hai appena inviato. Attendi qualche istante. + error_postcount: Hai inviato troppo in questa ora. + # fields errors + field_required: Campo richiesto + field_email: Per favore usa un indirizzo email valido + field_tel: Per favore usa un numero di telefono valido + field_url: Per favore usa un indirizzo web valido + field_message: Per favore inserisci un maggior numero di caratteri + field_captcha: Per favore rispondi correttamente al seguente captcha + field_password: Password errata + field_blacklist: Questo campo contiene parole non permesse + field_whitelist: Un valore è mancante + # configuration panel + config_title: Configurazione p01contact + config_updated: Le modifiche sono state applicate. + config_error_open: "Impossibile aprire il file di configurazione. Controlla che esista e i suoi permessi :" + config_error_modify: "Impossibile modificare il file di configurazione. Controlla i permessi di accesso :" + # infos + new_release: È disponibile una nuova release! + download: Scarica l'ultima versione + repo: Github + wiki: Documentazione / Wiki + issues: Aiuto / Segnala un bug + + # settings + + disable: Disabilita tutti i form + disable_sub: Disabilita invio mail, senza nascondere i form di contatto. + + default_email: Email di default + default_email_sub: Uno o più indirizzi, separati da virgola, che riceveranno tutte le mail dei form. + + default_params: Parametri di default + default_params_sub: Struttura form di default. Usa la sintassi descritta nella documentazione. + + lang: Lingua + lang_sub: La lingua di default è impostata in + + message_len: Lunghezza minima del messaggio + message_len_sub: Numero minimo di caratteri per il campo messaggio. + + separator: Separatore + separator_sub: "Separatore parametri nel markup dei form. Es: virgola, punto e virgola, doppia barra verticale..." + + logs_count: Numero di log + logs_count_sub: Numero massimo di voci da tenere nei log. + + checklists: Checklist dei campi + blacklist: Blacklist + whitelist: Whitelist + checklists_sub: "Una blacklist è una lista di valori che non devono essere presenti nel campo per inviare l'email, una whitelist è una lista di possibili valori richiesti nel campo per inviare l'email. Separati da virgola" + + use_honeypot: Usa campo honeypot nasconsto + use_honeypot_sub: Aggiunge ad ogni form, un campo nascosto da non compilare. Le persone non lo vedranno, ma i bot spam cadranno nella trappola. + + min_sec_after_load: Tempo minimo dopo il caricamento pagina + min_sec_after_load_sub: Numero minimo di secondi tra il caricamento pagina e l'invio del form. Le persone hanno bisogno di almeno qualche secondo per leggere, compilare e inviare un form. I robot no. + + min_sec_between_posts: Tempo minimo tra due invii + min_sec_between_posts_sub: Tempo minimo di secondi fra l'invio di due form da parte dello stesso utente. + + max_posts_by_hour: Invii massimi in un'ora + max_posts_by_hour_sub: Numero massimo di invii per ogni ora da un utente. + + captcha_info: I meccasismi anti-spam e anti-errore dovrebbero prevenire tutti gli invii indesiderati. Se hai bisogno di un livello più alto di sicurezza puoi creare un captcha personalizzato aggiungendo un campo con una risposta obbligatoria. Infine, puoi inserire un Google reCaptcha usando un campo captcha con le seguenti impostazioni. + recaptcha_public_key: reCaptcha public key + recaptcha_public_key_sub: Google reCaptcha public key. + recaptcha_secret_key: reCaptcha secret key + recaptcha_secret_key_sub: Google reCaptcha secret key. + + debug: Modalità debug + debug_sub: Disabilita l'invio di email, mostra la data structure di p01-contact , i dati inviati da POST e l'email che sarebbe stata inviata. + debug_warn: Non attivarlo sul sito di produzione! \ No newline at end of file diff --git a/plugins/PicoContact/lang/ka.yml b/plugins/PicoContact/lang/ka.yml new file mode 100644 index 0000000..3b34257 --- /dev/null +++ b/plugins/PicoContact/lang/ka.yml @@ -0,0 +1,93 @@ +--- +# Italian language file for p01-contact +key: ka +name: Georgian (Kartuli) +english_name: Georgian (Kartuli) +authors: Temur Danelia +date: "2011-10-27" +compatibility: 1.1 +strings: + # fields + name: სახელი + email: ელფოსტა + address: მისამართი + tel: ტელეფონის ნომერი + url: ვებგვერდი + subject: სათაური + message: წერილის ტექსტი + file: მიმაგრებული + captcha: Captcha + reload: ხელახლა ჩატვირთვა + fieldcaptcha: "არ შეავსოთ ეს ველი :" + askcopy: გამომიგზავნეთ ამ წერილის ასლი + send: გაგზავნა + + # email words + askedcopy: ამ წერილის ასლი მიუვიდა გამომგზავნს + anonymous: ანონიმური + nosubject: (სათაურის გარეშე) + email_title: წერილის ავტორი + + # status messages + sent: წერილი გაიგზავნა. + error: "შეცდომა : წერილი არ გაიგზავნა." + disable: კონტაქტის ფორმა გამორთულია. + error_notarget: ამ კონტაქტის ფორმას არ ჰყავს ადრესატი. + token: წერილი უკვე გაიგზავნა. + + # fields errors + field_required: ამ ველის შევსება სავალდებულოა + field_email: გამოიყენეთ არსებული ელფოსტა + field_tel: გამოიყენეთ არსებული ტელეფონის ნომერი + field_url: შეიყვანეთ არსებული ვებგვერდის მისამართი + field_message: წერილის ტექსტი ძალიან მოკლეა + field_captcha: დააკოპირეთ შემდეგი ტექსტი + field_fieldcaptcha: არ შეავსოთ ეს ველი + field_password: არასწორი პაროლი + + # configuration panel + + config_title: p01contact-ის კონფიგურაცია + + # messages + config_updated: ცვლილებები წარმატებით შეინახა. + + config_error_open: "config ფაილის გახსნა შეუძლებელია. გადაამოწმეთ რომ ფაილი არსებობს და მისი დაშვებებია :" + + config_error_modify: "config ფაილის შეცვლა შეუძლებელია. გადაამოწმეთ ფაილის დაშვებები :" + + # New release alert + new_release: არსებობს ჩანართის უფრო ახალი ვერსია! + download: გადმოწერეთ ჩანართის ბოლო ვერსია + + # Links + doc: დოკუმენტაცია + forum: ფორუმი + + # Parameters + enable: ჩართვა + enable_sub: წერილის გაგზავნის ფუნქციის ჩართვა ან გამორთვა (საკონტაქტო ფორმა არ დაიმალება). + + default_email: ნაგულისხმები ელფოსტა + default_email_sub: დატოვეთ ცარიელი რათა დაყენდეს + + lang: ენა + lang_sub: ნაგულისხმებ ენად დაყენებულია + + default_params: ნაგულისხმები პარამეტრები + default_params_sub: ფორმის ნაგულისხმები სტრუქტურის ტეგები. გამოიყენეთ დოკუმენტაციაში აღწერილი სინტაქსი. + + message_len: წერილის ტექსტის მინიმალური ზომა + message_len_sub: სიმბოლოების მინიმალური რაოდენობა წერილის ტექსტის ველში. + + checklists: ველების დაშვებების სია + blacklist: შავი სია + whitelist: თეთრი სია + checklists_sub: "შავი სია : სიმბოლოები, რომელთა შესაბამის ველში შეყვანის შემთხვევაში წერილი არ გაიგზავნება.
Whitelist : სიმბოლოები, რომელთა შესაბამის ველში შეყვანის გარეშე წერილი არ გაიგზავნება.
გამოყავით მძიმით." + + general_fields: ძირითადი ველები + special_fields: სპეციალური ველები + + debug: შეცდომების გასწორების რეჟიმი + debug_sub: წერილის გაგზავნის ფუნქციის გამორთვა, p01-contact-ის მონაცემთა სტრუქტურის ჩვენება, POST-ის მიერ გაგზავნილი მონაცემები და წერილი, რომელიც გაიგზავნებოდა. + debug_warn: არ გამოიყენოთ მოქმედ საიტზე! diff --git a/plugins/PicoContact/lang/lt.yml b/plugins/PicoContact/lang/lt.yml new file mode 100644 index 0000000..73027a8 --- /dev/null +++ b/plugins/PicoContact/lang/lt.yml @@ -0,0 +1,93 @@ +--- +# Lithuanian language file for p01-contact +key: lt +name: Lithuanian +english_name: Lithuanian +authors: Vaidotas Kazla +date: "2011-10-27" +compatibility: 1.1 +strings: + # fields + name: Vardas + email: El. paštas + address: Pašto adresas + tel: Telefonas + url: Interneto svetainė + subject: Tema + message: Žinutė + file: Prisegtas failas + captcha: Apsaugos kodas + reload: Atnaujinti + fieldcaptcha: "Prašome nepildyti šio lauko :" + askcopy: Atsiųsti laiško kopiją man + send: Siųsti + + # email words + askedcopy: Buvo prašymas gauti šios žinutės kopiją + anonymous: Anonimas + nosubject: (be temos) + email_title: Išsiųsta iš + + # status messages + sent: Žinutė išsiųsta sėkmingai. + error: "Klaida: nepavyko išsiųsti žinutės." + disable: Susisiekimo formos yra išjungtos. + error_notarget: Ši susisiekimo forma neturi nurodyto gavėjo. + token: Ši žinutė jau buvo išsiųsta. + + # fields errors + field_required: Būtina užpildyti šį lauką + field_email: Prašome įvesti teisingą el. pašto adresą + field_tel: Prašome įvesti teisingą telefono numerį + field_url: Prašome įvesti teisingą interneto svetainės adresą + field_message: Žinutė per trumpa + field_captcha: Prašome įvesti šį apsaugos kodą + field_fieldcaptcha: Prašome nepildyti šio lauko + field_password: Neteisingas slaptažodis + + # configuration panel + + config_title: p01contact konfigūracija + + # messages + config_updated: Jūsų pakeitimai išsaugoti sėkmingai. + + config_error_open: "Nepavyko atverti konfigūracijos failo. Prašome patikrinti kad failas egzistuoja ir turi teisingus leidimus:" + + config_error_modify: "Nepavyko pakeisti konfigūracijos failo. Prašome patikrinti failo leidimus :" + + # New release alert + new_release: Yra nauja versija! + download: Parsiųsti naują versiją + + # Links + doc: Dokumentacija + forum: Forumas + + # Parameters + enable: Įjungti + enable_sub: Įjungti arba išjungti pašto siuntimą (nepaslepia formų). + + default_email: Numatytasis el. pašto adresas + default_email_sub: Jei paliksite tuščią, laiškai bus siunčiami į + + lang: Kalba + lang_sub: Numatytoji kalba nustatyta kaip + + default_params: Numatytieji parametrai + default_params_sub: Numatytoji žymų formos struktūra. Naudokite sintaksę aprašytą dokumentacijoje. + + message_len: Minimalus žinutės ilgis. + message_len_sub: Minimalus leidžiamas simbolių skaičius žinutės laukams. + + checklists: Laukų kontrolinis sąrašas + blacklist: Juodasis sąrašas + whitelist: Baltasis sąrašas + checklists_sub: "Juodasis sąrašas : žodžiai kuriuos radus formos laukuose nebus siunčiamas el. laiškas.
Baltasis sąrašas : žodžiai, kurie privalo būti formos laukuose, kad būtų siunčiamas el. laiškas.
Reikšmės atskiriamos kableliais." + + general_fields: Pagrindiniai laukai + special_fields: Specialūs laukai + + debug: Derinimo režimas + debug_sub: Išjungiamas laiško siuntimas, vietoje to parodoma p01-contact duomenų struktūra, siunčiami POST duomenys ir siunčiamo laiško vaizdas. + debug_warn: Prašome nenaudoti veikiančioje svetainėje! diff --git a/plugins/PicoContact/lang/mk.yml b/plugins/PicoContact/lang/mk.yml new file mode 100644 index 0000000..531867e --- /dev/null +++ b/plugins/PicoContact/lang/mk.yml @@ -0,0 +1,93 @@ +--- +# Macedonian language file for p01-contact +key: mk +name: Macedonian +english_name: Macedonian +authors: Спиркоски +date: "2011-10-27" +compatibility: 1.1 +strings: + # fields + name: Име + email: Email + address: Поштенска адреса + tel: Телефонски број + url: Web страна + subject: Наслов + message: Порака + file: Прилог + captcha: Captcha + reload: Смени + fieldcaptcha: "Ве молам не пополнувајте го следното поле:" + askcopy: Испрати ми копија на оваа email адреса + send: Испрати + + # email words + askedcopy: Побарана беше копија од оваа email порака + anonymous: Анонимно + nosubject: (Нема наслов) + email_title: Пораката е испратена од + + # status messages + sent: Email пораката е пратена. + error: "ГРЕШКА: пораката не е пратена." + disable: Контакт формите се исклучени. + error_notarget: Оваа контактна форма нема примач. + token: Пораката веќе беше испратена. + + # fields errors + field_required: Ова поле е обврзно + field_email: Ве молам внесете валидна email адреса + field_tel: Ве молам внесете валиден телефонски број + field_url: Ве молам внесете валидна web адреса + field_message: Ве молам напишете подолга порака + field_captcha: Ве молам препишете го следниот текст + field_fieldcaptcha: Ве молам не го пополнувајте ова поле + field_password: Погрешна лозинка + + # configuration panel + + config_title: p01contact конфигурација + + # messages + config_updated: Вашите измени се успешно зачувани. + + config_error_open: "Не можам да ја отворам конфугурациската датотека. Ве молам проверете дали постои датотеката и нејзините привилегии:" + + config_error_modify: "Не можам да ја изменам конфигурацискта датотека. Проверете ги нејзините привилегии:" + + # New release alert + new_release: Има нова верзија! + download: Превземи ја најновата верзија + + # Links + doc: Документација + forum: Форум + + # Parameters + enable: Вклучи + enable_sub: Вклучи или исклучи испраќање на пораки (не ги крие контакт формите). + + default_email: Главен email + default_email_sub: Оставете го празно за да биде конфигурирано на + + lang: Јазик + lang_sub: Основниот јазик е конфигуриран на + + default_params: Основни параметри + default_params_sub: Структура на основна tag форма. Користете ја синтаксата опишана во документацијата. + + message_len: Минимална должина на пораката + message_len_sub: Минимален број на знаци во полињата за порака. + + checklists: Чеклисти на полињата + blacklist: Црна листа + whitelist: Бела листа + checklists_sub: "Црна листа: вредности кои не смеат да се појават за да се прати пораката.
Бела листа: можни вредности потребни за да се прати пораката.
Разделени со запирки." + + general_fields: Основни полиња + special_fields: Специјални полиња + + debug: Режим за дебагирање + debug_sub: Оневозможи праќање на пораки, прикажи ја p01-contact структурата на податоци, податоците пратени со POST и email-от кој би бил испратен. + debug_warn: Не активирајте на функционална web страна! diff --git a/plugins/PicoContact/lang/nl.yml b/plugins/PicoContact/lang/nl.yml new file mode 100644 index 0000000..6f08ffe --- /dev/null +++ b/plugins/PicoContact/lang/nl.yml @@ -0,0 +1,94 @@ +--- +# Dutch language file for p01-contact +key: nl +name: Dutch +english_name: Dutch +authors: Thomas Stolwijk +date: "2011-10-27" +compatibility: 1.1 +strings: + # fields + name: Naam + email: Email + address: Postadres + tel: Telefoonnummer + url: Website + subject: Onderwerp + message: Bericht + file: Attachment + captcha: Captcha + reload: Herlaad + fieldcaptcha: "Vul alstublieft niet het volgende veld in :" + askcopy: Stuur mij een kopie van dit bericht + send: Verstuur + + # email words + askedcopy: Een kopie van deze mail is aangevraagd + anonymous: Anoniem + nosubject: (Geen onderwerp) + email_title: Mail verstuurd vanaf + + # status messages + sent: Bericht verzonden. + error: "Fout : het bericht is niet verzonden." + disable: De contactplugin is uitgeschakeld. + error_notarget: Dit contactformulier heeft geen ontvanger. + token: Dit bericht is al verstuurd. + + + # fields errors + field_required: Dit veld is verplicht + field_email: Voer alstublieft een geldig email-adres in + field_tel: Voer alstublieft een geldig telefoonnummer in + field_url: Voer alstublieft een geldig webadres in + field_message: Schrijf alstublieft een langer bericht + field_captcha: Kopieer alstublieft de volgende tekst + field_fieldcaptcha: Vult u alstublieft dit veld niet in + field_password: Verkeerd wachtwoord + + # configuration panel + + config_title: p01contact configuratie + + # messages + config_updated: Uw wijzigingen zijn opgeslagen. + + config_error_open: "Kan het configuratiebestand niet openen. Controleer of het bestand bestaat en de toegangsrechten erop :" + + config_error_modify: "Kan het configuratiebestand niet wijzigen. Controleer de toegangsrechten op het bestand :" + + # New release alert + new_release: Er is een nieuwe versie uitgebracht! + download: Download de nieuwste versie + + # Links + doc: Documentatie + forum: Forum + + # Parameters + enable: Inschakelen + enable_sub: Schakelt sturen van mail aan of uit (het formulier blijft zichtbaar). + + default_email: Standaardinstelling emailadres + default_email_sub: Laat leeg om de standaardinstelling te gebruiken + + lang: Taal + lang_sub: Taal standaard ingesteld op + + default_params: Standaardinstelling parameters + default_params_sub: Standaard formulierstructuur. Gebruik de syntax zoals bescheven in de documentatie. + + message_len: Minimum berichtlengte + message_len_sub: Minimum aantal karakters voor berichtvelden. + + checklists: Veldchecklist + blacklist: Blacklist + whitelist: Whitelist + checklists_sub: "Blacklist : waarden die niet in het veld mogen voorkomen om het berichte te kunnen versturen.
Whitelist : waarden waarvan er een in het veld moet voorkomen om het bericht te kunnen versturen.
Gescheiden door komma's." + + general_fields: Algemene fields + special_fields: Speciale fields + + debug: Debugmodus + debug_sub: Schakel mail sturen uit, toon datastructuur van p01-contact, data verstuurd met het POST-request en de mail die verstuurd zou zijn. + debug_warn: Schakel dit niet in op een website die in bedrijf is! diff --git a/plugins/PicoContact/lang/no.yml b/plugins/PicoContact/lang/no.yml new file mode 100644 index 0000000..a4fd7cb --- /dev/null +++ b/plugins/PicoContact/lang/no.yml @@ -0,0 +1,41 @@ +--- +# Norwegian language file for p01-contact +key: "no" +name: Norwegian +english_name: Norwegian +authors: Tor Rafsol Løseth +date: "2011-10-27" +compatibility: 1.1 +strings: + # fields + name: Navn + email: E-post adresse + address: Adresse + tel: Tel. nummer + url: Nettside + subject: Emne + message: Melding + file: Bilag + captcha: Captcha + reload: Nytt bilde + askcopy: Send en kopi till meg selv + send: Send + + # email words + anonymous: Anonym + nosubject: (Intet emne) + email_title: E-post sendt i fra + + # status messages + sent: E-post sendt. + error: "Feil : Ingen melding er sendt." + disable: Kontaktskjemaet er ute av funksjon. + error_notarget: Kontaktskjemaet har ingen mottager. + + # fields errors + field_required: Dette feltet må fylles ut + field_email: Vennligst bruk en korrekt e-post adresse + field_tel: Vennligst bruk ett korrekt telefon nummer + field_url: Vennligst bruk en korrekt nettside adresse + field_message: Meldingen er for kort. + field_captcha: Kopier bokstavene diff --git a/plugins/PicoContact/lang/pl.yml b/plugins/PicoContact/lang/pl.yml new file mode 100644 index 0000000..92eb63b --- /dev/null +++ b/plugins/PicoContact/lang/pl.yml @@ -0,0 +1,95 @@ +--- +# Polish language file for p01-contact +key: pl +name: Polish +english_name: Polish +authors: barlew +date: "2011-10-27" +compatibility: 1.1 +strings: + # fields + name: Imię i nazwisko + email: Email + address: Adres + tel: Telefon + url: Strona www + subject: Temat + message: Wiadomość + file: Załącznik + captcha: Captcha + reload: Załaduj ponownie + fieldcaptcha: "Proszę nie wypełniać tych pól:" + askcopy: Wyślij kopię wiadomości do mnie + send: Wyślij + + # email words + askedcopy: A copy of this email have been requested + anonymous: Anonymous + nosubject: (bez tematu) + email_title: Wiadomość wysłana z + + # status messages + sent: Wiadomość została wysłana! + error: "Błąd: wiadomość nie została wysłana." + disable: Formularz kontaktowy jest wyłączony. + error_notarget: Nie określono odbiorcy dla tego formularza. + token: The message have already been sent. + + # fields errors + field_required: Wypełnienie tego pola jest wymagane + field_email: Wprowadź prawidłowy adres email + field_tel: Wprowadź prawidłowy numer telefonu + field_url: Wprowadź prawidłowy adres www + field_message: Tekst wiadomości jest zbyt krótki + field_captcha: Skopiuj następujący tekst + field_fieldcaptcha: Proszę nie wypełniać tego pola + field_password: Hasło nieprawidłowe + + # configuration panel + + config_title: Konfiguracja p01-contact + default: Domyślnie + save: Zapisz + + # messages + config_updated: Twoje ustawienia zostały pomyślnie zapisane. + + config_error_open: "Nie można otworzyć pliku konfiguracyjnego. Sprawdź czy plik istnieje oraz ustawienia do jego zapisu:" + + config_error_modify: "Nie można zmodyfikować pliku konfiguracyjnego. Sprwdź ustawienia uprawnień tego pliku:" + + # New release alert + new_release: Nowa wersja jest dostępna! + download: Pobierz najnowszą wersję. + + # Links + doc: Dokumentacja + forum: Forum + + # Parameters + enable: Włączony + enable_sub: Włącza lub wyłącza wysyłanie maili (nie ukrywa formularza kontaktowego). + + default_email: Domyślny adres email + default_email_sub: Pozostaw to pole puste, aby wysyłać maile do + + lang: Język + lang_sub: Język domyślny ustawiony jako + + default_params: Ustawienia domyślne + default_params_sub: Domyślna struktura formularza. W celu modyfikacji proszę zapoznać się z dokumentacją. + + message_len: Minimalna długość tekstu wiadomości + message_len_sub: Określa minimalną liczbę znaków dla tekstu wiadomości. + + checklists: Sprawdzanie zawartości pól formularza + blacklist: Zabronione + whitelist: Dozwolone + checklists_sub: "Zabronione: słowa, które nie mogą występować w polach formularza.
Dozwolone: słowa, które mogą występować w polach formularza.
Oddzielone przecinkami." + + general_fields: Pola ogólne + special_fields: Pola specjalne + + debug: Tryb debug + debug_sub: Wyłącza wysyłanie maili, wyświetla strukturę danych p01-contact oraz mail, który byłyby wysłany przez funkcję POST. + debug_warn: Nie włączać na stronie produkcyjnej! diff --git a/plugins/PicoContact/lang/pt.yml b/plugins/PicoContact/lang/pt.yml new file mode 100644 index 0000000..2bac9df --- /dev/null +++ b/plugins/PicoContact/lang/pt.yml @@ -0,0 +1,126 @@ +--- +# Portuguese language file for p01contact +key: pt +name: Português +english_name: Portuguese +authors: Julianna Brandão (JuhBass), Rafael Capaci +date: "2017-11-01" +compatibility: 1.1 +strings: + # basic fields + text: texto + textarea: campo de texto + password: senha + file: arquivo + # html5 inputs types + color: cor + date: data + email: e-mail + month: mês + number: número + range: valor + search: busca + tel: número de telefone + time: hora + url: URL + week: semana + # other fields + name: nome + subject: assunto + message: mensagem + address: endereço postal + askcopy: me envie uma cópia deste e-mail + captcha: captcha + # actions + send: Enviar + reload: Recarregar + reset: Apagar este campo + # received email + askedcopy: Uma cópia deste e-mail foi requisitada + anonymous: Anônimo + nosubject: (Sem assunto) + email_title: E-mail enviado de + # confirmations + sent: E-mail enviado. + sent_debug: E-mail virtualmente enviado (modo de depuração habilitado). + sent_copy: E-mail enviado. Uma cópia foi enviada para o endereço especificado. + sent_copy_error: E-mail enviado, mas houve uma problema ao te enviar uma cópia. + sent_already: A mensagem já foi enviada. + # errors + error: "Erro : a mensagem não foi enviada." + error_notarget: Este campo de contato encontra-se vazio. + error_honeypot: Blip. Blop. Blup. Você caiu no "pote de mel" para robôs. + error_pageload: Blip. Blop. Blup. Você é tão rápido quanto um robô. Por favor, espere alguns segundos. + error_lastpost: Você enviou recentemente. Por favor, aguarde um pouco. + error_postcount: Você enviou muitas vezes na última hora. + # fields errors + field_required: Este campo é necessário + field_email: Por favor, utilize um endereço de e-mail válido + field_tel: Por favor, utilize um número de telefone válido + field_url: Por favor, escreva um endereço web válido + field_message: Por favor, escreva uma mensagem mais longa + field_captcha: Por favor, responda corretamente o captha a seguir + field_password: Senha errada + field_blacklist: Este campo contém termos proibidos + field_whitelist: Um valor esperado está faltando + # configuration panel + config_title: configuração do p01contact + config_updated: Suas alterações foram salvas com sucesso. + config_error_open: Não foi possível abrir o arquivo de configuração. Verifique se o arquivo existe e se possue as devidas permissões + config_error_modify: Não foi possível modificar o arquivo de configurações. Verifique as permissões do arquivo" + # infos + new_release: Há uma nova versão! + download: Baixe a última versão + repo: Github + wiki: Documentação / Wiki + issues: Ajuda / reporte um erro + + # settings + + disable: Desabilitar todos os campos + disable_sub: Desabilitar envio de e-mails, sem esconder os campos de contato. + + default_email: E-mails padrão + default_email_sub: Um ou mais endereços de e-mail, separados por vírgula, que receberão e-mails de todos os formulários. + + default_params: Parâmetros padrões + default_params_sub: Estrutura de campos padrão. Use a sintaxe descrita na documentação. + + lang: Idioma + lang_sub: Idioma padrão está configurado para + + message_len: Tamanho mínimo das mensagens + message_len_sub: Número mínimo de caracteres para os cmapos de mensagem. + + separator: Separador + separator_sub: "Separador de parâmetros nos campos. Ex: vírgula, ponto e vírgula, barra dupla..." + + logs_count: Número do log + logs_count_sub: Máximo número de entradas a serem mantidas nos logs. + + checklists: Lista de verificação de campos + blacklist: Lista negra + whitelist: Lista branca + checklists_sub: Uma lista negra é uma lista de valores proibidos no tipo de campo em questão, e uma lista branca é uma lista dos únicos valores possíveis para certo tipo de campo. Cada termo deve ser separado por vírgulas. + + use_honeypot: Use campo de "pote de mel" escondido + use_honeypot_sub: Adicionar a todos os campos um campo escondido que não deve ser preenchido. Humanos não o enxergarão, mas a maioria dos robôs de spam cairão na armadilha. + + min_sec_after_load: Tempo mínimo após o carregamento da página + min_sec_after_load_sub: Mínimo número de segundos entre uma carregamento de uma página e uma submissão de um formulário. Humanos necessitam de pelo menos alguns segundos para ler, preencher e enviar um formulário. Robôs não. + + min_sec_between_posts: Tempo mínimo entre duas submissões + min_sec_between_posts_sub: Mínimo número de segundos entre a submissão de dois formulários pelo mesmo usuário. + + max_posts_by_hour: Número máximo de submissões por hora + max_posts_by_hour_sub: Número máximo de submissões por hora por usuário. + + captcha_info: Os mecanismos nativos de anti-spam e anti-erro devem prevenir todas as submissões não desejadas. Se precisar de um nível maior de segurança, você pode criar um captcha customizado ao adicionar um campo com a resposta requerida. Finalmente, você pode inserir um Google reCaptcha ao usar um campo captcha com as configurações a baixo. + recaptcha_public_key: chave pública do reCaptcha + recaptcha_public_key_sub: chave pública do Google reCaptcha. + recaptcha_secret_key: chave secreta do reCaptcha + recaptcha_secret_key_sub: chave secreta do Google reCaptcha. + + debug: Modo de depuração + debug_sub: Desabilitar o envio de e-mails, mostrar a estrutura de dados do p01-contact, os dados enviador por POST e o e-mail que deveria ser enviado. + debug_warn: não ative num site em produção! diff --git a/plugins/PicoContact/lang/ro.yml b/plugins/PicoContact/lang/ro.yml new file mode 100644 index 0000000..5b98cfd --- /dev/null +++ b/plugins/PicoContact/lang/ro.yml @@ -0,0 +1,93 @@ +--- +# Romanian language file for p01-contact +key: ro +name: Romanian +english_name: Romanian +authors: Alexandru Cuciureanu +date: "2011-10-27" +compatibility: 1.1 +strings: + # fields + name: Nume + email: Email + address: Adresa postala + tel: Numar telefon + url: Website + subject: Subiect + message: Mesaj + file: Atasament + captcha: Captcha + reload: Reincarcare + fieldcaptcha: "Te rog sa nu completezi urmatorul spatiu :" + askcopy: Trimite-mi o copie al acestui email + send: Trimite + + # email words + askedcopy: A fost solicitata o copie al acestui email + anonymous: Anonim + nosubject: (Fara subiect) + email_title: Mesaj trimis de + + # status messages + sent: Mesajul a fost trimis. + error: "Eroare : mesajul nu a fost trimis." + disable: Formularele de contact sunt dezactivate. + error_notarget: Acest formular de contact nu are un recipient. + token: Mesajul a fost deja trimis. + + # fields errors + field_required: Acest spatiu trebuie completat + field_email: Te rog sa completezi o adresa de email valida + field_tel: Te rog sa folosesti un numar de telefon valid + field_url: Te rog sa introduci o adresa de web valida + field_message: Te rog sa scrii un mesaj mai lung + field_captcha: Te rog copiaza urmatorul text + field_fieldcaptcha: Te rog sa nu completezi urmatorul spatiu + field_password: Parola gresita + + # configuration panel + + config_title: Configurare p01contact + + # messages + config_updated: Schimbarile tale au fost salvate. + + config_error_open: "Nu a putut fi deschis fisierul de configurare. Verifica daca fisierul exista sau daca ai permisiunile corecte :" + + config_error_modify: "Nu a putut fi modificat fisierul de configurare. Verifica permisiunile :" + + # New release alert + new_release: Exista o noua versiune! + download: Descarca ultima versiune + + # Links + doc: Documentatie + forum: Forum + + # Parameters + enable: Activeaza + enable_sub: Activeaza sau dezactiveaza trimiterea de email (nu ascunde formularul de contact). + + default_email: Emailul implicit + default_email_sub: Lasa spatiu gol pentru a seta ca + + lang: Limba + lang_sub: Limba implicita este setata ca + + default_params: Parametri impliciti + default_params_sub: Etichete implicite in formular. Foloseste sintaxa din documentatie. + + message_len: Lungimea minima a mesajului + message_len_sub: Numarul minim de caractere pentru spatiile destinate mesajelor + + checklists: Casute pentru bifat + blacklist: Blacklist + whitelist: Whitelist + checklists_sub: "Blacklist : cuvinte care nu trebuie sa apara in email.
Whitelist : posibile cuvinte care ar trebui sa apara in email.
Separate de virgula." + + general_fields: Campuri generale + special_fields: Campuri speciale + + debug: Mod Debug + debug_sub: Dezactiveaza trimiterea mesajului, afiseaza structura de date p01-contact, date trimise prin POST si email care a fost trimis. + debug_warn: Nu activa siteul in productie! diff --git a/plugins/PicoContact/lang/ru.yml b/plugins/PicoContact/lang/ru.yml new file mode 100644 index 0000000..1c79f77 --- /dev/null +++ b/plugins/PicoContact/lang/ru.yml @@ -0,0 +1,93 @@ +--- +# Russian language file for p01-contact +key: ru +name: Russian +english_name: Russian +authors: Stanislav Ulver +date: "2011-10-27" +compatibility: 1.1 +strings: + # fields + name: Ваше имя + email: E-mail + address: Почтовый адрес + tel: Номер телефона + url: Сайт + subject: Тема + message: Сообщение + file: Прикрепить файл + captcha: Код безопасности + reload: Обновить + fieldcaptcha: "Пожалуйста, не заполняйте следующие поля :" + askcopy: Отправить мне копию этого сообщения + send: Отправить + + # email words + askedcopy: Копия этого письма была запрошена + anonymous: Анонимно + nosubject: (Без темы) + email_title: "Отправитель:" + + # status messages + sent: E-mail отправлен. + error: "Ошибка: сообщение не было отправлено." + disable: Контактный плагин отключен. + error_notarget: Не указан получатель. + token: Это сообщение уже было отправлено. + + # fields errors + field_required: Обязательное поле + field_email: Неверно указан e-mail адрес + field_tel: Неверно указан номер телефона + field_url: Неверно указан веб-адрес + field_message: Ваше сообщение слишком короткое + field_captcha: Код безопасности не соответствует отображённому + field_fieldcaptcha: Пожалуйста не заполняйте это поле + field_password: Неправильный пароль + + # configuration panel + + config_title: p01contact конфигурация + + # messages + config_updated: Изменения сохранены. + + config_error_open: "Никак не открыть конфигурационный файл. Проверьте его существование и права доступа к нему :" + + config_error_modify: "Не удается модифицировать конфигурационный файл. Проверьте права доступа к нему :" + + # New release alert + new_release: Это новая версия! + download: Скачать последнюю версию + + # Links + doc: Документация + forum: Форум + + # Parameters + enable: Включено + enable_sub: Включить или выключить отправку е-mail сообщения (не скрывает контактную форму). + + default_email: email по умолчанию + default_email_sub: Оставьте пустым для установки + + lang: Язык + lang_sub: Язык по умолчанию установлен в + + default_params: Параметры по умолчанию + default_params_sub: Структура тегов формы. Используйте синтаксис описанный в документации. + + message_len: Минимальная длинна сообщения + message_len_sub: Минимальное количество символов для поля сообщения. + + checklists: Проверочный список полей + blacklist: Черный список + whitelist: Белый список + checklists_sub: "Черный список: значения, при которых отправка письма не произойдет.
Белый список: значения, которые требуются для отправки письма.
Элементы разделяются запятыми." + + general_fields: Основные поля + special_fields: Специальные поля + + debug: Режим отладки + debug_sub: Отключается отправка емайл сообщения, на экране отображается p01-contact структура данных, и данные которые были бы посланы по электронной почте. + debug_warn: Не включайте на рабочем сайте! diff --git a/plugins/PicoContact/lang/sk.yml b/plugins/PicoContact/lang/sk.yml new file mode 100644 index 0000000..4e42ba3 --- /dev/null +++ b/plugins/PicoContact/lang/sk.yml @@ -0,0 +1,94 @@ +--- +# Slovak language file for p01-contact +key: sk +name: Slovak +english_name: Slovak +authors: Ján Maras +date: "2011-10-27" +compatibility: 1.1 +strings: + # fields + name: Meno + email: Email + address: Poštová adresa + tel: Telefón + url: WWW + subject: Predmet + message: Správa + file: Príloha + captcha: Captcha + reload: Načítať nový + fieldcaptcha: "Prosím nevypĺňajte nasledovné polia :" + askcopy: Pošlite mi kópiu tohto e-mailu + send: Odoslať + + # email words + askedcopy: Kópia tohoto emailu bola vyžiadaná + anonymous: Anonym + nosubject: Správa z kontaktného formulára + email_title: Mail odoslaný z + + # status messages + sent: Správa odoslaná. + error: "Chyba : správa nebola odoslaná." + disable: Kontaktný formulár je vypnutý. + error_notarget: Tento kontaktný formulár nemá príjemcu. + token: Správa už bola odoslaná. + + # fields errors + field_required: Toto pole je povinné + field_email: Prosím, zadajte platný email + field_tel: Prosím zadajte platné tel. číslo + field_url: Prosím, zadajte platnú www adresu + field_message: Prosím, zadajte dlhšiu správu + field_captcha: Prosím, skopírujte nasledujúci text + field_fieldcaptcha: Prosím, nevypĺňajte toto pole + field_password: Zlé heslo + + # configuration panel + + config_title: p01contact nastavenie + + # messages + config_updated: Vaše zmeny sú úspešne uložené. + + config_error_open: "Nemožno otvoriť konfiguračný súbor. Skontrolujte, či súbor existuje a či je povolené zapisovanie do súboru :" + + config_error_modify: "Nemožno zmeniť konfiguračný súbor. Skontrolujte práva na zápis do súboru:" + + # New release alert + new_release: K dispozícii je nová verzia! + download: Stiahnite si poslednú verziu + + # Links + doc: Dokumentácia + forum: Fórum + + # Parameters + enable: Povoliť + enable_sub: Povoliť, alebo zakaázať odosielanie pošty (zaškrtnutím povolíte obrazenie formulára). + + default_email: Predvolený email + default_email_sub: Ak ponecháte prázdne, bude nastavené na + + lang: Jazyk + lang_sub: Predvolený jazyk je nastavený na + + default_params: Predvolené parametre + default_params_sub: Predvolené tagy štruktúry formulára. Použite syntax popísanú v dokumentácii. + + message_len: Minimálna dĺžka správy + message_len_sub: Minimálny počet znakov pre položku správa. + + checklists: Zozna polí + blacklist: Blacklist + whitelist: Whitelist + checklists_sub: "Blacklist : hodnoty, ktoré nesmú byť prítomné v poli.
Whitelist : hodnoty, ktoré musia byť prítomné v poli.
Oddelené čiarkou." + + general_fields: Všeobecné polia + special_fields: Špeciálne polia + save: Uložiť + + debug: Debug mode + debug_sub: Disable mail sending, display p01-contact data structure, data sent by POST and the email that would have been sent. + debug_warn: Don\'t active that on production website! diff --git a/plugins/PicoContact/lang/sr.yml b/plugins/PicoContact/lang/sr.yml new file mode 100644 index 0000000..352b378 --- /dev/null +++ b/plugins/PicoContact/lang/sr.yml @@ -0,0 +1,93 @@ +--- +# Serbian language file for p01-contact +key: sr +name: Serbian +english_name: Serbian +authors: lemi667 +date: "2011-10-27" +compatibility: 1.1 +strings: + # fields + name: Ime + email: Email + address: Adresa + tel: Broj telefona + url: Website + subject: Tema + message: Poruka + file: Dodatak + captcha: Captcha + reload: Učitaj ponovo + fieldcaptcha: "Molimo nemojte popunjavati sledeće polje :" + askcopy: Pošalji mi kopiju ove poruke + send: Pošalji + + # email words + askedcopy: Kopija ove poruke je zatražena + anonymous: Anonimno + nosubject: (No subject) + email_title: Mail poslao + + # status messages + sent: Email poslat. + error: Greška u slanju poruke. + disable: Formulari za kontakt su onemogućeni. + error_notarget: Ovaj formular nema adresu za prijem. + token: Poruka je već poslata. + + # fields errors + field_required: Ovo polje je obavezno + field_email: Molimo koristite validnu email adresu + field_tel: Molimo koristite validan broj telefona + field_url: Molimo koristite validnu web adresu + field_message: Molimo upišite dužu poruku + field_captcha: Molimo kopirajte sledeći tekst + field_fieldcaptcha: Molimo da ne popunjavate ovo polje + field_password: Pogrešna lozinka + + # configuration panel + + config_title: p01contact konfiguracija + + # messages + config_updated: Vaše promene su sačuvane. + + config_error_open: "Nije moguće otvoriti konfiguracioni fajl. Proverite da li fajl postoji i dozvole za pristup :" + + config_error_modify: "Nije moguće modifikovati konfiguracioni fajl. Proverite dozvole za pristup :" + + # New release alert + new_release: Postoji nova verzija! + download: Preuzmite najnoviju verziju + + # Links + doc: Dokumentacija + forum: Forum + + # Parameters + enable: Omogući + enable_sub: Omogući/onemogući slanje poruka (ne sakriva kontakt formular). + + default_email: Podrazumevani email + default_email_sub: "Ostavite prazno da bi podesili:" + + lang: Jezik + lang_sub: Podrazumevani jezik je + + default_params: Podrazumevani parametri + default_params_sub: Podrazumevani tag iz strukture. Koristite sintaksu opisanu u dokumentaciji. + + message_len: Minimalna dužina poruke + message_len_sub: Minimalan broj karaktera za polje poruke. + + checklists: Kontrolna lista polja + blacklist: Crna lista + whitelist: Bela lista + checklists_sub: "Crna lista : vrednosti koje ne smeju biti prisutne da bi poruka bila poslata.
Bela lista : moguće vrednosti potrebne u polju da bi poruka bila poslata.
Odvojeno zarezima." + + general_fields: Opšta polja + special_fields: Specijalna polja + + debug: Debug režim + debug_sub: Onemogućuje slanje poruke, prikazuje p01-contact strukturu podataka, podaci poslati putem POST i poruka koja bi bila poslata. + debug_warn: Nemojte ovo aktivirati na sajtu koji je u funkciji! diff --git a/plugins/PicoContact/lang/sv.yml b/plugins/PicoContact/lang/sv.yml new file mode 100644 index 0000000..e2d06e4 --- /dev/null +++ b/plugins/PicoContact/lang/sv.yml @@ -0,0 +1,40 @@ +--- +# Swedish language file for p01-contact +key: sv +name: Swedish +english_name: Swedish +authors: Göran Söderberg +date: "2011-10-27" +compatibility: 1.1 + # fields + name: Namn + email: Email-adress + address: Adress + tel: Tel. nummer + url: Hemsida + subject: Ämne + message: Meddelande + file: Bilaga + captcha: Captcha + reload: Ny bild + askcopy: Skicka en kopia till mig själv + send: Send + + # email words + anonymous: Anonym + nosubject: (Inget ämne) + email_title: Mail skickat från + + # status messages + sent: Email skickat. + error: "Fel : Inget meddelande skickades." + disable: Kontaktformuläret är ur funktion. + error_notarget: Kontaktformuläret har ingen mottagare. + + # fields errors + field_required: Detta fält måste fyllas i + field_email: Vänligen använd en riktig mail-adress + field_tel: Vänligen använd ett riktigt telefonnummer + field_url: Vänligen skriv en korrekt hemsida + field_message: Meddelandet är för kort. + field_captcha: Kopiera bokstäverna diff --git a/plugins/PicoContact/src/P01contact.php b/plugins/PicoContact/src/P01contact.php new file mode 100644 index 0000000..a13a8fe --- /dev/null +++ b/plugins/PicoContact/src/P01contact.php @@ -0,0 +1,476 @@ +version = VERSION; + + define('P01C\SERVERNAME', $_SERVER['SERVER_NAME']); + define('P01C\SERVERPORT', $_SERVER['SERVER_PORT']); + define('P01C\SCRIPTNAME', $_SERVER['SCRIPT_NAME']); + define('P01C\SCRIPTPATH', get_included_files()[0]); + + define('P01C\HTTPS', !empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off'); + define('P01C\PORT', SERVERPORT && SERVERPORT != 80 && SERVERPORT != 443 ? ':'.SERVERPORT : ''); + define('P01C\PROTOCOL', HTTPS || SERVERPORT == 443 ? 'https' : 'http'); + define('P01C\SERVER', PROTOCOL . '://' . SERVERNAME . PORT); + define('P01C\PAGEURI', $_SERVER['REQUEST_URI']); + define('P01C\PAGEURL', SERVER . PAGEURI); + + define('P01C\PATH', dirname(__DIR__) . '/'); + define('P01C\ROOT', str_replace(SCRIPTNAME,'', SCRIPTPATH)); + define('P01C\RELPATH', str_replace(ROOT, '', PATH)); + + define('P01C\LANGSPATH', PATH . 'lang/'); + define('P01C\TPLPATH', PATH . 'src/templates/'); + define('P01C\CONFIGPATH', PATH . 'config.json'); + define('P01C\LOGPATH', PATH . 'log.json'); + + define('P01C\REPOURL', 'https://github.com/nliautaud/p01contact'); + define('P01C\WIKIURL', 'https://github.com/nliautaud/p01contact/wiki'); + define('P01C\ISSUESURL', 'https://github.com/nliautaud/p01contact/issues'); + define('P01C\APILATEST', 'https://api.github.com/repos/nliautaud/p01contact/releases/latest'); + + $this->loadConfig(); + $this->loadLangs(); + + if ($this->config('debug')) { + $this->enablePHPdebug(); + } + + Session::stack('pageloads', time()); + } + + /** + * Query the releases API and return the new release infos, if there is one. + * + * @see https://developer.github.com/v3/repos/releases/#get-the-latest-release + * @return object the release infos + */ + public function getNewRelease() + { + $ch = curl_init(); + curl_setopt($ch, CURLOPT_URL, APILATEST); + curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); + curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 1); + curl_setopt($ch, CURLOPT_USERAGENT, 'p01contact/curl'); + $resp = curl_exec($ch); + curl_close($ch); + if ($resp) { + return json_decode($resp); + } + return; + } + + /** + * Parse a string to replace tags by forms + * + * Find tags, create forms structures, check POST and modify string. + * @param string $contents the string to parse + * @return string the modified string + */ + public function parse($contents) + { + $sp = '(?:\s|)*'; + $pattern = "`(?)\(%\s*contact\s*(\w*)\s*:?$sp(.*?)$sp%\)`s"; + preg_match_all($pattern, $contents, $tags, PREG_SET_ORDER); + + foreach ($tags as $tag) { + $form = $this->newForm($tag[2], $tag[1]); + $contents = preg_replace($pattern, $form, $contents, 1); + } + return $contents; + } + /** + * Return a form based on the given parameters and lang + * + * @param string $params the parameters string, according to the syntax + * @param string $lang form-specific language code + * @return string the html form + */ + public function newForm($params = '', $lang = null) + { + $defaultStyle = ''; + static $once; + if (!$once) { + $defaultStyle = ''; + $once = true; + } + $form = new P01contactForm($this); + $form->parseTag($params); + if ($lang) { + $form->lang = $lang; + } + $form->post(); + + return $defaultStyle . $form->html(); + } + + /** + * Display system and P01contact infos. + * + * @return string the html report + */ + public function debugReport() + { + $out = '

p01-contact debug

'; + + $out.= '

Health :

'; + $health = 'PHP version : '.phpversion()."\n"; + $health.= 'PHP mbstring (UTF-8) : '.(extension_loaded('mbstring') ? 'OK' : 'MISSING'); + $out.= preint($health, true); + + $out.= '

Constants :

'; + $constants = get_defined_constants(true)['user']; + $filteredConstants = array_filter(array_keys($constants), function ($key) { + return 0 === strpos($key, __namespace__); + }); + $filteredConstants = array_intersect_key($constants, array_flip($filteredConstants)); + $out .= preint($filteredConstants, true); + + $out .= Session::report(); + + if (!empty($_POST)) { + $out.= '

$_POST :

'; + $out.= preint($_POST, true); + } + $out.= '

$p01contact :

'; + $out.= preint($this, true); + return $out; + } + /** + * Enable PHP error reporting + */ + public function enablePHPdebug() + { + ini_set('display_errors', 1); + ini_set('display_startup_errors', 1); + error_reporting(E_ALL); + } + + + /* + * LANG + */ + + + /** + * Load language files + */ + private function loadLangs() + { + $this->langs = []; + $files = glob(LANGSPATH . '*.yml'); + foreach ($files as $f) { + $parsed = \Spyc::YAMLLoad($f); + if (!$parsed || !isset($parsed['key'])) { + continue; + } + $this->langs[$parsed['key']] = $parsed; + } + } + /** + * Return a traduction of the keyword + * + * Manage languages between requested langs and existing traductions. + * @param string $key the keyword + * @return string + */ + public function lang($key, $lang = null) + { + $default = !empty($this->default_lang) ? $this->default_lang : 'en'; + + if (!$lang) { + $lang = $this->config('lang'); + } + + if (empty($lang) + || !isset($this->langs[$lang]) + || !isset($this->langs[$lang]['strings'][$key])) { + $lang = $default; + } + + $strings = $this->langs[$lang]['strings']; + if (!empty($strings[$key])) { + return trim($strings[$key]); + } + return ucfirst($key); + } + /** + * Return the languages objects + * @return array + */ + public function langs() + { + return $this->langs; + } + + + /* + * CONFIG + */ + + + /** + * Load the JSON configuration file. + */ + private function loadConfig() + { + $content = file_exists(CONFIGPATH) ? file_get_contents(CONFIGPATH) : null; + $this->config = $content ? json_decode($content) : (object) array(); + $this->setDefaultConfig(); + } + + /** + * Set the obligatory settings if missing. + */ + private function setDefaultConfig() + { + $default = array( + 'default_params' => 'name!, email!, subject!, message!', + 'separator' => ',', + 'logs_count' => 10, + 'use_honeypot' => true, + 'min_sec_after_load' => '3', + 'max_posts_by_hour' => '10', + 'min_sec_between_posts' => '5', + ); + foreach ($default as $key => $value) { + if (empty($this->config->{$key})) { + $this->config->{$key} = $value; + } + } + } + + /** + * Add an entry to the logs. + */ + public function log($data) + { + if (!$this->config('logs_count')) { + return; + } + $logs = json_decode(@file_get_contents(LOGPATH)); + $logs[] = $data; + $max = max(0, intval($this->config('logs_count'))); + + while (count($logs) > $max) { + array_shift($logs); + } + $this->updateJSON(LOGPATH, $logs); + } + + /** + * Update a JSON file with new data. + * + * @param string $file_path the config file path + * @param array $new_values the new values to write + * @param array $old_values the values to change + * @return boolean file edition sucess + */ + private function updateJSON($path, $new_values) + { + if ($file = fopen($path, 'w')) { + fwrite($file, json_encode($new_values, JSON_PRETTY_PRINT)); + fclose($file); + return true; + } return false; + } + /** + * Return a setting value from the config. + * @param mixed $key the setting key, or an array as path to sub-key + * @return mixed the setting value + */ + public function config($key) + { + if (!is_array($key)) { + $key = array($key); + } + $curr = $this->config; + foreach ($key as $k) { + if (is_numeric($k)) { + $k = intval($k); + if (!isset($curr[$k])) { + return; + } + $curr = $curr[$k]; + } else { + if (!isset($curr->$k)) { + return; + } + $curr = $curr->$k; + } + $k = $curr; + } + return $k; + } + + + /* + * TEMPLATES + */ + + + /** + * Return a template file content + */ + public function getTemplate($name) + { + static $cache; + if (isset($cache[$name])) { + return $cache[$name]; + } + if (!isset($cache)) { + $cache = array(); + } + $cache[$name] = @file_get_contents(TPLPATH . $name . '.html'); + return $cache[$name]; + } + + /** + * Set the obligatory settings if missing. + */ + public function renderTemplate($name, $data) + { + $html = $this->getTemplate($name); + // config + $html = preg_replace_callback('`config\((.+)\)`', function ($matches) { + return $this->config(explode(',', $matches[1])); + }, $html); + // lang + $html = preg_replace_callback('`{{lang\.(\w+)}}`', function ($matches) { + return $this->lang($matches[1]); + }, $html); + // constants + $html = preg_replace_callback('`{{([A-Z]{3,})}}`', function ($matches) { + return constant(__namespace__.'\\'.$matches[1]); + }, $html); + // data + $html = preg_replace_callback('`{{(\w+)}}`', function ($matches) use ($data) { + return @$data->{$matches[1]}; + }, $html); + return $html; + } + + + /* + * PANEL + */ + + + /** + * Save settings if necessary and display configuration panel content + * Parse and replace values in php config file by POST values. + */ + public function panel() + { + if (isset($_POST['p01-contact']['settings'])) { + $success = $this->updateJSON(CONFIGPATH, $_POST['p01-contact']['settings']); + $this->loadConfig(); + + if ($success) { + $msg = '
' . $this->lang('config_updated') . '
'; + } else { + $msg = '
'.$this->lang('config_error_modify'); + $msg.= '
'.CONFIGPATH.'
'; + } + return $msg . $this->panelContent(); + } + return $this->panelContent(); + } + + /** + * Return configuration panel content, replacing the following in the template : + * + * - lang(key) : language string + * - config(key,...) : value of a config setting + * - other(key) : other value pre-defined + * - VALUE : constant value + * + * @return string + */ + private function panelContent($system = 'gs') + { + $debug = $this->config('debug'); + $tpl_data = (object) null; + $tpl_data->disablechecked = $this->config('disable') ? 'checked="checked" ' : ''; + $tpl_data->debugchecked = $debug ? 'checked="checked" ' : ''; + $tpl_data->honeypotchecked = $this->config('use_honeypot') ? 'checked="checked" ' : ''; + $tpl_data->default_lang = $this->default_lang; + $tpl_data->version = $this->version; + + $list = $this->config('checklist'); + if ($list) { + foreach ($list as $i => $cl) { + $bl = 'cl'.$i.'bl'; + $wl = 'cl'.$i.'wl'; + $tpl_data->$bl = isset($cl->type) && $cl->type == 'whitelist' ? '' : 'checked'; + $tpl_data->$wl = $tpl_data->$bl ? '' : 'checked'; + } + } + + $lang = $this->config('lang'); + $tpl_data->langsoptions = ''; + foreach ($this->langs() as $language) { + $tpl_data->langsoptions .= ''; + } + + $html = $this->renderTemplate($system.'_settings', $tpl_data); + + //new release + $infos = ''; + if ($response = $this->getNewRelease()) { + if ($debug && isset($response->message)) { + $infos .= '
New release check error debug : Github '; + $infos .= $response->message . '
'; + } + if (isset($response->url) && version_compare($response->tag_name, $this->version) > 0) { + $infos .= '
' . $this->lang('new_release'); + $infos .= '
'; + $infos .= $this->lang('download') . ' (' . $response->tag_name . ')
'; + } + } + + $logsblock = $this->logsTable(); + + return $infos . $html . $logsblock; + } + + private function logsTable() + { + $logs = json_decode(@file_get_contents(LOGPATH)); + if (!$logs) { + return; + } + $html = ''; + foreach (array_reverse($logs) as $log) { + $html .= ''; + $html .= implode('', array_map('htmlentities', $log)); + $html .= ''; + } + return '

Logs

'.$html.'
'; + } +} diff --git a/plugins/PicoContact/src/P01contact_Field.php b/plugins/PicoContact/src/P01contact_Field.php new file mode 100644 index 0000000..9286546 --- /dev/null +++ b/plugins/PicoContact/src/P01contact_Field.php @@ -0,0 +1,406 @@ +form = $form; + $this->id = $id; + $this->type = $type; + } + + /** + * Set the field value or selected value + * + * @param mixed $new_value the value, or an array of selected values ids + */ + public function setValue($new_value) + { + // simple value + if (!is_array($this->value)) { + $this->value = htmlentities($new_value, ENT_COMPAT, 'UTF-8', false); + return; + } + // multiples-values (checkbox, radio, select) + if (!is_array($new_value)) { + $new_value = array($new_value); + } + foreach ($new_value as $i) { + $this->selected_values[intval($i)] = true; + } + } + + /** + * Reset the selected values by finding ones who starts or end with ":" + */ + public function resetSelectedValues() + { + $this->selected_values = array(); + foreach ($this->value as $i => $val) { + $value = preg_replace('`(^\s*:|:\s*$)`', '', $val, -1, $count); + if ($count) { + $this->value[$i] = $value; + $this->selected_values[$i] = true; + } + } + } + + /** + * Check field value. + * @return boolean + */ + public function validate() + { + // empty and required + if (empty($this->value) && $this->required) { + $this->error = 'field_required'; + return false; + } + // value blacklisted or not in whitelist + if ($reason = $this->isBlacklisted()) { + $this->error = 'field_' . $reason; + return false; + } + // not empty but not valid + if (!empty($this->value) && !$this->isValid()) { + $this->error = 'field_' . $this->type; + return false; + } + return true; + } + + /** + * Check if field value is valid + * Mean different things depending on field type + * @return boolean + */ + public function isValid() + { + switch ($this->type) { + case 'email': + return filter_var($this->value, FILTER_VALIDATE_EMAIL); + case 'tel': + $pattern = '`^\+?[-0-9(). ]{6,}$$`i'; + return preg_match($pattern, $this->value); + case 'url': + return filter_var($this->value, FILTER_VALIDATE_URL); + case 'message': + return strlen($this->value) > $this->form->config('message_len'); + case 'captcha': + return $this->reCaptchaValidity($_POST['g-recaptcha-response']); + case 'password': + return $this->value == $this->required; + default: + return true; + } + } + + /** + * Check if reCaptcha is valid + * @return boolean + */ + public function reCaptchaValidity($answer) + { + if (!$answer) { + return false; + } + $params = [ + 'secret' => $this->form->config('recaptcha_secret_key'), + 'response' => $answer + ]; + $url = "https://www.google.com/recaptcha/api/siteverify?" . http_build_query($params); + if (function_exists('curl_version')) { + $curl = curl_init($url); + curl_setopt($curl, CURLOPT_HEADER, false); + curl_setopt($curl, CURLOPT_RETURNTRANSFER, true); + curl_setopt($curl, CURLOPT_TIMEOUT, 1); + curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false); + $response = curl_exec($curl); + } else { + $response = file_get_contents($url); + } + + if (empty($response) || is_null($response)) { + return false; + } + + return json_decode($response)->success; + } + + /** + * Check if field value is blacklisted + * + * Search for every comma-separated entry of every checklist + * in value, and define if it should or should not be there. + * + * @return boolean + */ + public function isBlacklisted() + { + $list = $this->form->config('checklist'); + if (!$list) { + return; + } + foreach ($list as $cl) { + if ($cl->name != $this->type) { + continue; + } + $content = array_filter(explode(',', $cl->content)); + foreach ($content as $avoid) { + $found = preg_match("`$avoid`", $this->value); + $foundBlacklisted = $found && $cl->type == 'blacklist'; + $notFoundWhitelisted = !$found && $cl->type == 'whitelist'; + if ($foundBlacklisted || $notFoundWhitelisted) { + return $cl->type; + } + } + } + return false; + } + + /* + * Return the html display of the field + * + * Manage field title, error message, and type-based display + * @return string the
+ */ + public function html() + { + $id = 'p01-contact' . $this->form->getId() . '_field' . $this->id; + $name = 'p01-contact_fields[' . $this->id . ']'; + $type = $this->getGeneralType(); + $orig = $type != $this->type ? $this->type : ''; + $value = $this->value; + $disabled = $this->locked ? ' disabled="disabled"' : ''; + $required = $this->required ? ' required ' : ''; + $placeholder = $this->placeholder ? ' placeholder="'.$this->placeholder.'"' : ''; + + $is_single_option = is_array($this->value) && count($this->value) == 1; + if ($is_single_option) { + $html = "
"; + } else { + $html = "
"; + $html .= $this->htmlLabel($id); + } + + switch ($type) { + case 'textarea': + $html .= ' + + + + + + +
+

{{lang.checklists}}

+

{{lang.checklists_sub}}

+
+
+ + + + + +
+ +
+
+
+ + + + + +
+ +
+
+
+ + + + + +
+ +
+
+
+

{{lang.Security}}

+ + + + +

{{lang.captcha_info}}

+ + +
+
+

{{lang.debug}}

+ + +
+ + +
diff --git a/plugins/PicoContact/src/templates/mail_template.html b/plugins/PicoContact/src/templates/mail_template.html new file mode 100644 index 0000000..2803129 --- /dev/null +++ b/plugins/PicoContact/src/templates/mail_template.html @@ -0,0 +1,28 @@ + + + + + + + + + + + + + + + +
+

+ {{lang.email_title}} + {{SERVERNAME}} +

+
{{date}}{{PAGEURI}}{{ip}}
{{fields}}
+ If this mail should not be for you, please contact + {{contact}}. + + + p01-contact v{{VERSION}} + +
diff --git a/plugins/PicoContact/src/vendor/spyc.php b/plugins/PicoContact/src/vendor/spyc.php new file mode 100644 index 0000000..6d4478f --- /dev/null +++ b/plugins/PicoContact/src/vendor/spyc.php @@ -0,0 +1,1161 @@ + + * @author Chris Wanstrath + * @link https://github.com/mustangostang/spyc/ + * @copyright Copyright 2005-2006 Chris Wanstrath, 2006-2011 Vlad Andersen + * @license http://www.opensource.org/licenses/mit-license.php MIT License + * @package Spyc + */ + +if (!function_exists('spyc_load')) { + /** + * Parses YAML to array. + * @param string $string YAML string. + * @return array + */ + function spyc_load ($string) { + return Spyc::YAMLLoadString($string); + } +} + +if (!function_exists('spyc_load_file')) { + /** + * Parses YAML to array. + * @param string $file Path to YAML file. + * @return array + */ + function spyc_load_file ($file) { + return Spyc::YAMLLoad($file); + } +} + +if (!function_exists('spyc_dump')) { + /** + * Dumps array to YAML. + * @param array $data Array. + * @return string + */ + function spyc_dump ($data) { + return Spyc::YAMLDump($data, false, false, true); + } +} + +if (!class_exists('Spyc')) { + +/** + * The Simple PHP YAML Class. + * + * This class can be used to read a YAML file and convert its contents + * into a PHP array. It currently supports a very limited subsection of + * the YAML spec. + * + * Usage: + * + * $Spyc = new Spyc; + * $array = $Spyc->load($file); + * + * or: + * + * $array = Spyc::YAMLLoad($file); + * + * or: + * + * $array = spyc_load_file($file); + * + * @package Spyc + */ +class Spyc { + + // SETTINGS + + const REMPTY = "\0\0\0\0\0"; + + /** + * Setting this to true will force YAMLDump to enclose any string value in + * quotes. False by default. + * + * @var bool + */ + public $setting_dump_force_quotes = false; + + /** + * Setting this to true will forse YAMLLoad to use syck_load function when + * possible. False by default. + * @var bool + */ + public $setting_use_syck_is_possible = false; + + + + /**#@+ + * @access private + * @var mixed + */ + private $_dumpIndent; + private $_dumpWordWrap; + private $_containsGroupAnchor = false; + private $_containsGroupAlias = false; + private $path; + private $result; + private $LiteralPlaceHolder = '___YAML_Literal_Block___'; + private $SavedGroups = array(); + private $indent; + /** + * Path modifier that should be applied after adding current element. + * @var array + */ + private $delayedPath = array(); + + /**#@+ + * @access public + * @var mixed + */ + public $_nodeId; + +/** + * Load a valid YAML string to Spyc. + * @param string $input + * @return array + */ + public function load ($input) { + return $this->_loadString($input); + } + + /** + * Load a valid YAML file to Spyc. + * @param string $file + * @return array + */ + public function loadFile ($file) { + return $this->_load($file); + } + + /** + * Load YAML into a PHP array statically + * + * The load method, when supplied with a YAML stream (string or file), + * will do its best to convert YAML in a file into a PHP array. Pretty + * simple. + * Usage: + * + * $array = Spyc::YAMLLoad('lucky.yaml'); + * print_r($array); + * + * @access public + * @return array + * @param string $input Path of YAML file or string containing YAML + */ + public static function YAMLLoad($input) { + $Spyc = new Spyc; + return $Spyc->_load($input); + } + + /** + * Load a string of YAML into a PHP array statically + * + * The load method, when supplied with a YAML string, will do its best + * to convert YAML in a string into a PHP array. Pretty simple. + * + * Note: use this function if you don't want files from the file system + * loaded and processed as YAML. This is of interest to people concerned + * about security whose input is from a string. + * + * Usage: + * + * $array = Spyc::YAMLLoadString("---\n0: hello world\n"); + * print_r($array); + * + * @access public + * @return array + * @param string $input String containing YAML + */ + public static function YAMLLoadString($input) { + $Spyc = new Spyc; + return $Spyc->_loadString($input); + } + + /** + * Dump YAML from PHP array statically + * + * The dump method, when supplied with an array, will do its best + * to convert the array into friendly YAML. Pretty simple. Feel free to + * save the returned string as nothing.yaml and pass it around. + * + * Oh, and you can decide how big the indent is and what the wordwrap + * for folding is. Pretty cool -- just pass in 'false' for either if + * you want to use the default. + * + * Indent's default is 2 spaces, wordwrap's default is 40 characters. And + * you can turn off wordwrap by passing in 0. + * + * @access public + * @return string + * @param array|\stdClass $array PHP array + * @param int $indent Pass in false to use the default, which is 2 + * @param int $wordwrap Pass in 0 for no wordwrap, false for default (40) + * @param bool $no_opening_dashes Do not start YAML file with "---\n" + */ + public static function YAMLDump($array, $indent = false, $wordwrap = false, $no_opening_dashes = false) { + $spyc = new Spyc; + return $spyc->dump($array, $indent, $wordwrap, $no_opening_dashes); + } + + + /** + * Dump PHP array to YAML + * + * The dump method, when supplied with an array, will do its best + * to convert the array into friendly YAML. Pretty simple. Feel free to + * save the returned string as tasteful.yaml and pass it around. + * + * Oh, and you can decide how big the indent is and what the wordwrap + * for folding is. Pretty cool -- just pass in 'false' for either if + * you want to use the default. + * + * Indent's default is 2 spaces, wordwrap's default is 40 characters. And + * you can turn off wordwrap by passing in 0. + * + * @access public + * @return string + * @param array $array PHP array + * @param int $indent Pass in false to use the default, which is 2 + * @param int $wordwrap Pass in 0 for no wordwrap, false for default (40) + */ + public function dump($array,$indent = false,$wordwrap = false, $no_opening_dashes = false) { + // Dumps to some very clean YAML. We'll have to add some more features + // and options soon. And better support for folding. + + // New features and options. + if ($indent === false or !is_numeric($indent)) { + $this->_dumpIndent = 2; + } else { + $this->_dumpIndent = $indent; + } + + if ($wordwrap === false or !is_numeric($wordwrap)) { + $this->_dumpWordWrap = 40; + } else { + $this->_dumpWordWrap = $wordwrap; + } + + // New YAML document + $string = ""; + if (!$no_opening_dashes) $string = "---\n"; + + // Start at the base of the array and move through it. + if ($array) { + $array = (array)$array; + $previous_key = -1; + foreach ($array as $key => $value) { + if (!isset($first_key)) $first_key = $key; + $string .= $this->_yamlize($key,$value,0,$previous_key, $first_key, $array); + $previous_key = $key; + } + } + return $string; + } + + /** + * Attempts to convert a key / value array item to YAML + * @access private + * @return string + * @param $key The name of the key + * @param $value The value of the item + * @param $indent The indent of the current node + */ + private function _yamlize($key,$value,$indent, $previous_key = -1, $first_key = 0, $source_array = null) { + if(is_object($value)) $value = (array)$value; + if (is_array($value)) { + if (empty ($value)) + return $this->_dumpNode($key, array(), $indent, $previous_key, $first_key, $source_array); + // It has children. What to do? + // Make it the right kind of item + $string = $this->_dumpNode($key, self::REMPTY, $indent, $previous_key, $first_key, $source_array); + // Add the indent + $indent += $this->_dumpIndent; + // Yamlize the array + $string .= $this->_yamlizeArray($value,$indent); + } elseif (!is_array($value)) { + // It doesn't have children. Yip. + $string = $this->_dumpNode($key, $value, $indent, $previous_key, $first_key, $source_array); + } + return $string; + } + + /** + * Attempts to convert an array to YAML + * @access private + * @return string + * @param $array The array you want to convert + * @param $indent The indent of the current level + */ + private function _yamlizeArray($array,$indent) { + if (is_array($array)) { + $string = ''; + $previous_key = -1; + foreach ($array as $key => $value) { + if (!isset($first_key)) $first_key = $key; + $string .= $this->_yamlize($key, $value, $indent, $previous_key, $first_key, $array); + $previous_key = $key; + } + return $string; + } else { + return false; + } + } + + /** + * Returns YAML from a key and a value + * @access private + * @return string + * @param $key The name of the key + * @param $value The value of the item + * @param $indent The indent of the current node + */ + private function _dumpNode($key, $value, $indent, $previous_key = -1, $first_key = 0, $source_array = null) { + // do some folding here, for blocks + if (is_string ($value) && ((strpos($value,"\n") !== false || strpos($value,": ") !== false || strpos($value,"- ") !== false || + strpos($value,"*") !== false || strpos($value,"#") !== false || strpos($value,"<") !== false || strpos($value,">") !== false || strpos ($value, '%') !== false || strpos ($value, ' ') !== false || + strpos($value,"[") !== false || strpos($value,"]") !== false || strpos($value,"{") !== false || strpos($value,"}") !== false) || strpos($value,"&") !== false || strpos($value, "'") !== false || strpos($value, "!") === 0 || + substr ($value, -1, 1) == ':') + ) { + $value = $this->_doLiteralBlock($value,$indent); + } else { + $value = $this->_doFolding($value,$indent); + } + + if ($value === array()) $value = '[ ]'; + if ($value === "") $value = '""'; + if (self::isTranslationWord($value)) { + $value = $this->_doLiteralBlock($value, $indent); + } + if (trim ($value) != $value) + $value = $this->_doLiteralBlock($value,$indent); + + if (is_bool($value)) { + $value = $value ? "true" : "false"; + } + + if ($value === null) $value = 'null'; + if ($value === "'" . self::REMPTY . "'") $value = null; + + $spaces = str_repeat(' ',$indent); + + //if (is_int($key) && $key - 1 == $previous_key && $first_key===0) { + if (is_array ($source_array) && array_keys($source_array) === range(0, count($source_array) - 1)) { + // It's a sequence + $string = $spaces.'- '.$value."\n"; + } else { + // if ($first_key===0) throw new Exception('Keys are all screwy. The first one was zero, now it\'s "'. $key .'"'); + // It's mapped + if (strpos($key, ":") !== false || strpos($key, "#") !== false) { $key = '"' . $key . '"'; } + $string = rtrim ($spaces.$key.': '.$value)."\n"; + } + return $string; + } + + /** + * Creates a literal block for dumping + * @access private + * @return string + * @param $value + * @param $indent int The value of the indent + */ + private function _doLiteralBlock($value,$indent) { + if ($value === "\n") return '\n'; + if (strpos($value, "\n") === false && strpos($value, "'") === false) { + return sprintf ("'%s'", $value); + } + if (strpos($value, "\n") === false && strpos($value, '"') === false) { + return sprintf ('"%s"', $value); + } + $exploded = explode("\n",$value); + $newValue = '|'; + if (isset($exploded[0]) && ($exploded[0] == "|" || $exploded[0] == "|-" || $exploded[0] == ">")) { + $newValue = $exploded[0]; + unset($exploded[0]); + } + $indent += $this->_dumpIndent; + $spaces = str_repeat(' ',$indent); + foreach ($exploded as $line) { + $line = trim($line); + if (strpos($line, '"') === 0 && strrpos($line, '"') == (strlen($line)-1) || strpos($line, "'") === 0 && strrpos($line, "'") == (strlen($line)-1)) { + $line = substr($line, 1, -1); + } + $newValue .= "\n" . $spaces . ($line); + } + return $newValue; + } + + /** + * Folds a string of text, if necessary + * @access private + * @return string + * @param $value The string you wish to fold + */ + private function _doFolding($value,$indent) { + // Don't do anything if wordwrap is set to 0 + + if ($this->_dumpWordWrap !== 0 && is_string ($value) && strlen($value) > $this->_dumpWordWrap) { + $indent += $this->_dumpIndent; + $indent = str_repeat(' ',$indent); + $wrapped = wordwrap($value,$this->_dumpWordWrap,"\n$indent"); + $value = ">\n".$indent.$wrapped; + } else { + if ($this->setting_dump_force_quotes && is_string ($value) && $value !== self::REMPTY) + $value = '"' . $value . '"'; + if (is_numeric($value) && is_string($value)) + $value = '"' . $value . '"'; + } + + + return $value; + } + + private function isTrueWord($value) { + $words = self::getTranslations(array('true', 'on', 'yes', 'y')); + return in_array($value, $words, true); + } + + private function isFalseWord($value) { + $words = self::getTranslations(array('false', 'off', 'no', 'n')); + return in_array($value, $words, true); + } + + private function isNullWord($value) { + $words = self::getTranslations(array('null', '~')); + return in_array($value, $words, true); + } + + private function isTranslationWord($value) { + return ( + self::isTrueWord($value) || + self::isFalseWord($value) || + self::isNullWord($value) + ); + } + + /** + * Coerce a string into a native type + * Reference: http://yaml.org/type/bool.html + * TODO: Use only words from the YAML spec. + * @access private + * @param $value The value to coerce + */ + private function coerceValue(&$value) { + if (self::isTrueWord($value)) { + $value = true; + } else if (self::isFalseWord($value)) { + $value = false; + } else if (self::isNullWord($value)) { + $value = null; + } + } + + /** + * Given a set of words, perform the appropriate translations on them to + * match the YAML 1.1 specification for type coercing. + * @param $words The words to translate + * @access private + */ + private static function getTranslations(array $words) { + $result = array(); + foreach ($words as $i) { + $result = array_merge($result, array(ucfirst($i), strtoupper($i), strtolower($i))); + } + return $result; + } + +// LOADING FUNCTIONS + + private function _load($input) { + $Source = $this->loadFromSource($input); + return $this->loadWithSource($Source); + } + + private function _loadString($input) { + $Source = $this->loadFromString($input); + return $this->loadWithSource($Source); + } + + private function loadWithSource($Source) { + if (empty ($Source)) return array(); + if ($this->setting_use_syck_is_possible && function_exists ('syck_load')) { + $array = syck_load (implode ("\n", $Source)); + return is_array($array) ? $array : array(); + } + + $this->path = array(); + $this->result = array(); + + $cnt = count($Source); + for ($i = 0; $i < $cnt; $i++) { + $line = $Source[$i]; + + $this->indent = strlen($line) - strlen(ltrim($line)); + $tempPath = $this->getParentPathByIndent($this->indent); + $line = self::stripIndent($line, $this->indent); + if (self::isComment($line)) continue; + if (self::isEmpty($line)) continue; + $this->path = $tempPath; + + $literalBlockStyle = self::startsLiteralBlock($line); + if ($literalBlockStyle) { + $line = rtrim ($line, $literalBlockStyle . " \n"); + $literalBlock = ''; + $line .= ' '.$this->LiteralPlaceHolder; + $literal_block_indent = strlen($Source[$i+1]) - strlen(ltrim($Source[$i+1])); + while (++$i < $cnt && $this->literalBlockContinues($Source[$i], $this->indent)) { + $literalBlock = $this->addLiteralLine($literalBlock, $Source[$i], $literalBlockStyle, $literal_block_indent); + } + $i--; + } + + // Strip out comments + if (strpos ($line, '#')) { + $line = preg_replace('/\s*#([^"\']+)$/','',$line); + } + + while (++$i < $cnt && self::greedilyNeedNextLine($line)) { + $line = rtrim ($line, " \n\t\r") . ' ' . ltrim ($Source[$i], " \t"); + } + $i--; + + $lineArray = $this->_parseLine($line); + + if ($literalBlockStyle) + $lineArray = $this->revertLiteralPlaceHolder ($lineArray, $literalBlock); + + $this->addArray($lineArray, $this->indent); + + foreach ($this->delayedPath as $indent => $delayedPath) + $this->path[$indent] = $delayedPath; + + $this->delayedPath = array(); + + } + return $this->result; + } + + private function loadFromSource ($input) { + if (!empty($input) && strpos($input, "\n") === false && file_exists($input)) + $input = file_get_contents($input); + + return $this->loadFromString($input); + } + + private function loadFromString ($input) { + $lines = explode("\n",$input); + foreach ($lines as $k => $_) { + $lines[$k] = rtrim ($_, "\r"); + } + return $lines; + } + + /** + * Parses YAML code and returns an array for a node + * @access private + * @return array + * @param string $line A line from the YAML file + */ + private function _parseLine($line) { + if (!$line) return array(); + $line = trim($line); + if (!$line) return array(); + + $array = array(); + + $group = $this->nodeContainsGroup($line); + if ($group) { + $this->addGroup($line, $group); + $line = $this->stripGroup ($line, $group); + } + + if ($this->startsMappedSequence($line)) + return $this->returnMappedSequence($line); + + if ($this->startsMappedValue($line)) + return $this->returnMappedValue($line); + + if ($this->isArrayElement($line)) + return $this->returnArrayElement($line); + + if ($this->isPlainArray($line)) + return $this->returnPlainArray($line); + + + return $this->returnKeyValuePair($line); + + } + + /** + * Finds the type of the passed value, returns the value as the new type. + * @access private + * @param string $value + * @return mixed + */ + private function _toType($value) { + if ($value === '') return ""; + $first_character = $value[0]; + $last_character = substr($value, -1, 1); + + $is_quoted = false; + do { + if (!$value) break; + if ($first_character != '"' && $first_character != "'") break; + if ($last_character != '"' && $last_character != "'") break; + $is_quoted = true; + } while (0); + + if ($is_quoted) { + $value = str_replace('\n', "\n", $value); + if ($first_character == "'") + return strtr(substr ($value, 1, -1), array ('\'\'' => '\'', '\\\''=> '\'')); + return strtr(substr ($value, 1, -1), array ('\\"' => '"', '\\\''=> '\'')); + } + + if (strpos($value, ' #') !== false && !$is_quoted) + $value = preg_replace('/\s+#(.+)$/','',$value); + + if ($first_character == '[' && $last_character == ']') { + // Take out strings sequences and mappings + $innerValue = trim(substr ($value, 1, -1)); + if ($innerValue === '') return array(); + $explode = $this->_inlineEscape($innerValue); + // Propagate value array + $value = array(); + foreach ($explode as $v) { + $value[] = $this->_toType($v); + } + return $value; + } + + if (strpos($value,': ')!==false && $first_character != '{') { + $array = explode(': ',$value); + $key = trim($array[0]); + array_shift($array); + $value = trim(implode(': ',$array)); + $value = $this->_toType($value); + return array($key => $value); + } + + if ($first_character == '{' && $last_character == '}') { + $innerValue = trim(substr ($value, 1, -1)); + if ($innerValue === '') return array(); + // Inline Mapping + // Take out strings sequences and mappings + $explode = $this->_inlineEscape($innerValue); + // Propagate value array + $array = array(); + foreach ($explode as $v) { + $SubArr = $this->_toType($v); + if (empty($SubArr)) continue; + if (is_array ($SubArr)) { + $array[key($SubArr)] = $SubArr[key($SubArr)]; continue; + } + $array[] = $SubArr; + } + return $array; + } + + if ($value == 'null' || $value == 'NULL' || $value == 'Null' || $value == '' || $value == '~') { + return null; + } + + if ( is_numeric($value) && preg_match ('/^(-|)[1-9]+[0-9]*$/', $value) ){ + $intvalue = (int)$value; + if ($intvalue != PHP_INT_MAX && $intvalue != ~PHP_INT_MAX) + $value = $intvalue; + return $value; + } + + if ( is_string($value) && preg_match('/^0[xX][0-9a-fA-F]+$/', $value)) { + // Hexadecimal value. + return hexdec($value); + } + + $this->coerceValue($value); + + if (is_numeric($value)) { + if ($value === '0') return 0; + if (rtrim ($value, 0) === $value) + $value = (float)$value; + return $value; + } + + return $value; + } + + /** + * Used in inlines to check for more inlines or quoted strings + * @access private + * @return array + */ + private function _inlineEscape($inline) { + // There's gotta be a cleaner way to do this... + // While pure sequences seem to be nesting just fine, + // pure mappings and mappings with sequences inside can't go very + // deep. This needs to be fixed. + + $seqs = array(); + $maps = array(); + $saved_strings = array(); + $saved_empties = array(); + + // Check for empty strings + $regex = '/("")|(\'\')/'; + if (preg_match_all($regex,$inline,$strings)) { + $saved_empties = $strings[0]; + $inline = preg_replace($regex,'YAMLEmpty',$inline); + } + unset($regex); + + // Check for strings + $regex = '/(?:(")|(?:\'))((?(1)[^"]+|[^\']+))(?(1)"|\')/'; + if (preg_match_all($regex,$inline,$strings)) { + $saved_strings = $strings[0]; + $inline = preg_replace($regex,'YAMLString',$inline); + } + unset($regex); + + // echo $inline; + + $i = 0; + do { + + // Check for sequences + while (preg_match('/\[([^{}\[\]]+)\]/U',$inline,$matchseqs)) { + $seqs[] = $matchseqs[0]; + $inline = preg_replace('/\[([^{}\[\]]+)\]/U', ('YAMLSeq' . (count($seqs) - 1) . 's'), $inline, 1); + } + + // Check for mappings + while (preg_match('/{([^\[\]{}]+)}/U',$inline,$matchmaps)) { + $maps[] = $matchmaps[0]; + $inline = preg_replace('/{([^\[\]{}]+)}/U', ('YAMLMap' . (count($maps) - 1) . 's'), $inline, 1); + } + + if ($i++ >= 10) break; + + } while (strpos ($inline, '[') !== false || strpos ($inline, '{') !== false); + + $explode = explode(',',$inline); + $explode = array_map('trim', $explode); + $stringi = 0; $i = 0; + + while (1) { + + // Re-add the sequences + if (!empty($seqs)) { + foreach ($explode as $key => $value) { + if (strpos($value,'YAMLSeq') !== false) { + foreach ($seqs as $seqk => $seq) { + $explode[$key] = str_replace(('YAMLSeq'.$seqk.'s'),$seq,$value); + $value = $explode[$key]; + } + } + } + } + + // Re-add the mappings + if (!empty($maps)) { + foreach ($explode as $key => $value) { + if (strpos($value,'YAMLMap') !== false) { + foreach ($maps as $mapk => $map) { + $explode[$key] = str_replace(('YAMLMap'.$mapk.'s'), $map, $value); + $value = $explode[$key]; + } + } + } + } + + + // Re-add the strings + if (!empty($saved_strings)) { + foreach ($explode as $key => $value) { + while (strpos($value,'YAMLString') !== false) { + $explode[$key] = preg_replace('/YAMLString/',$saved_strings[$stringi],$value, 1); + unset($saved_strings[$stringi]); + ++$stringi; + $value = $explode[$key]; + } + } + } + + + // Re-add the empties + if (!empty($saved_empties)) { + foreach ($explode as $key => $value) { + while (strpos($value,'YAMLEmpty') !== false) { + $explode[$key] = preg_replace('/YAMLEmpty/', '', $value, 1); + $value = $explode[$key]; + } + } + } + + $finished = true; + foreach ($explode as $key => $value) { + if (strpos($value,'YAMLSeq') !== false) { + $finished = false; break; + } + if (strpos($value,'YAMLMap') !== false) { + $finished = false; break; + } + if (strpos($value,'YAMLString') !== false) { + $finished = false; break; + } + if (strpos($value,'YAMLEmpty') !== false) { + $finished = false; break; + } + } + if ($finished) break; + + $i++; + if ($i > 10) + break; // Prevent infinite loops. + } + + + return $explode; + } + + private function literalBlockContinues ($line, $lineIndent) { + if (!trim($line)) return true; + if (strlen($line) - strlen(ltrim($line)) > $lineIndent) return true; + return false; + } + + private function referenceContentsByAlias ($alias) { + do { + if (!isset($this->SavedGroups[$alias])) { echo "Bad group name: $alias."; break; } + $groupPath = $this->SavedGroups[$alias]; + $value = $this->result; + foreach ($groupPath as $k) { + $value = $value[$k]; + } + } while (false); + return $value; + } + + private function addArrayInline ($array, $indent) { + $CommonGroupPath = $this->path; + if (empty ($array)) return false; + + foreach ($array as $k => $_) { + $this->addArray(array($k => $_), $indent); + $this->path = $CommonGroupPath; + } + return true; + } + + private function addArray ($incoming_data, $incoming_indent) { + + // print_r ($incoming_data); + + if (count ($incoming_data) > 1) + return $this->addArrayInline ($incoming_data, $incoming_indent); + + $key = key ($incoming_data); + $value = isset($incoming_data[$key]) ? $incoming_data[$key] : null; + if ($key === '__!YAMLZero') $key = '0'; + + if ($incoming_indent == 0 && !$this->_containsGroupAlias && !$this->_containsGroupAnchor) { // Shortcut for root-level values. + if ($key || $key === '' || $key === '0') { + $this->result[$key] = $value; + } else { + $this->result[] = $value; end ($this->result); $key = key ($this->result); + } + $this->path[$incoming_indent] = $key; + return; + } + + + + $history = array(); + // Unfolding inner array tree. + $history[] = $_arr = $this->result; + foreach ($this->path as $k) { + $history[] = $_arr = $_arr[$k]; + } + + if ($this->_containsGroupAlias) { + $value = $this->referenceContentsByAlias($this->_containsGroupAlias); + $this->_containsGroupAlias = false; + } + + + // Adding string or numeric key to the innermost level or $this->arr. + if (is_string($key) && $key == '<<') { + if (!is_array ($_arr)) { $_arr = array (); } + + $_arr = array_merge ($_arr, $value); + } else if ($key || $key === '' || $key === '0') { + if (!is_array ($_arr)) + $_arr = array ($key=>$value); + else + $_arr[$key] = $value; + } else { + if (!is_array ($_arr)) { $_arr = array ($value); $key = 0; } + else { $_arr[] = $value; end ($_arr); $key = key ($_arr); } + } + + $reverse_path = array_reverse($this->path); + $reverse_history = array_reverse ($history); + $reverse_history[0] = $_arr; + $cnt = count($reverse_history) - 1; + for ($i = 0; $i < $cnt; $i++) { + $reverse_history[$i+1][$reverse_path[$i]] = $reverse_history[$i]; + } + $this->result = $reverse_history[$cnt]; + + $this->path[$incoming_indent] = $key; + + if ($this->_containsGroupAnchor) { + $this->SavedGroups[$this->_containsGroupAnchor] = $this->path; + if (is_array ($value)) { + $k = key ($value); + if (!is_int ($k)) { + $this->SavedGroups[$this->_containsGroupAnchor][$incoming_indent + 2] = $k; + } + } + $this->_containsGroupAnchor = false; + } + + } + + private static function startsLiteralBlock ($line) { + $lastChar = substr (trim($line), -1); + if ($lastChar != '>' && $lastChar != '|') return false; + if ($lastChar == '|') return $lastChar; + // HTML tags should not be counted as literal blocks. + if (preg_match ('#<.*?>$#', $line)) return false; + return $lastChar; + } + + private static function greedilyNeedNextLine($line) { + $line = trim ($line); + if (!strlen($line)) return false; + if (substr ($line, -1, 1) == ']') return false; + if ($line[0] == '[') return true; + if (preg_match ('#^[^:]+?:\s*\[#', $line)) return true; + return false; + } + + private function addLiteralLine ($literalBlock, $line, $literalBlockStyle, $indent = -1) { + $line = self::stripIndent($line, $indent); + if ($literalBlockStyle !== '|') { + $line = self::stripIndent($line); + } + $line = rtrim ($line, "\r\n\t ") . "\n"; + if ($literalBlockStyle == '|') { + return $literalBlock . $line; + } + if (strlen($line) == 0) + return rtrim($literalBlock, ' ') . "\n"; + if ($line == "\n" && $literalBlockStyle == '>') { + return rtrim ($literalBlock, " \t") . "\n"; + } + if ($line != "\n") + $line = trim ($line, "\r\n ") . " "; + return $literalBlock . $line; + } + + function revertLiteralPlaceHolder ($lineArray, $literalBlock) { + foreach ($lineArray as $k => $_) { + if (is_array($_)) + $lineArray[$k] = $this->revertLiteralPlaceHolder ($_, $literalBlock); + else if (substr($_, -1 * strlen ($this->LiteralPlaceHolder)) == $this->LiteralPlaceHolder) + $lineArray[$k] = rtrim ($literalBlock, " \r\n"); + } + return $lineArray; + } + + private static function stripIndent ($line, $indent = -1) { + if ($indent == -1) $indent = strlen($line) - strlen(ltrim($line)); + return substr ($line, $indent); + } + + private function getParentPathByIndent ($indent) { + if ($indent == 0) return array(); + $linePath = $this->path; + do { + end($linePath); $lastIndentInParentPath = key($linePath); + if ($indent <= $lastIndentInParentPath) array_pop ($linePath); + } while ($indent <= $lastIndentInParentPath); + return $linePath; + } + + + private function clearBiggerPathValues ($indent) { + + + if ($indent == 0) $this->path = array(); + if (empty ($this->path)) return true; + + foreach ($this->path as $k => $_) { + if ($k > $indent) unset ($this->path[$k]); + } + + return true; + } + + + private static function isComment ($line) { + if (!$line) return false; + if ($line[0] == '#') return true; + if (trim($line, " \r\n\t") == '---') return true; + return false; + } + + private static function isEmpty ($line) { + return (trim ($line) === ''); + } + + + private function isArrayElement ($line) { + if (!$line || !is_scalar($line)) return false; + if (substr($line, 0, 2) != '- ') return false; + if (strlen ($line) > 3) + if (substr($line,0,3) == '---') return false; + + return true; + } + + private function isHashElement ($line) { + return strpos($line, ':'); + } + + private function isLiteral ($line) { + if ($this->isArrayElement($line)) return false; + if ($this->isHashElement($line)) return false; + return true; + } + + + private static function unquote ($value) { + if (!$value) return $value; + if (!is_string($value)) return $value; + if ($value[0] == '\'') return trim ($value, '\''); + if ($value[0] == '"') return trim ($value, '"'); + return $value; + } + + private function startsMappedSequence ($line) { + return (substr($line, 0, 2) == '- ' && substr ($line, -1, 1) == ':'); + } + + private function returnMappedSequence ($line) { + $array = array(); + $key = self::unquote(trim(substr($line,1,-1))); + $array[$key] = array(); + $this->delayedPath = array(strpos ($line, $key) + $this->indent => $key); + return array($array); + } + + private function checkKeysInValue($value) { + if (strchr('[{"\'', $value[0]) === false) { + if (strchr($value, ': ') !== false) { + throw new Exception('Too many keys: '.$value); + } + } + } + + private function returnMappedValue ($line) { + $this->checkKeysInValue($line); + $array = array(); + $key = self::unquote (trim(substr($line,0,-1))); + $array[$key] = ''; + return $array; + } + + private function startsMappedValue ($line) { + return (substr ($line, -1, 1) == ':'); + } + + private function isPlainArray ($line) { + return ($line[0] == '[' && substr ($line, -1, 1) == ']'); + } + + private function returnPlainArray ($line) { + return $this->_toType($line); + } + + private function returnKeyValuePair ($line) { + $array = array(); + $key = ''; + if (strpos ($line, ': ')) { + // It's a key/value pair most likely + // If the key is in double quotes pull it out + if (($line[0] == '"' || $line[0] == "'") && preg_match('/^(["\'](.*)["\'](\s)*:)/',$line,$matches)) { + $value = trim(str_replace($matches[1],'',$line)); + $key = $matches[2]; + } else { + // Do some guesswork as to the key and the value + $explode = explode(': ', $line); + $key = trim(array_shift($explode)); + $value = trim(implode(': ', $explode)); + $this->checkKeysInValue($value); + } + // Set the type of the value. Int, string, etc + $value = $this->_toType($value); + if ($key === '0') $key = '__!YAMLZero'; + $array[$key] = $value; + } else { + $array = array ($line); + } + return $array; + + } + + + private function returnArrayElement ($line) { + if (strlen($line) <= 1) return array(array()); // Weird %) + $array = array(); + $value = trim(substr($line,1)); + $value = $this->_toType($value); + if ($this->isArrayElement($value)) { + $value = $this->returnArrayElement($value); + } + $array[] = $value; + return $array; + } + + + private function nodeContainsGroup ($line) { + $symbolsForReference = 'A-z0-9_\-'; + if (strpos($line, '&') === false && strpos($line, '*') === false) return false; // Please die fast ;-) + if ($line[0] == '&' && preg_match('/^(&['.$symbolsForReference.']+)/', $line, $matches)) return $matches[1]; + if ($line[0] == '*' && preg_match('/^(\*['.$symbolsForReference.']+)/', $line, $matches)) return $matches[1]; + if (preg_match('/(&['.$symbolsForReference.']+)$/', $line, $matches)) return $matches[1]; + if (preg_match('/(\*['.$symbolsForReference.']+$)/', $line, $matches)) return $matches[1]; + if (preg_match ('#^\s*<<\s*:\s*(\*[^\s]+).*$#', $line, $matches)) return $matches[1]; + return false; + + } + + private function addGroup ($line, $group) { + if ($group[0] == '&') $this->_containsGroupAnchor = substr ($group, 1); + if ($group[0] == '*') $this->_containsGroupAlias = substr ($group, 1); + //print_r ($this->path); + } + + private function stripGroup ($line, $group) { + $line = trim(str_replace($group, '', $line)); + return $line; + } +} +} + +// Enable use of Spyc from command line +// The syntax is the following: php Spyc.php spyc.yaml + +do { + if (PHP_SAPI != 'cli') break; + if (empty ($_SERVER['argc']) || $_SERVER['argc'] < 2) break; + if (empty ($_SERVER['PHP_SELF']) || FALSE === strpos ($_SERVER['PHP_SELF'], 'Spyc.php') ) break; + $file = $argv[1]; + echo json_encode (spyc_load_file ($file)); +} while (0); \ No newline at end of file diff --git a/plugins/PicoContact/style.css b/plugins/PicoContact/style.css new file mode 100644 index 0000000..0115915 --- /dev/null +++ b/plugins/PicoContact/style.css @@ -0,0 +1,100 @@ +.p01-contact * { + box-sizing: border-box; +} +.p01-contact { + margin: 1em auto; + max-width: 26em; + font-family: "Lucida Sans Unicode", "Lucida Grande", sans-serif; +} +.p01-contact .field { + margin-top: .5em; +} +.p01-contact .field.inline { + margin-top: 1em; +} +.p01-contact label { + display: block; + font-weight: normal; +} +.p01-contact label .description{ + font-size: .875em; + color: #888; + float: right; +} +.p01-contact input:not([type=radio]):not([type=checkbox]), +.p01-contact textarea, +.p01-contact select{ + border:1px solid #BEBEBE; + padding: 7px; + margin:0px; + transition: all 0.30s ease-in-out; + outline: none; + width: 100%; +} +.p01-contact input:focus, +.p01-contact textarea:focus, +.p01-contact select:focus{ + box-shadow: 0 0 8px #88D5E9; + border: 1px solid #88D5E9; +} +.p01-contact input[type=submit]:not([type=radio]):not([type=checkbox]), +.p01-contact input[type=button]:not([type=radio]):not([type=checkbox]){ + background: #4B99AD; + padding: 8px 15px 8px 15px; + margin: 1em 0; + border: none; + color: #fff; +} +.p01-contact input[type=submit]:hover, +.p01-contact input[type=button]:hover{ + background: #4691A4; + box-shadow:none; +} +.p01-contact .required label:after { + content: ' *'; + color: #4B99AD; + font-weight: bold; +} +.p01-contact input[type=radio], +.p01-contact input[type=checkbox] { + vertical-align: middle; +} +.p01-contact :not(.inline) .options { + display: flex; + border: 1px solid #ddd; + padding: .5em; +} +.p01-contact :not(.inline) .options .option { + margin: 0 1em; +} +.p01-contact .options input { + display: inline-block; + margin-right: .5em; +} +.p01-contact .error-msg { + color: red; + font-size: .85em; + margin-left: .5em; +} +input:invalid, +textarea:invalid { + box-shadow: none; +} + +.p01-contact .alert { + padding: 15px; + margin-bottom: 20px; + border: 1px solid transparent; + border-radius: 4px; +} +.p01-contact .alert.success { + color: #3c763d; + background-color: #dff0d8; + border-color: #d6e9c6; +} +.p01-contact .alert.failed { + color: #a94442; + background-color: #f2dede; + border-color: #ebccd1; +} + diff --git a/plugins/PicoPagesImages.php b/plugins/PicoPagesImages.php new file mode 100644 index 0000000..67651e0 --- /dev/null +++ b/plugins/PicoPagesImages.php @@ -0,0 +1,124 @@ + + * @license http://opensource.org/licenses/MIT The MIT License + * @link http://nliautaud.fr + * @link http://picocms.org + */ +class PicoPagesImages extends AbstractPicoPlugin +{ + const API_VERSION = 2; + private $path; + private $root; + + /** + * Register path relative to content without index and extension + * var/html/content/foo/bar.md => foo/bar/ + * + * Triggered after Pico has discovered the content file to serve + * + * @see Pico::resolveFilePath() + * @see Pico::getRequestFile() + * + * @param string &$file absolute path to the content file to serve + * + * @return void + */ + public function onRequestFile(&$file) + { + $contentDir = $this->getConfig('content_dir'); + $contentDirLength = strlen($contentDir); + if (substr($file, 0, $contentDirLength) !== $contentDir) { + return; + } + $contentExt = $this->getConfig('content_ext'); + $this->path = substr($file, $contentDirLength); + $this->path = rtrim($this->path, "index$contentExt"); + $this->path = rtrim($this->path, $contentExt); + if ($this->path) { + $this->path .= '/'; + } + } + /** + * Triggered after Pico has read its configuration + * + * @see Pico::getConfig() + * @param array &$config array of config variables + * @return void + */ + public function onConfigLoaded(array &$config) + { + if (!empty($config['images_path'])) { + $this->root = rtrim($config['images_path'], '/') . '/'; + } else { + $this->root = 'images/'; + } + } + /** + * Triggered before Pico renders the page + * + * @see DummyPlugin::onPageRendered() + * + * @param string &$templateName file name of the template + * @param array &$twigVariables template variables + * + * @return void + */ + public function onPageRendering(&$templateName, array &$twigVariables) + { + // Create images array + $twigVariables['images'] = $this->getImages(); + } + /** + * Return the list and infos of images in the current directory. + * + * @return array + */ + private function getImages() + { + $images_path = $this->root . $this->path; + // Filter images path for extra slashes + $images_path = preg_replace('/(\/+)/','/',$images_path); + + $data = array(); + $pattern = '*.{[jJ][pP][gG],[jJ][pP][eE][gG],[pP][nN][gG],[gG][iI][fF]}'; + $images = glob($images_path . $pattern, GLOB_BRACE); + $meta = array(); + + if (!is_array($images)) { + return array(); + } + + foreach ($images as $path) { + $imagesize = getimagesize($path); + if (!is_array($imagesize)) { + $imagesize = array(); + } + list($width, $height,, $size) = array_pad($imagesize, 4, ''); + + // Find meta files for images if they exist + $metapath = $path . '.meta.yml'; + if (is_file($metapath)) { + $yamlparser = $this->getPico()->getYamlParser(); + $meta = $yamlparser->parse(file_get_contents($metapath)); + } + + $data[] = array ( + 'url' => $this->getBaseUrl() . $images_path . pathinfo($path, PATHINFO_BASENAME), + 'path' => $images_path, + 'name' => pathinfo($path, PATHINFO_FILENAME), + 'ext' => pathinfo($path, PATHINFO_EXTENSION), + 'width' => $width, + 'height' => $height, + 'size' => $size, + 'meta' => $meta + ); + + + } + return $data; + } +} diff --git a/themes/chrosey/css/mini-default.css b/themes/chrosey/css/mini-default.css new file mode 100644 index 0000000..301ae38 --- /dev/null +++ b/themes/chrosey/css/mini-default.css @@ -0,0 +1,2170 @@ +@charset "UTF-8"; +/* + Flavor name: Default (mini-default) + Author: Angelos Chalaris (chalarangelo@gmail.com) + Maintainers: Angelos Chalaris + mini.css version: v3.0.1 +*/ +/* + Browsers resets and base typography. +*/ +/* Core module CSS variable definitions */ +:root { + --fore-color: #111; + --secondary-fore-color: #444; + --back-color: #f8f8f8; + --secondary-back-color: #f0f0f0; + --blockquote-color: #f57c00; + --pre-color: #1565c0; + --border-color: #aaa; + --secondary-border-color: #ddd; + --heading-ratio: 1.19; + --universal-margin: 0.5rem; + --universal-padding: 0.5rem; + --universal-border-radius: 0.125rem; + --a-link-color: #0277bd; + --a-visited-color: #01579b; +} + +html { + font-size: 16px; +} + +a, b, del, em, i, ins, q, span, strong, u { + font-size: 1em; +} + +html, * { + font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Ubuntu, "Helvetica Neue", Helvetica, sans-serif; + line-height: 1.5; + -webkit-text-size-adjust: 100%; +} + +* { + font-size: 1rem; +} + +body { + margin: 0; + color: var(--fore-color); + background: var(--back-color); +} + +details { + display: block; +} + +summary { + display: list-item; +} + +abbr[title] { + border-bottom: none; + text-decoration: underline dotted; +} + +input { + overflow: visible; +} + +img { + max-width: 100%; + height: auto; +} + +h1, h2, h3, h4, h5, h6 { + line-height: 1.2; + margin: calc(1.5 * var(--universal-margin)) var(--universal-margin); + font-weight: 500; +} + +h1 small, h2 small, h3 small, h4 small, h5 small, h6 small { + color: var(--secondary-fore-color); + display: block; + margin-top: -0.25rem; +} + +h1 { + font-size: calc(1rem * var(--heading-ratio) * var(--heading-ratio) * var(--heading-ratio) * var(--heading-ratio)); +} + +h2 { + font-size: calc(1rem * var(--heading-ratio) * var(--heading-ratio) * var(--heading-ratio)); +} + +h3 { + font-size: calc(1rem * var(--heading-ratio) * var(--heading-ratio)); +} + +h4 { + font-size: calc(1rem * var(--heading-ratio)); +} + +h5 { + font-size: 1rem; +} + +h6 { + font-size: calc(1rem / var(--heading-ratio)); +} + +p { + margin: var(--universal-margin); +} + +ol, ul { + margin: var(--universal-margin); + padding-left: calc(2 * var(--universal-margin)); +} + +b, strong { + font-weight: 700; +} + +hr { + box-sizing: content-box; + border: 0; + line-height: 1.25em; + margin: var(--universal-margin); + height: 0.0625rem; + background: linear-gradient(to right, transparent, var(--border-color) 20%, var(--border-color) 80%, transparent); +} + +blockquote { + display: block; + position: relative; + font-style: italic; + color: var(--secondary-fore-color); + margin: var(--universal-margin); + padding: calc(3 * var(--universal-padding)); + border: 0.0625rem solid var(--secondary-border-color); + border-left: 0.375rem solid var(--blockquote-color); + border-radius: 0 var(--universal-border-radius) var(--universal-border-radius) 0; +} + +blockquote:before { + position: absolute; + top: calc(0rem - var(--universal-padding)); + left: 0; + font-family: sans-serif; + font-size: 3rem; + font-weight: 700; + content: "\201c"; + color: var(--blockquote-color); +} + +blockquote[cite]:after { + font-style: normal; + font-size: 0.75em; + font-weight: 700; + content: "\a— " attr(cite); + white-space: pre; +} + +code, kbd, pre, samp { + font-family: Menlo, Consolas, monospace; + font-size: 0.85em; +} + +code { + background: var(--secondary-back-color); + border-radius: var(--universal-border-radius); + padding: calc(var(--universal-padding) / 4) calc(var(--universal-padding) / 2); +} + +kbd { + background: var(--fore-color); + color: var(--back-color); + border-radius: var(--universal-border-radius); + padding: calc(var(--universal-padding) / 4) calc(var(--universal-padding) / 2); +} + +pre { + overflow: auto; + background: var(--secondary-back-color); + padding: calc(1.5 * var(--universal-padding)); + margin: var(--universal-margin); + border: 0.0625rem solid var(--secondary-border-color); + border-left: 0.25rem solid var(--pre-color); + border-radius: 0 var(--universal-border-radius) var(--universal-border-radius) 0; +} + +sup, sub, code, kbd { + line-height: 0; + position: relative; + vertical-align: baseline; +} + +small, sup, sub, figcaption { + font-size: 0.75em; +} + +sup { + top: -0.5em; +} + +sub { + bottom: -0.25em; +} + +figure { + margin: var(--universal-margin); +} + +figcaption { + color: var(--secondary-fore-color); +} + +a { + text-decoration: none; +} + +a:link { + color: var(--a-link-color); +} + +a:visited { + color: var(--a-visited-color); +} + +a:hover, a:focus { + text-decoration: underline; +} + +/* + Definitions for the grid system, cards and containers. +*/ +.container { + margin: 0 auto; + padding: 0 calc(1.5 * var(--universal-padding)); +} + +.row { + box-sizing: border-box; + display: flex; + flex: 0 1 auto; + flex-flow: row wrap; +} + +.col-sm, +[class^='col-sm-'], +[class^='col-sm-offset-'], +.row[class*='cols-sm-'] > * { + box-sizing: border-box; + flex: 0 0 auto; + padding: 0 calc(var(--universal-padding) / 2); +} + +.col-sm, +.row.cols-sm > * { + max-width: 100%; + flex-grow: 1; + flex-basis: 0; +} + +.col-sm-1, +.row.cols-sm-1 > * { + max-width: 8.33333%; + flex-basis: 8.33333%; +} + +.col-sm-offset-0 { + margin-left: 0; +} + +.col-sm-2, +.row.cols-sm-2 > * { + max-width: 16.66667%; + flex-basis: 16.66667%; +} + +.col-sm-offset-1 { + margin-left: 8.33333%; +} + +.col-sm-3, +.row.cols-sm-3 > * { + max-width: 25%; + flex-basis: 25%; +} + +.col-sm-offset-2 { + margin-left: 16.66667%; +} + +.col-sm-4, +.row.cols-sm-4 > * { + max-width: 33.33333%; + flex-basis: 33.33333%; +} + +.col-sm-offset-3 { + margin-left: 25%; +} + +.col-sm-5, +.row.cols-sm-5 > * { + max-width: 41.66667%; + flex-basis: 41.66667%; +} + +.col-sm-offset-4 { + margin-left: 33.33333%; +} + +.col-sm-6, +.row.cols-sm-6 > * { + max-width: 50%; + flex-basis: 50%; +} + +.col-sm-offset-5 { + margin-left: 41.66667%; +} + +.col-sm-7, +.row.cols-sm-7 > * { + max-width: 58.33333%; + flex-basis: 58.33333%; +} + +.col-sm-offset-6 { + margin-left: 50%; +} + +.col-sm-8, +.row.cols-sm-8 > * { + max-width: 66.66667%; + flex-basis: 66.66667%; +} + +.col-sm-offset-7 { + margin-left: 58.33333%; +} + +.col-sm-9, +.row.cols-sm-9 > * { + max-width: 75%; + flex-basis: 75%; +} + +.col-sm-offset-8 { + margin-left: 66.66667%; +} + +.col-sm-10, +.row.cols-sm-10 > * { + max-width: 83.33333%; + flex-basis: 83.33333%; +} + +.col-sm-offset-9 { + margin-left: 75%; +} + +.col-sm-11, +.row.cols-sm-11 > * { + max-width: 91.66667%; + flex-basis: 91.66667%; +} + +.col-sm-offset-10 { + margin-left: 83.33333%; +} + +.col-sm-12, +.row.cols-sm-12 > * { + max-width: 100%; + flex-basis: 100%; +} + +.col-sm-offset-11 { + margin-left: 91.66667%; +} + +.col-sm-normal { + order: initial; +} + +.col-sm-first { + order: -999; +} + +.col-sm-last { + order: 999; +} + +@media screen and (min-width: 768px) { + .col-md, + [class^='col-md-'], + [class^='col-md-offset-'], + .row[class*='cols-md-'] > * { + box-sizing: border-box; + flex: 0 0 auto; + padding: 0 calc(var(--universal-padding) / 2); + } + .col-md, + .row.cols-md > * { + max-width: 100%; + flex-grow: 1; + flex-basis: 0; + } + .col-md-1, + .row.cols-md-1 > * { + max-width: 8.33333%; + flex-basis: 8.33333%; + } + .col-md-offset-0 { + margin-left: 0; + } + .col-md-2, + .row.cols-md-2 > * { + max-width: 16.66667%; + flex-basis: 16.66667%; + } + .col-md-offset-1 { + margin-left: 8.33333%; + } + .col-md-3, + .row.cols-md-3 > * { + max-width: 25%; + flex-basis: 25%; + } + .col-md-offset-2 { + margin-left: 16.66667%; + } + .col-md-4, + .row.cols-md-4 > * { + max-width: 33.33333%; + flex-basis: 33.33333%; + } + .col-md-offset-3 { + margin-left: 25%; + } + .col-md-5, + .row.cols-md-5 > * { + max-width: 41.66667%; + flex-basis: 41.66667%; + } + .col-md-offset-4 { + margin-left: 33.33333%; + } + .col-md-6, + .row.cols-md-6 > * { + max-width: 50%; + flex-basis: 50%; + } + .col-md-offset-5 { + margin-left: 41.66667%; + } + .col-md-7, + .row.cols-md-7 > * { + max-width: 58.33333%; + flex-basis: 58.33333%; + } + .col-md-offset-6 { + margin-left: 50%; + } + .col-md-8, + .row.cols-md-8 > * { + max-width: 66.66667%; + flex-basis: 66.66667%; + } + .col-md-offset-7 { + margin-left: 58.33333%; + } + .col-md-9, + .row.cols-md-9 > * { + max-width: 75%; + flex-basis: 75%; + } + .col-md-offset-8 { + margin-left: 66.66667%; + } + .col-md-10, + .row.cols-md-10 > * { + max-width: 83.33333%; + flex-basis: 83.33333%; + } + .col-md-offset-9 { + margin-left: 75%; + } + .col-md-11, + .row.cols-md-11 > * { + max-width: 91.66667%; + flex-basis: 91.66667%; + } + .col-md-offset-10 { + margin-left: 83.33333%; + } + .col-md-12, + .row.cols-md-12 > * { + max-width: 100%; + flex-basis: 100%; + } + .col-md-offset-11 { + margin-left: 91.66667%; + } + .col-md-normal { + order: initial; + } + .col-md-first { + order: -999; + } + .col-md-last { + order: 999; + } +} + +@media screen and (min-width: 1280px) { + .col-lg, + [class^='col-lg-'], + [class^='col-lg-offset-'], + .row[class*='cols-lg-'] > * { + box-sizing: border-box; + flex: 0 0 auto; + padding: 0 calc(var(--universal-padding) / 2); + } + .col-lg, + .row.cols-lg > * { + max-width: 100%; + flex-grow: 1; + flex-basis: 0; + } + .col-lg-1, + .row.cols-lg-1 > * { + max-width: 8.33333%; + flex-basis: 8.33333%; + } + .col-lg-offset-0 { + margin-left: 0; + } + .col-lg-2, + .row.cols-lg-2 > * { + max-width: 16.66667%; + flex-basis: 16.66667%; + } + .col-lg-offset-1 { + margin-left: 8.33333%; + } + .col-lg-3, + .row.cols-lg-3 > * { + max-width: 25%; + flex-basis: 25%; + } + .col-lg-offset-2 { + margin-left: 16.66667%; + } + .col-lg-4, + .row.cols-lg-4 > * { + max-width: 33.33333%; + flex-basis: 33.33333%; + } + .col-lg-offset-3 { + margin-left: 25%; + } + .col-lg-5, + .row.cols-lg-5 > * { + max-width: 41.66667%; + flex-basis: 41.66667%; + } + .col-lg-offset-4 { + margin-left: 33.33333%; + } + .col-lg-6, + .row.cols-lg-6 > * { + max-width: 50%; + flex-basis: 50%; + } + .col-lg-offset-5 { + margin-left: 41.66667%; + } + .col-lg-7, + .row.cols-lg-7 > * { + max-width: 58.33333%; + flex-basis: 58.33333%; + } + .col-lg-offset-6 { + margin-left: 50%; + } + .col-lg-8, + .row.cols-lg-8 > * { + max-width: 66.66667%; + flex-basis: 66.66667%; + } + .col-lg-offset-7 { + margin-left: 58.33333%; + } + .col-lg-9, + .row.cols-lg-9 > * { + max-width: 75%; + flex-basis: 75%; + } + .col-lg-offset-8 { + margin-left: 66.66667%; + } + .col-lg-10, + .row.cols-lg-10 > * { + max-width: 83.33333%; + flex-basis: 83.33333%; + } + .col-lg-offset-9 { + margin-left: 75%; + } + .col-lg-11, + .row.cols-lg-11 > * { + max-width: 91.66667%; + flex-basis: 91.66667%; + } + .col-lg-offset-10 { + margin-left: 83.33333%; + } + .col-lg-12, + .row.cols-lg-12 > * { + max-width: 100%; + flex-basis: 100%; + } + .col-lg-offset-11 { + margin-left: 91.66667%; + } + .col-lg-normal { + order: initial; + } + .col-lg-first { + order: -999; + } + .col-lg-last { + order: 999; + } +} + +/* Card component CSS variable definitions */ +:root { + --card-back-color: #f8f8f8; + --card-fore-color: #111; + --card-border-color: #ddd; +} + +.card { + display: flex; + flex-direction: column; + justify-content: space-between; + align-self: center; + position: relative; + width: 100%; + background: var(--card-back-color); + color: var(--card-fore-color); + border: 0.0625rem solid var(--card-border-color); + border-radius: var(--universal-border-radius); + margin: var(--universal-margin); + overflow: hidden; +} + +@media screen and (min-width: 320px) { + .card { + max-width: 320px; + } +} + +.card > .section { + background: var(--card-back-color); + color: var(--card-fore-color); + box-sizing: border-box; + margin: 0; + border: 0; + border-radius: 0; + border-bottom: 0.0625rem solid var(--card-border-color); + padding: var(--universal-padding); + width: 100%; +} + +.card > .section.media { + height: 200px; + padding: 0; + -o-object-fit: cover; + object-fit: cover; +} + +.card > .section:last-child { + border-bottom: 0; +} + +/* + Custom elements for card elements. +*/ +@media screen and (min-width: 240px) { + .card.small { + max-width: 240px; + } +} + +@media screen and (min-width: 480px) { + .card.large { + max-width: 480px; + } +} + +.card.fluid { + max-width: 100%; + width: auto; +} + +.card.warning { + --card-back-color: #ffca28; + --card-border-color: #e8b825; +} + +.card.error { + --card-back-color: #b71c1c; + --card-fore-color: #f8f8f8; + --card-border-color: #a71a1a; +} + +.card > .section.dark { + --card-back-color: #e0e0e0; +} + +.card > .section.double-padded { + padding: calc(1.5 * var(--universal-padding)); +} + +/* + Definitions for forms and input elements. +*/ +/* Input_control module CSS variable definitions */ +:root { + --form-back-color: #f0f0f0; + --form-fore-color: #111; + --form-border-color: #ddd; + --input-back-color: #f8f8f8; + --input-fore-color: #111; + --input-border-color: #ddd; + --input-focus-color: #0288d1; + --input-invalid-color: #d32f2f; + --button-back-color: #e2e2e2; + --button-hover-back-color: #dcdcdc; + --button-fore-color: #212121; + --button-border-color: transparent; + --button-hover-border-color: transparent; + --button-group-border-color: rgba(124, 124, 124, 0.54); +} + +form { + background: var(--form-back-color); + color: var(--form-fore-color); + border: 0.0625rem solid var(--form-border-color); + border-radius: var(--universal-border-radius); + margin: var(--universal-margin); + padding: calc(2 * var(--universal-padding)) var(--universal-padding); +} + +fieldset { + border: 0.0625rem solid var(--form-border-color); + border-radius: var(--universal-border-radius); + margin: calc(var(--universal-margin) / 4); + padding: var(--universal-padding); +} + +legend { + box-sizing: border-box; + display: table; + max-width: 100%; + white-space: normal; + font-weight: 700; + padding: calc(var(--universal-padding) / 2); +} + +label { + padding: calc(var(--universal-padding) / 2) var(--universal-padding); +} + +.input-group { + display: inline-block; +} + +.input-group.fluid { + display: flex; + align-items: center; + justify-content: center; +} + +.input-group.fluid > input { + max-width: 100%; + flex-grow: 1; + flex-basis: 0px; +} + +@media screen and (max-width: 767px) { + .input-group.fluid { + align-items: stretch; + flex-direction: column; + } +} + +.input-group.vertical { + display: flex; + align-items: stretch; + flex-direction: column; +} + +.input-group.vertical > input { + max-width: 100%; + flex-grow: 1; + flex-basis: 0px; +} + +[type="number"]::-webkit-inner-spin-button, [type="number"]::-webkit-outer-spin-button { + height: auto; +} + +[type="search"] { + -webkit-appearance: textfield; + outline-offset: -2px; +} + +[type="search"]::-webkit-search-cancel-button, +[type="search"]::-webkit-search-decoration { + -webkit-appearance: none; +} + +input:not([type]), [type="text"], [type="email"], [type="number"], [type="search"], +[type="password"], [type="url"], [type="tel"], [type="checkbox"], [type="radio"], textarea, select { + box-sizing: border-box; + background: var(--input-back-color); + color: var(--input-fore-color); + border: 0.0625rem solid var(--input-border-color); + border-radius: var(--universal-border-radius); + margin: calc(var(--universal-margin) / 2); + padding: var(--universal-padding) calc(1.5 * var(--universal-padding)); +} + +input:not([type="button"]):not([type="submit"]):not([type="reset"]):hover, input:not([type="button"]):not([type="submit"]):not([type="reset"]):focus, textarea:hover, textarea:focus, select:hover, select:focus { + border-color: var(--input-focus-color); + box-shadow: none; +} + +input:not([type="button"]):not([type="submit"]):not([type="reset"]):invalid, input:not([type="button"]):not([type="submit"]):not([type="reset"]):focus:invalid, textarea:invalid, textarea:focus:invalid, select:invalid, select:focus:invalid { + border-color: var(--input-invalid-color); + box-shadow: none; +} + +input:not([type="button"]):not([type="submit"]):not([type="reset"])[readonly], textarea[readonly], select[readonly] { + background: var(--secondary-back-color); +} + +select { + max-width: 100%; +} + +option { + overflow: hidden; + text-overflow: ellipsis; +} + +[type="checkbox"], [type="radio"] { + -webkit-appearance: none; + -moz-appearance: none; + appearance: none; + position: relative; + height: calc(1rem + var(--universal-padding) / 2); + width: calc(1rem + var(--universal-padding) / 2); + vertical-align: text-bottom; + padding: 0; + flex-basis: calc(1rem + var(--universal-padding) / 2) !important; + flex-grow: 0 !important; +} + +[type="checkbox"]:checked:before, [type="radio"]:checked:before { + position: absolute; +} + +[type="checkbox"]:checked:before { + content: '\2713'; + font-family: sans-serif; + font-size: calc(1rem + var(--universal-padding) / 2); + top: calc(0rem - var(--universal-padding)); + left: calc(var(--universal-padding) / 4); +} + +[type="radio"] { + border-radius: 100%; +} + +[type="radio"]:checked:before { + border-radius: 100%; + content: ''; + top: calc(0.0625rem + var(--universal-padding) / 2); + left: calc(0.0625rem + var(--universal-padding) / 2); + background: var(--input-fore-color); + width: 0.5rem; + height: 0.5rem; +} + +:placeholder-shown { + color: var(--input-fore-color); +} + +::-ms-placeholder { + color: var(--input-fore-color); + opacity: 0.54; +} + +button::-moz-focus-inner, [type="button"]::-moz-focus-inner, [type="reset"]::-moz-focus-inner, [type="submit"]::-moz-focus-inner { + border-style: none; + padding: 0; +} + +button, html [type="button"], [type="reset"], [type="submit"] { + -webkit-appearance: button; +} + +button { + overflow: visible; + text-transform: none; +} + +button, [type="button"], [type="submit"], [type="reset"], +a.button, label.button, .button, +a[role="button"], label[role="button"], [role="button"] { + display: inline-block; + background: var(--button-back-color); + color: var(--button-fore-color); + border: 0.0625rem solid var(--button-border-color); + border-radius: var(--universal-border-radius); + padding: var(--universal-padding) calc(1.5 * var(--universal-padding)); + margin: var(--universal-margin); + text-decoration: none; + cursor: pointer; + transition: background 0.3s; +} + +button:hover, button:focus, [type="button"]:hover, [type="button"]:focus, [type="submit"]:hover, [type="submit"]:focus, [type="reset"]:hover, [type="reset"]:focus, +a.button:hover, +a.button:focus, label.button:hover, label.button:focus, .button:hover, .button:focus, +a[role="button"]:hover, +a[role="button"]:focus, label[role="button"]:hover, label[role="button"]:focus, [role="button"]:hover, [role="button"]:focus { + background: var(--button-hover-back-color); + border-color: var(--button-hover-border-color); +} + +input:disabled, input[disabled], textarea:disabled, textarea[disabled], select:disabled, select[disabled], button:disabled, button[disabled], .button:disabled, .button[disabled], [role="button"]:disabled, [role="button"][disabled] { + cursor: not-allowed; + opacity: 0.75; +} + +.button-group { + display: flex; + border: 0.0625rem solid var(--button-group-border-color); + border-radius: var(--universal-border-radius); + margin: var(--universal-margin); +} + +.button-group > button, .button-group [type="button"], .button-group > [type="submit"], .button-group > [type="reset"], +.button-group > .button, .button-group > [role="button"] { + margin: 0; + max-width: 100%; + flex: 1 1 auto; + text-align: center; + border: 0; + border-radius: 0; + box-shadow: none; +} + +.button-group > :not(:first-child) { + border-left: 0.0625rem solid var(--button-group-border-color); +} + +@media screen and (max-width: 767px) { + .button-group { + flex-direction: column; + } + .button-group > :not(:first-child) { + border: 0; + border-top: 0.0625rem solid var(--button-group-border-color); + } +} + +/* + Custom elements for forms and input elements. +*/ +button.primary, [type="button"].primary, [type="submit"].primary, [type="reset"].primary, .button.primary, [role="button"].primary { + --button-back-color: #1976d2; + --button-fore-color: #f8f8f8; +} + +button.primary:hover, button.primary:focus, [type="button"].primary:hover, [type="button"].primary:focus, [type="submit"].primary:hover, [type="submit"].primary:focus, [type="reset"].primary:hover, [type="reset"].primary:focus, .button.primary:hover, .button.primary:focus, [role="button"].primary:hover, [role="button"].primary:focus { + --button-hover-back-color: #1565c0; +} + +button.secondary, [type="button"].secondary, [type="submit"].secondary, [type="reset"].secondary, .button.secondary, [role="button"].secondary { + --button-back-color: #d32f2f; + --button-fore-color: #f8f8f8; +} + +button.secondary:hover, button.secondary:focus, [type="button"].secondary:hover, [type="button"].secondary:focus, [type="submit"].secondary:hover, [type="submit"].secondary:focus, [type="reset"].secondary:hover, [type="reset"].secondary:focus, .button.secondary:hover, .button.secondary:focus, [role="button"].secondary:hover, [role="button"].secondary:focus { + --button-hover-back-color: #c62828; +} + +button.tertiary, [type="button"].tertiary, [type="submit"].tertiary, [type="reset"].tertiary, .button.tertiary, [role="button"].tertiary { + --button-back-color: #308732; + --button-fore-color: #f8f8f8; +} + +button.tertiary:hover, button.tertiary:focus, [type="button"].tertiary:hover, [type="button"].tertiary:focus, [type="submit"].tertiary:hover, [type="submit"].tertiary:focus, [type="reset"].tertiary:hover, [type="reset"].tertiary:focus, .button.tertiary:hover, .button.tertiary:focus, [role="button"].tertiary:hover, [role="button"].tertiary:focus { + --button-hover-back-color: #277529; +} + +button.inverse, [type="button"].inverse, [type="submit"].inverse, [type="reset"].inverse, .button.inverse, [role="button"].inverse { + --button-back-color: #212121; + --button-fore-color: #f8f8f8; +} + +button.inverse:hover, button.inverse:focus, [type="button"].inverse:hover, [type="button"].inverse:focus, [type="submit"].inverse:hover, [type="submit"].inverse:focus, [type="reset"].inverse:hover, [type="reset"].inverse:focus, .button.inverse:hover, .button.inverse:focus, [role="button"].inverse:hover, [role="button"].inverse:focus { + --button-hover-back-color: #111; +} + +button.small, [type="button"].small, [type="submit"].small, [type="reset"].small, .button.small, [role="button"].small { + padding: calc(0.5 * var(--universal-padding)) calc(0.75 * var(--universal-padding)); + margin: var(--universal-margin); +} + +button.large, [type="button"].large, [type="submit"].large, [type="reset"].large, .button.large, [role="button"].large { + padding: calc(1.5 * var(--universal-padding)) calc(2 * var(--universal-padding)); + margin: var(--universal-margin); +} + +/* + Definitions for navigation elements. +*/ +/* Navigation module CSS variable definitions */ +:root { + --header-back-color: #f8f8f8; + --header-hover-back-color: #f0f0f0; + --header-fore-color: #444; + --header-border-color: #ddd; + --nav-back-color: #f8f8f8; + --nav-hover-back-color: #f0f0f0; + --nav-fore-color: #444; + --nav-border-color: #ddd; + --nav-link-color: #0277bd; + --footer-fore-color: #444; + --footer-back-color: #f8f8f8; + --footer-border-color: #ddd; + --footer-link-color: #0277bd; + --drawer-back-color: #f8f8f8; + --drawer-hover-back-color: #f0f0f0; + --drawer-border-color: #ddd; + --drawer-close-color: #444; +} + +header { + height: 3.1875rem; + background: var(--header-back-color); + color: var(--header-fore-color); + border-bottom: 0.0625rem solid var(--header-border-color); + padding: calc(var(--universal-padding) / 4) 0; + white-space: nowrap; + overflow-x: auto; + overflow-y: hidden; +} + +header.row { + box-sizing: content-box; +} + +header .logo { + color: var(--header-fore-color); + font-size: 1.75rem; + padding: var(--universal-padding) calc(2 * var(--universal-padding)); + text-decoration: none; +} + +header button, header [type="button"], header .button, header [role="button"] { + box-sizing: border-box; + position: relative; + top: calc(0rem - var(--universal-padding) / 4); + height: calc(3.1875rem + var(--universal-padding) / 2); + background: var(--header-back-color); + line-height: calc(3.1875rem - var(--universal-padding) * 1.5); + text-align: center; + color: var(--header-fore-color); + border: 0; + border-radius: 0; + margin: 0; + text-transform: uppercase; +} + +header button:hover, header button:focus, header [type="button"]:hover, header [type="button"]:focus, header .button:hover, header .button:focus, header [role="button"]:hover, header [role="button"]:focus { + background: var(--header-hover-back-color); +} + +nav { + background: var(--nav-back-color); + color: var(--nav-fore-color); + border: 0.0625rem solid var(--nav-border-color); + border-radius: var(--universal-border-radius); + margin: var(--universal-margin); +} + +nav * { + padding: var(--universal-padding) calc(1.5 * var(--universal-padding)); +} + +nav a, nav a:visited { + display: block; + color: var(--nav-link-color); + border-radius: var(--universal-border-radius); + transition: background 0.3s; +} + +nav a:hover, nav a:focus, nav a:visited:hover, nav a:visited:focus { + text-decoration: none; + background: var(--nav-hover-back-color); +} + +nav .sublink-1 { + position: relative; + margin-left: calc(2 * var(--universal-padding)); +} + +nav .sublink-1:before { + position: absolute; + left: calc(var(--universal-padding) - 1 * var(--universal-padding)); + top: -0.0625rem; + content: ''; + height: 100%; + border: 0.0625rem solid var(--nav-border-color); + border-left: 0; +} + +nav .sublink-2 { + position: relative; + margin-left: calc(4 * var(--universal-padding)); +} + +nav .sublink-2:before { + position: absolute; + left: calc(var(--universal-padding) - 3 * var(--universal-padding)); + top: -0.0625rem; + content: ''; + height: 100%; + border: 0.0625rem solid var(--nav-border-color); + border-left: 0; +} + +footer { + background: var(--footer-back-color); + color: var(--footer-fore-color); + border-top: 0.0625rem solid var(--footer-border-color); + padding: calc(2 * var(--universal-padding)) var(--universal-padding); + font-size: 0.875rem; +} + +footer a, footer a:visited { + color: var(--footer-link-color); +} + +header.sticky { + position: -webkit-sticky; + position: sticky; + z-index: 1101; + top: 0; +} + +footer.sticky { + position: -webkit-sticky; + position: sticky; + z-index: 1101; + bottom: 0; +} + +.drawer-toggle:before { + display: inline-block; + position: relative; + vertical-align: bottom; + content: '\00a0\2261\00a0'; + font-family: sans-serif; + font-size: 1.5em; +} + +@media screen and (min-width: 768px) { + .drawer-toggle:not(.persistent) { + display: none; + } +} + +[type="checkbox"].drawer { + height: 1px; + width: 1px; + margin: -1px; + overflow: hidden; + position: absolute; + clip: rect(0 0 0 0); + -webkit-clip-path: inset(100%); + clip-path: inset(100%); +} + +[type="checkbox"].drawer + * { + display: block; + box-sizing: border-box; + position: fixed; + top: 0; + width: 320px; + height: 100vh; + overflow-y: auto; + background: var(--drawer-back-color); + border: 0.0625rem solid var(--drawer-border-color); + border-radius: 0; + margin: 0; + z-index: 1110; + right: -320px; + transition: right 0.3s; +} + +[type="checkbox"].drawer + * .drawer-close { + position: absolute; + top: var(--universal-margin); + right: var(--universal-margin); + z-index: 1111; + width: 2rem; + height: 2rem; + border-radius: var(--universal-border-radius); + padding: var(--universal-padding); + margin: 0; + cursor: pointer; + transition: background 0.3s; +} + +[type="checkbox"].drawer + * .drawer-close:before { + display: block; + content: '\00D7'; + color: var(--drawer-close-color); + position: relative; + font-family: sans-serif; + font-size: 2rem; + line-height: 1; + text-align: center; +} + +[type="checkbox"].drawer + * .drawer-close:hover, [type="checkbox"].drawer + * .drawer-close:focus { + background: var(--drawer-hover-back-color); +} + +@media screen and (max-width: 320px) { + [type="checkbox"].drawer + * { + width: 100%; + } +} + +[type="checkbox"].drawer:checked + * { + right: 0; +} + +@media screen and (min-width: 768px) { + [type="checkbox"].drawer:not(.persistent) + * { + position: static; + height: 100%; + z-index: 1100; + } + [type="checkbox"].drawer:not(.persistent) + * .drawer-close { + display: none; + } +} + +/* + Definitions for the responsive table component. +*/ +/* Table module CSS variable definitions. */ +:root { + --table-border-color: #aaa; + --table-border-separator-color: #666; + --table-head-back-color: #e6e6e6; + --table-head-fore-color: #111; + --table-body-back-color: #f8f8f8; + --table-body-fore-color: #111; + --table-body-alt-back-color: #eee; +} + +table { + border-collapse: separate; + border-spacing: 0; + margin: 0; + display: flex; + flex: 0 1 auto; + flex-flow: row wrap; + padding: var(--universal-padding); + padding-top: 0; +} + +table caption { + font-size: 1.5rem; + margin: calc(2 * var(--universal-margin)) 0; + max-width: 100%; + flex: 0 0 100%; +} + +table thead, table tbody { + display: flex; + flex-flow: row wrap; + border: 0.0625rem solid var(--table-border-color); +} + +table thead { + z-index: 999; + border-radius: var(--universal-border-radius) var(--universal-border-radius) 0 0; + border-bottom: 0.0625rem solid var(--table-border-separator-color); +} + +table tbody { + border-top: 0; + margin-top: calc(0 - var(--universal-margin)); + border-radius: 0 0 var(--universal-border-radius) var(--universal-border-radius); +} + +table tr { + display: flex; + padding: 0; +} + +table th, table td { + padding: calc(2 * var(--universal-padding)); +} + +table th { + text-align: left; + background: var(--table-head-back-color); + color: var(--table-head-fore-color); +} + +table td { + background: var(--table-body-back-color); + color: var(--table-body-fore-color); + border-top: 0.0625rem solid var(--table-border-color); +} + +table:not(.horizontal) { + overflow: auto; + max-height: 400px; +} + +table:not(.horizontal) thead, table:not(.horizontal) tbody { + max-width: 100%; + flex: 0 0 100%; +} + +table:not(.horizontal) tr { + flex-flow: row wrap; + flex: 0 0 100%; +} + +table:not(.horizontal) th, table:not(.horizontal) td { + flex: 1 0 0%; + overflow: hidden; + text-overflow: ellipsis; +} + +table:not(.horizontal) thead { + position: sticky; + top: 0; +} + +table:not(.horizontal) tbody tr:first-child td { + border-top: 0; +} + +table.horizontal { + border: 0; +} + +table.horizontal thead, table.horizontal tbody { + border: 0; + flex: .2 0 0; + flex-flow: row nowrap; +} + +table.horizontal tbody { + overflow: auto; + justify-content: space-between; + flex: .8 0 0; + margin-left: 0; + padding-bottom: calc(var(--universal-padding) / 4); +} + +table.horizontal tr { + flex-direction: column; + flex: 1 0 auto; +} + +table.horizontal th, table.horizontal td { + width: auto; + border: 0; + border-bottom: 0.0625rem solid var(--table-border-color); +} + +table.horizontal th:not(:first-child), table.horizontal td:not(:first-child) { + border-top: 0; +} + +table.horizontal th { + text-align: right; + border-left: 0.0625rem solid var(--table-border-color); + border-right: 0.0625rem solid var(--table-border-separator-color); +} + +table.horizontal thead tr:first-child { + padding-left: 0; +} + +table.horizontal th:first-child, table.horizontal td:first-child { + border-top: 0.0625rem solid var(--table-border-color); +} + +table.horizontal tbody tr:last-child td { + border-right: 0.0625rem solid var(--table-border-color); +} + +table.horizontal tbody tr:last-child td:first-child { + border-top-right-radius: 0.25rem; +} + +table.horizontal tbody tr:last-child td:last-child { + border-bottom-right-radius: 0.25rem; +} + +table.horizontal thead tr:first-child th:first-child { + border-top-left-radius: 0.25rem; +} + +table.horizontal thead tr:first-child th:last-child { + border-bottom-left-radius: 0.25rem; +} + +@media screen and (max-width: 767px) { + table, table.horizontal { + border-collapse: collapse; + border: 0; + width: 100%; + display: table; + } + table thead, table th, table.horizontal thead, table.horizontal th { + border: 0; + height: 1px; + width: 1px; + margin: -1px; + overflow: hidden; + padding: 0; + position: absolute; + clip: rect(0 0 0 0); + -webkit-clip-path: inset(100%); + clip-path: inset(100%); + } + table tbody, table.horizontal tbody { + border: 0; + display: table-row-group; + } + table tr, table.horizontal tr { + display: block; + border: 0.0625rem solid var(--table-border-color); + border-radius: var(--universal-border-radius); + background: #fafafa; + padding: var(--universal-padding); + margin: var(--universal-margin); + margin-bottom: calc(2 * var(--universal-margin)); + } + table th, table td, table.horizontal th, table.horizontal td { + width: auto; + } + table td, table.horizontal td { + display: block; + border: 0; + text-align: right; + } + table td:before, table.horizontal td:before { + content: attr(data-label); + float: left; + font-weight: 600; + } + table th:first-child, table td:first-child, table.horizontal th:first-child, table.horizontal td:first-child { + border-top: 0; + } + table tbody tr:last-child td, table.horizontal tbody tr:last-child td { + border-right: 0; + } +} + +:root { + --table-body-alt-back-color: #eee; +} + +table.striped tr:nth-of-type(2n) > td { + background: var(--table-body-alt-back-color); +} + +@media screen and (max-width: 768px) { + table.striped tr:nth-of-type(2n) { + background: var(--table-body-alt-back-color); + } +} + +:root { + --table-body-hover-back-color: #90caf9; +} + +table.hoverable tr:hover, table.hoverable tr:hover > td, table.hoverable tr:focus, table.hoverable tr:focus > td { + background: var(--table-body-hover-back-color); +} + +@media screen and (max-width: 768px) { + table.hoverable tr:hover, table.hoverable tr:hover > td, table.hoverable tr:focus, table.hoverable tr:focus > td { + background: var(--table-body-hover-back-color); + } +} + +/* + Definitions for contextual background elements, toasts and tooltips. +*/ +/* Contextual module CSS variable definitions */ +:root { + --mark-back-color: #0277bd; + --mark-fore-color: #fafafa; +} + +mark { + background: var(--mark-back-color); + color: var(--mark-fore-color); + font-size: 0.95em; + line-height: 1em; + border-radius: var(--universal-border-radius); + padding: calc(var(--universal-padding) / 4) calc(var(--universal-padding) / 2); +} + +mark.inline-block { + display: inline-block; + font-size: 1em; + line-height: 1.5; + padding: calc(var(--universal-padding) / 2) var(--universal-padding); +} + +:root { + --toast-back-color: #424242; + --toast-fore-color: #fafafa; +} + +.toast { + position: fixed; + bottom: calc(var(--universal-margin) * 3); + left: 50%; + transform: translate(-50%, -50%); + z-index: 1111; + color: var(--toast-fore-color); + background: var(--toast-back-color); + border-radius: calc(var(--universal-border-radius) * 16); + padding: var(--universal-padding) calc(var(--universal-padding) * 3); +} + +:root { + --tooltip-back-color: #212121; + --tooltip-fore-color: #fafafa; +} + +.tooltip { + position: relative; + display: inline-block; +} + +.tooltip:before, .tooltip:after { + position: absolute; + opacity: 0; + clip: rect(0 0 0 0); + -webkit-clip-path: inset(100%); + clip-path: inset(100%); + transition: all 0.3s; + z-index: 1010; + left: 50%; +} + +.tooltip:not(.bottom):before, .tooltip:not(.bottom):after { + bottom: 75%; +} + +.tooltip.bottom:before, .tooltip.bottom:after { + top: 75%; +} + +.tooltip:hover:before, .tooltip:hover:after, .tooltip:focus:before, .tooltip:focus:after { + opacity: 1; + clip: auto; + -webkit-clip-path: inset(0%); + clip-path: inset(0%); +} + +.tooltip:before { + content: ''; + background: transparent; + border: var(--universal-margin) solid transparent; + left: calc(50% - var(--universal-margin)); +} + +.tooltip:not(.bottom):before { + border-top-color: #212121; +} + +.tooltip.bottom:before { + border-bottom-color: #212121; +} + +.tooltip:after { + content: attr(aria-label); + color: var(--tooltip-fore-color); + background: var(--tooltip-back-color); + border-radius: var(--universal-border-radius); + padding: var(--universal-padding); + white-space: nowrap; + transform: translateX(-50%); +} + +.tooltip:not(.bottom):after { + margin-bottom: calc(2 * var(--universal-margin)); +} + +.tooltip.bottom:after { + margin-top: calc(2 * var(--universal-margin)); +} + +:root { + --modal-overlay-color: rgba(0, 0, 0, 0.45); + --modal-close-color: #444; + --modal-close-hover-color: #f0f0f0; +} + +[type="checkbox"].modal { + height: 1px; + width: 1px; + margin: -1px; + overflow: hidden; + position: absolute; + clip: rect(0 0 0 0); + -webkit-clip-path: inset(100%); + clip-path: inset(100%); +} + +[type="checkbox"].modal + div { + position: fixed; + top: 0; + left: 0; + display: none; + width: 100vw; + height: 100vh; + background: var(--modal-overlay-color); +} + +[type="checkbox"].modal + div .card { + margin: 0 auto; + max-height: 50vh; + overflow: auto; +} + +[type="checkbox"].modal + div .card .modal-close { + position: absolute; + top: 0; + right: 0; + width: 1.75rem; + height: 1.75rem; + border-radius: var(--universal-border-radius); + padding: var(--universal-padding); + margin: 0; + cursor: pointer; + transition: background 0.3s; +} + +[type="checkbox"].modal + div .card .modal-close:before { + display: block; + content: '\00D7'; + color: var(--modal-close-color); + position: relative; + font-family: sans-serif; + font-size: 1.75rem; + line-height: 1; + text-align: center; +} + +[type="checkbox"].modal + div .card .modal-close:hover, [type="checkbox"].modal + div .card .modal-close:focus { + background: var(--modal-close-hover-color); +} + +[type="checkbox"].modal:checked + div { + display: flex; + flex: 0 1 auto; + z-index: 1200; +} + +[type="checkbox"].modal:checked + div .card .modal-close { + z-index: 1211; +} + +:root { + --collapse-label-back-color: #e8e8e8; + --collapse-label-fore-color: #212121; + --collapse-label-hover-back-color: #f0f0f0; + --collapse-selected-label-back-color: #ececec; + --collapse-border-color: #ddd; + --collapse-content-back-color: #fafafa; + --collapse-selected-label-border-color: #0277bd; +} + +.collapse { + width: calc(100% - 2 * var(--universal-margin)); + opacity: 1; + display: flex; + flex-direction: column; + margin: var(--universal-margin); + border-radius: var(--universal-border-radius); +} + +.collapse > [type="radio"], .collapse > [type="checkbox"] { + height: 1px; + width: 1px; + margin: -1px; + overflow: hidden; + position: absolute; + clip: rect(0 0 0 0); + -webkit-clip-path: inset(100%); + clip-path: inset(100%); +} + +.collapse > label { + flex-grow: 1; + display: inline-block; + height: 1.5rem; + cursor: pointer; + transition: background 0.3s; + color: var(--collapse-label-fore-color); + background: var(--collapse-label-back-color); + border: 0.0625rem solid var(--collapse-border-color); + padding: calc(1.5 * var(--universal-padding)); +} + +.collapse > label:hover, .collapse > label:focus { + background: var(--collapse-label-hover-back-color); +} + +.collapse > label + div { + flex-basis: auto; + height: 1px; + width: 1px; + margin: -1px; + overflow: hidden; + position: absolute; + clip: rect(0 0 0 0); + -webkit-clip-path: inset(100%); + clip-path: inset(100%); + transition: max-height 0.3s; + max-height: 1px; +} + +.collapse > :checked + label { + background: var(--collapse-selected-label-back-color); + border-bottom-color: var(--collapse-selected-label-border-color); +} + +.collapse > :checked + label + div { + box-sizing: border-box; + position: relative; + width: 100%; + height: auto; + overflow: auto; + margin: 0; + background: var(--collapse-content-back-color); + border: 0.0625rem solid var(--collapse-border-color); + border-top: 0; + padding: var(--universal-padding); + clip: auto; + -webkit-clip-path: inset(0%); + clip-path: inset(0%); + max-height: 400px; +} + +.collapse > label:not(:first-of-type) { + border-top: 0; +} + +.collapse > label:first-of-type { + border-radius: var(--universal-border-radius) var(--universal-border-radius) 0 0; +} + +.collapse > label:last-of-type:not(:first-of-type) { + border-radius: 0 0 var(--universal-border-radius) var(--universal-border-radius); +} + +.collapse > label:last-of-type:first-of-type { + border-radius: var(--universal-border-radius); +} + +.collapse > :checked:last-of-type:not(:first-of-type) + label { + border-radius: 0; +} + +.collapse > :checked:last-of-type + label + div { + border-radius: 0 0 var(--universal-border-radius) var(--universal-border-radius); +} + +/* + Custom elements for contextual background elements, toasts and tooltips. +*/ +mark.secondary { + --mark-back-color: #d32f2f; +} + +mark.tertiary { + --mark-back-color: #308732; +} + +mark.tag { + padding: calc(var(--universal-padding)/2) var(--universal-padding); + border-radius: 1em; +} + +/* + Definitions for progress elements and spinners. +*/ +/* Progess module CSS variable definitions */ +:root { + --progress-back-color: #ddd; + --progress-fore-color: #555; +} + +progress { + display: block; + vertical-align: baseline; + -webkit-appearance: none; + -moz-appearance: none; + appearance: none; + height: 0.75rem; + width: calc(100% - 2 * var(--universal-margin)); + margin: var(--universal-margin); + border: 0; + border-radius: calc(2 * var(--universal-border-radius)); + background: var(--progress-back-color); + color: var(--progress-fore-color); +} + +progress::-webkit-progress-value { + background: var(--progress-fore-color); + border-top-left-radius: calc(2 * var(--universal-border-radius)); + border-bottom-left-radius: calc(2 * var(--universal-border-radius)); +} + +progress::-webkit-progress-bar { + background: var(--progress-back-color); +} + +progress::-moz-progress-bar { + background: var(--progress-fore-color); + border-top-left-radius: calc(2 * var(--universal-border-radius)); + border-bottom-left-radius: calc(2 * var(--universal-border-radius)); +} + +progress[value="1000"]::-webkit-progress-value { + border-radius: calc(2 * var(--universal-border-radius)); +} + +progress[value="1000"]::-moz-progress-bar { + border-radius: calc(2 * var(--universal-border-radius)); +} + +progress.inline { + display: inline-block; + vertical-align: middle; + width: 60%; +} + +:root { + --spinner-back-color: #ddd; + --spinner-fore-color: #555; +} + +@keyframes spinner-donut-anim { + 0% { + transform: rotate(0deg); + } + 100% { + transform: rotate(360deg); + } +} + +.spinner { + display: inline-block; + margin: var(--universal-margin); + border: 0.25rem solid var(--spinner-back-color); + border-left: 0.25rem solid var(--spinner-fore-color); + border-radius: 50%; + width: 1.25rem; + height: 1.25rem; + animation: spinner-donut-anim 1.2s linear infinite; +} + +/* + Custom elements for progress bars and spinners. +*/ +progress.primary { + --progress-fore-color: #1976d2; +} + +progress.secondary { + --progress-fore-color: #d32f2f; +} + +progress.tertiary { + --progress-fore-color: #308732; +} + +.spinner.primary { + --spinner-fore-color: #1976d2; +} + +.spinner.secondary { + --spinner-fore-color: #d32f2f; +} + +.spinner.tertiary { + --spinner-fore-color: #308732; +} + +/* + Definitions for icons - powered by Feather (https://feathericons.com/). +*/ +span[class^='icon-'] { + display: inline-block; + height: 1em; + width: 1em; + vertical-align: -0.125em; + background-size: contain; + margin: 0 calc(var(--universal-margin) / 4); +} + +span[class^='icon-'].secondary { + -webkit-filter: invert(25%); + filter: invert(25%); +} + +span[class^='icon-'].inverse { + -webkit-filter: invert(100%); + filter: invert(100%); +} + +span.icon-alert { + background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='%23111' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='10'%3E%3C/circle%3E%3Cline x1='12' y1='8' x2='12' y2='12'%3E%3C/line%3E%3Cline x1='12' y1='16' x2='12' y2='16'%3E%3C/line%3E%3C/svg%3E"); +} + +span.icon-bookmark { + background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='%23111' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M19 21l-7-5-7 5V5a2 2 0 0 1 2-2h10a2 2 0 0 1 2 2z'%3E%3C/path%3E%3C/svg%3E"); +} + +span.icon-calendar { + background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='%23111' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect x='3' y='4' width='18' height='18' rx='2' ry='2'%3E%3C/rect%3E%3Cline x1='16' y1='2' x2='16' y2='6'%3E%3C/line%3E%3Cline x1='8' y1='2' x2='8' y2='6'%3E%3C/line%3E%3Cline x1='3' y1='10' x2='21' y2='10'%3E%3C/line%3E%3C/svg%3E"); +} + +span.icon-credit { + background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='%23111' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect x='1' y='4' width='22' height='16' rx='2' ry='2'%3E%3C/rect%3E%3Cline x1='1' y1='10' x2='23' y2='10'%3E%3C/line%3E%3C/svg%3E"); +} + +span.icon-edit { + background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='%23111' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M20 14.66V20a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2V6a2 2 0 0 1 2-2h5.34'%3E%3C/path%3E%3Cpolygon points='18 2 22 6 12 16 8 16 8 12 18 2'%3E%3C/polygon%3E%3C/svg%3E"); +} + +span.icon-link { + background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='%23111' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6'%3E%3C/path%3E%3Cpolyline points='15 3 21 3 21 9'%3E%3C/polyline%3E%3Cline x1='10' y1='14' x2='21' y2='3'%3E%3C/line%3E%3C/svg%3E"); +} + +span.icon-help { + background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='%23111' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M9.09 9a3 3 0 0 1 5.83 1c0 2-3 3-3 3'%3E%3C/path%3E%3Ccircle cx='12' cy='12' r='10'%3E%3C/circle%3E%3Cline x1='12' y1='17' x2='12' y2='17'%3E%3C/line%3E%3C/svg%3E"); +} + +span.icon-home { + background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='%23111' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M3 9l9-7 9 7v11a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z'%3E%3C/path%3E%3Cpolyline points='9 22 9 12 15 12 15 22'%3E%3C/polyline%3E%3C/svg%3E"); +} + +span.icon-info { + background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='%23111' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='10'%3E%3C/circle%3E%3Cline x1='12' y1='16' x2='12' y2='12'%3E%3C/line%3E%3Cline x1='12' y1='8' x2='12' y2='8'%3E%3C/line%3E%3C/svg%3E"); +} + +span.icon-lock { + background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='%23111' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect x='3' y='11' width='18' height='11' rx='2' ry='2'%3E%3C/rect%3E%3Cpath d='M7 11V7a5 5 0 0 1 10 0v4'%3E%3C/path%3E%3C/svg%3E"); +} + +span.icon-mail { + background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='%23111' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M4 4h16c1.1 0 2 .9 2 2v12c0 1.1-.9 2-2 2H4c-1.1 0-2-.9-2-2V6c0-1.1.9-2 2-2z'%3E%3C/path%3E%3Cpolyline points='22,6 12,13 2,6'%3E%3C/polyline%3E%3C/svg%3E"); +} + +span.icon-location { + background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='%23111' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M21 10c0 7-9 13-9 13s-9-6-9-13a9 9 0 0 1 18 0z'%3E%3C/path%3E%3Ccircle cx='12' cy='10' r='3'%3E%3C/circle%3E%3C/svg%3E"); +} + +span.icon-phone { + background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='%23111' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M22 16.92v3a2 2 0 0 1-2.18 2 19.79 19.79 0 0 1-8.63-3.07 19.5 19.5 0 0 1-6-6 19.79 19.79 0 0 1-3.07-8.67A2 2 0 0 1 4.11 2h3a2 2 0 0 1 2 1.72 12.84 12.84 0 0 0 .7 2.81 2 2 0 0 1-.45 2.11L8.09 9.91a16 16 0 0 0 6 6l1.27-1.27a2 2 0 0 1 2.11-.45 12.84 12.84 0 0 0 2.81.7A2 2 0 0 1 22 16.92z'%3E%3C/path%3E%3C/svg%3E"); +} + +span.icon-rss { + background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='%23111' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M4 11a9 9 0 0 1 9 9'%3E%3C/path%3E%3Cpath d='M4 4a16 16 0 0 1 16 16'%3E%3C/path%3E%3Ccircle cx='5' cy='19' r='1'%3E%3C/circle%3E%3C/svg%3E"); +} + +span.icon-search { + background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='%23111' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='11' cy='11' r='8'%3E%3C/circle%3E%3Cline x1='21' y1='21' x2='16.65' y2='16.65'%3E%3C/line%3E%3C/svg%3E"); +} + +span.icon-settings { + background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='%23111' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='3'%3E%3C/circle%3E%3Cpath d='M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 0 1 0 2.83 2 2 0 0 1-2.83 0l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 0 1-2 2 2 2 0 0 1-2-2v-.09A1.65 1.65 0 0 0 9 19.4a1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 0 1-2.83 0 2 2 0 0 1 0-2.83l.06-.06a1.65 1.65 0 0 0 .33-1.82 1.65 1.65 0 0 0-1.51-1H3a2 2 0 0 1-2-2 2 2 0 0 1 2-2h.09A1.65 1.65 0 0 0 4.6 9a1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 0 1 0-2.83 2 2 0 0 1 2.83 0l.06.06a1.65 1.65 0 0 0 1.82.33H9a1.65 1.65 0 0 0 1-1.51V3a2 2 0 0 1 2-2 2 2 0 0 1 2 2v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 0 1 2.83 0 2 2 0 0 1 0 2.83l-.06.06a1.65 1.65 0 0 0-.33 1.82V9a1.65 1.65 0 0 0 1.51 1H21a2 2 0 0 1 2 2 2 2 0 0 1-2 2h-.09a1.65 1.65 0 0 0-1.51 1z'%3E%3C/path%3E%3C/svg%3E"); +} + +span.icon-share { + background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='%23111' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='18' cy='5' r='3'%3E%3C/circle%3E%3Ccircle cx='6' cy='12' r='3'%3E%3C/circle%3E%3Ccircle cx='18' cy='19' r='3'%3E%3C/circle%3E%3Cline x1='8.59' y1='13.51' x2='15.42' y2='17.49'%3E%3C/line%3E%3Cline x1='15.41' y1='6.51' x2='8.59' y2='10.49'%3E%3C/line%3E%3C/svg%3E"); +} + +span.icon-cart { + background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='%23111' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='9' cy='21' r='1'%3E%3C/circle%3E%3Ccircle cx='20' cy='21' r='1'%3E%3C/circle%3E%3Cpath d='M1 1h4l2.68 13.39a2 2 0 0 0 2 1.61h9.72a2 2 0 0 0 2-1.61L23 6H6'%3E%3C/path%3E%3C/svg%3E"); +} + +span.icon-upload { + background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='%23111' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4'%3E%3C/path%3E%3Cpolyline points='17 8 12 3 7 8'%3E%3C/polyline%3E%3Cline x1='12' y1='3' x2='12' y2='15'%3E%3C/line%3E%3C/svg%3E"); +} + +span.icon-user { + background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='%23111' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M20 21v-2a4 4 0 0 0-4-4H8a4 4 0 0 0-4 4v2'%3E%3C/path%3E%3Ccircle cx='12' cy='7' r='4'%3E%3C/circle%3E%3C/svg%3E"); +} + +/* + Definitions for utilities and helper classes. +*/ +/* Utility module CSS variable definitions */ +:root { + --generic-border-color: rgba(0, 0, 0, 0.3); + --generic-box-shadow: 0 0.25rem 0.25rem 0 rgba(0, 0, 0, 0.125), 0 0.125rem 0.125rem -0.125rem rgba(0, 0, 0, 0.25); +} + +.hidden { + display: none !important; +} + +.visually-hidden { + position: absolute !important; + width: 1px !important; + height: 1px !important; + margin: -1px !important; + border: 0 !important; + padding: 0 !important; + clip: rect(0 0 0 0) !important; + -webkit-clip-path: inset(100%) !important; + clip-path: inset(100%) !important; + overflow: hidden !important; +} + +.bordered { + border: 0.0625rem solid var(--generic-border-color) !important; +} + +.rounded { + border-radius: var(--universal-border-radius) !important; +} + +.circular { + border-radius: 50% !important; +} + +.shadowed { + box-shadow: var(--generic-box-shadow) !important; +} + +.responsive-margin { + margin: calc(var(--universal-margin) / 4) !important; +} + +@media screen and (min-width: 768px) { + .responsive-margin { + margin: calc(var(--universal-margin) / 2) !important; + } +} + +@media screen and (min-width: 1280px) { + .responsive-margin { + margin: var(--universal-margin) !important; + } +} + +.responsive-padding { + padding: calc(var(--universal-padding) / 4) !important; +} + +@media screen and (min-width: 768px) { + .responsive-padding { + padding: calc(var(--universal-padding) / 2) !important; + } +} + +@media screen and (min-width: 1280px) { + .responsive-padding { + padding: var(--universal-padding) !important; + } +} + +@media screen and (max-width: 767px) { + .hidden-sm { + display: none !important; + } +} + +@media screen and (min-width: 768px) and (max-width: 1279px) { + .hidden-md { + display: none !important; + } +} + +@media screen and (min-width: 1280px) { + .hidden-lg { + display: none !important; + } +} + +@media screen and (max-width: 767px) { + .visually-hidden-sm { + position: absolute !important; + width: 1px !important; + height: 1px !important; + margin: -1px !important; + border: 0 !important; + padding: 0 !important; + clip: rect(0 0 0 0) !important; + -webkit-clip-path: inset(100%) !important; + clip-path: inset(100%) !important; + overflow: hidden !important; + } +} + +@media screen and (min-width: 768px) and (max-width: 1279px) { + .visually-hidden-md { + position: absolute !important; + width: 1px !important; + height: 1px !important; + margin: -1px !important; + border: 0 !important; + padding: 0 !important; + clip: rect(0 0 0 0) !important; + -webkit-clip-path: inset(100%) !important; + clip-path: inset(100%) !important; + overflow: hidden !important; + } +} + +@media screen and (min-width: 1280px) { + .visually-hidden-lg { + position: absolute !important; + width: 1px !important; + height: 1px !important; + margin: -1px !important; + border: 0 !important; + padding: 0 !important; + clip: rect(0 0 0 0) !important; + -webkit-clip-path: inset(100%) !important; + clip-path: inset(100%) !important; + overflow: hidden !important; + } +} diff --git a/themes/chrosey/css/style.css b/themes/chrosey/css/style.css index 935ba36..aad4aaa 100644 --- a/themes/chrosey/css/style.css +++ b/themes/chrosey/css/style.css @@ -3,7 +3,7 @@ :root { --fore-color: black; --secondary-fore-color: slategray; - --back-color: rgb(241, 241, 241); + --back-color: rgb(255, 255, 255); --secondary-back-color: #222; --blockquote-color: #f57c00; --pre-color: #1565c0; @@ -16,7 +16,7 @@ --a-link-color: #0277bd; --a-visited-color: #01579b; - --nav-back-color: var(--back-color); + --nav-back-color: rgba(0, 0, 0, 0.05); --nav-hover-back-color: rgba(0, 0, 0, 0.3); --nav-fore-color: var(--fore-color); --nav-border-color: var(--border-color); @@ -26,8 +26,6 @@ html { background-color: var(--back-color); font-family: 'Lato', sans-serif; - font-size: 16px; - line-height: 1.2; } .container { @@ -50,6 +48,8 @@ html { header { grid-column: 2 / span 2; + background: transparent; + border-bottom: 0; } h1, diff --git a/assets/logo.svg b/themes/chrosey/img/logo.svg similarity index 100% rename from assets/logo.svg rename to themes/chrosey/img/logo.svg diff --git a/themes/chrosey/templates/layout/base.twig b/themes/chrosey/templates/layout/base.twig index 6a188e6..3d9268f 100644 --- a/themes/chrosey/templates/layout/base.twig +++ b/themes/chrosey/templates/layout/base.twig @@ -7,7 +7,12 @@ - {% if meta.title %}{{ meta.title }} | {% endif %}{{ site_title }} + + {% if meta.title %} + {{ meta.title }} + | + {% endif %} + {{ site_title }} {% if meta.description %} @@ -23,7 +28,7 @@ {% endif %} + href="{{ theme_url }}/css/mini-default.css"> @@ -34,9 +39,12 @@
- - +
@@ -62,9 +70,10 @@ {{ content }} {% endblock %} +
- {% block footer %} {% endblock %} + {% block footer %}{% endblock %}