├── public ├── img │ └── .gitignore ├── .gitignore ├── robots.txt ├── sitemap.xml ├── api │ ├── .htaccess │ └── index.php ├── site.webmanifest ├── humans.txt └── addons │ └── copyable_captcha.php ├── src ├── style │ ├── Textpattern.css │ ├── Textpattern │ │ ├── sass │ │ │ ├── setup │ │ │ │ ├── _index.scss │ │ │ │ ├── _mixins.scss │ │ │ │ └── _settings.scss │ │ │ ├── modules │ │ │ │ ├── _http-errors.scss │ │ │ │ ├── _accessibility.scss │ │ │ │ ├── _index.scss │ │ │ │ ├── _misc.scss │ │ │ │ ├── fluxbb │ │ │ │ │ ├── _fluxbb_pagination.scss │ │ │ │ │ ├── _fluxbb_layout_admin.scss │ │ │ │ │ ├── _fluxbb_indicators.scss │ │ │ │ │ ├── _fluxbb_navigation.scss │ │ │ │ │ ├── _fluxbb_icons.scss │ │ │ │ │ └── _fluxbb_layout.scss │ │ │ │ ├── _lists.scss │ │ │ │ ├── _embedded-content.scss │ │ │ │ ├── _fonts.scss │ │ │ │ ├── _alerts.scss │ │ │ │ ├── _links.scss │ │ │ │ ├── _tables.scss │ │ │ │ ├── _code-highlighting.scss │ │ │ │ ├── _social.scss │ │ │ │ ├── _buttons.scss │ │ │ │ ├── _navigation.scss │ │ │ │ ├── _icons.scss │ │ │ │ ├── _typography.scss │ │ │ │ ├── _responsive.scss │ │ │ │ └── _forms.scss │ │ │ └── screen.scss │ │ ├── img │ │ │ ├── forum-icons.png │ │ │ ├── forum-icons@2x.png │ │ │ ├── dark-forum-icons.png │ │ │ └── dark-forum-icons@2x.png │ │ ├── fonts │ │ │ ├── pt-serif-v18-latin-ext-700.woff2 │ │ │ ├── pt-serif-v18-latin-ext-italic.woff2 │ │ │ ├── pt-serif-v18-latin-ext-regular.woff2 │ │ │ ├── pt-serif-v18-latin-ext-700italic.woff2 │ │ │ └── License.txt │ │ ├── base_admin.css │ │ ├── maintenance.tpl │ │ ├── js │ │ │ └── app.js │ │ ├── redirect.tpl │ │ ├── admin.tpl │ │ └── main.tpl │ └── .htaccess ├── 503.html ├── 500.html ├── 403.html └── 404.html ├── .github ├── PULL_REQUEST_TEMPLATE.md ├── dependabot.yml ├── ISSUE_TEMPLATE.md └── CODE_OF_CONDUCT.md ├── composer.json ├── .gitignore ├── .editorconfig ├── LICENSE ├── package.json ├── README.md └── Gruntfile.js /public/img/.gitignore: -------------------------------------------------------------------------------- 1 | /* 2 | !/.gitignore 3 | !/.htaccess -------------------------------------------------------------------------------- /src/style/Textpattern.css: -------------------------------------------------------------------------------- 1 | /** 2 | * Registers FluxBB style. 3 | */ 4 | -------------------------------------------------------------------------------- /src/style/Textpattern/sass/setup/_index.scss: -------------------------------------------------------------------------------- 1 | @forward "settings"; 2 | @forward "mixins"; 3 | -------------------------------------------------------------------------------- /src/style/Textpattern/img/forum-icons.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/textpattern/textpattern-forum/HEAD/src/style/Textpattern/img/forum-icons.png -------------------------------------------------------------------------------- /src/style/Textpattern/img/forum-icons@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/textpattern/textpattern-forum/HEAD/src/style/Textpattern/img/forum-icons@2x.png -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | Changes proposed in this pull request: 2 | 3 | - {Please write here} 4 | - {Please write here} 5 | - {Please write here} 6 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "config": { 3 | "vendor-dir": "public/vendor" 4 | }, 5 | "require": { 6 | "netcarver/textile": "3.8.0" 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /src/style/Textpattern/img/dark-forum-icons.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/textpattern/textpattern-forum/HEAD/src/style/Textpattern/img/dark-forum-icons.png -------------------------------------------------------------------------------- /src/style/Textpattern/img/dark-forum-icons@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/textpattern/textpattern-forum/HEAD/src/style/Textpattern/img/dark-forum-icons@2x.png -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: npm 4 | directory: "/" 5 | schedule: 6 | interval: daily 7 | open-pull-requests-limit: 10 8 | -------------------------------------------------------------------------------- /src/style/Textpattern/fonts/pt-serif-v18-latin-ext-700.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/textpattern/textpattern-forum/HEAD/src/style/Textpattern/fonts/pt-serif-v18-latin-ext-700.woff2 -------------------------------------------------------------------------------- /src/style/Textpattern/fonts/pt-serif-v18-latin-ext-italic.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/textpattern/textpattern-forum/HEAD/src/style/Textpattern/fonts/pt-serif-v18-latin-ext-italic.woff2 -------------------------------------------------------------------------------- /src/style/Textpattern/fonts/pt-serif-v18-latin-ext-regular.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/textpattern/textpattern-forum/HEAD/src/style/Textpattern/fonts/pt-serif-v18-latin-ext-regular.woff2 -------------------------------------------------------------------------------- /src/style/Textpattern/fonts/pt-serif-v18-latin-ext-700italic.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/textpattern/textpattern-forum/HEAD/src/style/Textpattern/fonts/pt-serif-v18-latin-ext-700italic.woff2 -------------------------------------------------------------------------------- /src/style/Textpattern/base_admin.css: -------------------------------------------------------------------------------- 1 | /** 2 | * Disables base admin-panel styles. 3 | * 4 | * This file is hard-linked, and as such, can not be versioned. We 5 | * won't be using this. 6 | */ 7 | -------------------------------------------------------------------------------- /public/.gitignore: -------------------------------------------------------------------------------- 1 | /.htaccess 2 | /cache 3 | /COPYING 4 | /include 5 | /lang 6 | /lib 7 | /style 8 | /tests 9 | /vendor 10 | /*.php 11 | /*.js 12 | /*.md 13 | /.* 14 | !/.gitignore 15 | /*.html 16 | /*.ico 17 | /*.png 18 | /*.svg 19 | -------------------------------------------------------------------------------- /public/robots.txt: -------------------------------------------------------------------------------- 1 | User-agent: * 2 | Disallow: /img/ 3 | Disallow: /*?*action= 4 | Disallow: /*?*type= 5 | Disallow: /*?*tid= 6 | Disallow: /*?*user_id= 7 | Disallow: /*?*search_id= 8 | Disallow: /*?*username= 9 | Sitemap: https://forum.textpattern.com/sitemap.xml 10 | -------------------------------------------------------------------------------- /public/sitemap.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | http://forum.textpattern.com 5 | 6 | 7 | https://forum.textpattern.com/humans.txt 8 | 9 | 10 | -------------------------------------------------------------------------------- /src/style/Textpattern/sass/modules/_http-errors.scss: -------------------------------------------------------------------------------- 1 | @use "../setup"; 2 | 3 | /* HTTP error pages 4 | ========================================================================== */ 5 | 6 | .http-status-code { 7 | font-size: 3em; 8 | } 9 | 10 | .http-status-description { 11 | display: inline-block; 12 | } 13 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # OS generated files # 2 | ###################### 3 | ._* 4 | .DS_Store 5 | .DS_Store? 6 | .nova 7 | .Spotlight-V100 8 | .Trashes 9 | .vscode 10 | Icon? 11 | ehthumbs.db 12 | Thumbs.db 13 | 14 | # Development files # 15 | ###################### 16 | /composer.lock 17 | /node_modules 18 | /package-lock.json 19 | /npm-debug.log 20 | /yarn.lock 21 | /yarn-error.log 22 | -------------------------------------------------------------------------------- /src/style/Textpattern/sass/modules/_accessibility.scss: -------------------------------------------------------------------------------- 1 | @use "../setup"; 2 | 3 | @media (prefers-reduced-motion: reduce), (update: slow) { 4 | body { 5 | scroll-behavior: auto; 6 | } 7 | 8 | .js #site-navigation, 9 | #site-navigation.site-navigation-open, 10 | .search-form [type="search"] { 11 | transition-duration: 0; 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /public/api/.htaccess: -------------------------------------------------------------------------------- 1 | 2 | Header unset X-XSS-Protection 3 | Header unset X-Frame-Options 4 | Header unset X-Content-Type-Options 5 | Header unset Expires 6 | Header unset Cache-Control 7 | Header unset Pragma 8 | Header unset Content-Security-Policy 9 | 10 | 11 | 12 | RewriteEngine On 13 | RewriteRule ^topics/([0-9]+) index.php?action=feed&fid=$1 [QSA] 14 | RewriteRule ^posts/([0-9]+) index.php?action=feed&tid=$1 [QSA] 15 | 16 | -------------------------------------------------------------------------------- /public/site.webmanifest: -------------------------------------------------------------------------------- 1 | { 2 | "short_name": "Textpattern", 3 | "name": "Textpattern CMS Support Forum", 4 | "start_url": "https://forum.textpattern.com", 5 | "scope": "https://forum.textpattern.com", 6 | "icons": [ 7 | { "src": "icon-192.png", "sizes": "192x192", "type": "image/png", "purpose": "maskable any" }, 8 | { "src": "icon-512.png", "sizes": "512x512", "type": "image/png", "purpose": "maskable any" } 9 | ], 10 | "background_color": "#ffffff", 11 | "theme_color": "#ffda44", 12 | "display": "minimal-ui" 13 | } 14 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # For more information about the properties used in 2 | # this file, please see the EditorConfig documentation: 3 | # https://editorconfig.org/ 4 | 5 | root = true 6 | 7 | [*] 8 | charset = utf-8 9 | end_of_line = lf 10 | indent_size = 4 11 | indent_style = space 12 | insert_final_newline = true 13 | trim_trailing_whitespace = true 14 | 15 | [*.md] 16 | trim_trailing_whitespace = false 17 | 18 | [{*.json,*.yml,humans.txt}] 19 | indent_size = 2 20 | indent_style = space 21 | 22 | [{feature-textpattern-forum.patch}] 23 | indent_style = tab 24 | -------------------------------------------------------------------------------- /src/style/Textpattern/sass/setup/_mixins.scss: -------------------------------------------------------------------------------- 1 | @use "settings"; 2 | 3 | // Dark Mode shorthand. 4 | 5 | @mixin dark-mode { 6 | @media (prefers-color-scheme: dark) { 7 | @content; 8 | } 9 | } 10 | 11 | // standard gradients 12 | 13 | @mixin gradient-linear($color-gradient-from, $color-gradient-to) { 14 | background-color: $color-gradient-to; 15 | background-image: linear-gradient($color-gradient-from, $color-gradient-to); 16 | } 17 | 18 | // hide text 19 | 20 | @mixin hide-text { 21 | overflow: hidden; 22 | text-indent: 110%; 23 | text-transform: capitalize; 24 | white-space: nowrap; 25 | } 26 | -------------------------------------------------------------------------------- /src/style/Textpattern/sass/setup/_settings.scss: -------------------------------------------------------------------------------- 1 | // typography grid 2 | $base-font-size: 16px !default; 3 | $base-line-height: 1.5 !default; 4 | $small-line-height: 1.375 !default; 5 | $code-font-size: 0.875rem !default; // 14px / 16px 6 | $small-font-size: 0.75rem !default; // 12px / 16px 7 | 8 | // layout grid 9 | $container-max-width: 72rem !default; // 1152px / 16px 10 | $breakpoint-3: 60rem !default; // 960px / 16px 11 | $breakpoint-2: 48rem !default; // 768px / 16px 12 | $breakpoint-1: 30rem !default; // 480px / 16px 13 | 14 | // borders 15 | $border-radius: 0.5em !default; // 8px / 16px 16 | -------------------------------------------------------------------------------- /src/style/Textpattern/sass/modules/_index.scss: -------------------------------------------------------------------------------- 1 | @use "fonts"; 2 | @use "layout"; 3 | @use "navigation"; 4 | @use "links"; 5 | @use "typography"; 6 | @use "alerts"; 7 | @use "embedded-content"; 8 | @use "tables"; 9 | @use "lists"; 10 | @use "forms"; 11 | @use "buttons"; 12 | @use "code-highlighting"; 13 | @use "social"; 14 | @use "misc"; 15 | @use "http-errors"; 16 | @use "icons"; 17 | @use "fluxbb/fluxbb_layout"; 18 | @use "fluxbb/fluxbb_layout_admin"; 19 | @use "fluxbb/fluxbb_navigation"; 20 | @use "fluxbb/fluxbb_indicators"; 21 | @use "fluxbb/fluxbb_pagination"; 22 | @use "fluxbb/fluxbb_icons"; 23 | @use "responsive"; 24 | @use "accessibility"; 25 | -------------------------------------------------------------------------------- /src/style/.htaccess: -------------------------------------------------------------------------------- 1 | 2 | Header unset X-XSS-Protection 3 | Header unset X-Frame-Options 4 | Header unset X-Content-Type-Options 5 | Header unset Content-Security-Policy 6 | Header append Cache-Control "public" 7 | 8 | 9 | Header append Vary "Accept-Encoding" 10 | 11 | 12 | 13 | 14 | ExpiresActive On 15 | ExpiresDefault "access plus 1 year" 16 | 17 | 18 | 19 | RewriteEngine On 20 | 21 | RewriteRule ^(.*?)\.[0-9]+\.(css|js|svg)$ $1.$2 [L] 22 | 23 | -------------------------------------------------------------------------------- /src/style/Textpattern/sass/modules/_misc.scss: -------------------------------------------------------------------------------- 1 | @use "../setup"; 2 | 3 | /* Miscellaneous 4 | ========================================================================== */ 5 | 6 | /** 7 | * Hide text but still allow screen reader access. 8 | * 9 | * Example HTML: 10 | * 11 | *

12 | */ 13 | 14 | .accessibility { 15 | position: absolute; 16 | width: 1px; 17 | height: 1px; 18 | margin: -1px; 19 | padding: 0; 20 | overflow: hidden; 21 | clip: rect(0 0 0 0); // TODO: Deprecated - use `clip-path` when browser support is better. 22 | //clip-path: inset(50%); // TODO: Currently causes severe performance issues in Chrome. 23 | border: 0; 24 | white-space: nowrap; 25 | } 26 | -------------------------------------------------------------------------------- /src/style/Textpattern/sass/modules/fluxbb/_fluxbb_pagination.scss: -------------------------------------------------------------------------------- 1 | @use "../../setup"; 2 | 3 | /* Forum pagination links 4 | ========================================================================== */ 5 | 6 | .pagelink { 7 | strong, 8 | a, 9 | .spacer { 10 | display: inline-block; 11 | min-width: 1.25em; 12 | padding: 0 0.1875em; // 3px / 16px 13 | text-align: center; 14 | } 15 | 16 | strong { 17 | background: var(--clr-text); 18 | color: var(--clr-text-white-enforced); 19 | font-weight: 400; 20 | cursor: default; 21 | } 22 | } 23 | 24 | @include setup.dark-mode { 25 | .pagelink strong { 26 | background: var(--clr-bkgd-form); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/style/Textpattern/sass/modules/_lists.scss: -------------------------------------------------------------------------------- 1 | @use "../setup"; 2 | 3 | /* Lists 4 | ========================================================================== */ 5 | 6 | /** 7 | * Address paddings set differently. 8 | */ 9 | 10 | menu, 11 | ol, 12 | ul { 13 | padding: 0 0 0 1.75em; 14 | } 15 | 16 | /** 17 | * Remove margins from nested lists. 18 | */ 19 | 20 | li { 21 | > ul, 22 | > ol { 23 | margin: 0; 24 | } 25 | } 26 | 27 | /** 28 | * CSS Lists and Counters Module Level 3 list marker styling. 29 | */ 30 | 31 | li::marker { 32 | color: var(--clr-text-promoted); 33 | } 34 | 35 | /** 36 | * Style for definition lists. 37 | */ 38 | 39 | dd { 40 | margin: 0 0 0 1.75em; 41 | } 42 | 43 | /** 44 | * Visually stronger definition terms. 45 | */ 46 | 47 | dt { 48 | color: var(--clr-text-promoted); 49 | font-weight: 700; 50 | } 51 | -------------------------------------------------------------------------------- /src/style/Textpattern/sass/modules/_embedded-content.scss: -------------------------------------------------------------------------------- 1 | @use "../setup"; 2 | 3 | /* Embedded content 4 | ========================================================================== */ 5 | 6 | /** 7 | * Make embedded elements responsive. 8 | */ 9 | 10 | img, 11 | video { 12 | max-width: 100%; 13 | height: auto; 14 | } 15 | 16 | /** 17 | * Remove the gap between images and the bottom of their containers. 18 | */ 19 | 20 | img { 21 | vertical-align: middle; 22 | } 23 | 24 | /** 25 | * Make embedded videos responsive. 26 | * 27 | * TODO: use `aspect-ratio: var(--aspect-ratio, 16 / 9);` when browser support 28 | * is better. 29 | */ 30 | 31 | .embed-video { 32 | position: relative; 33 | padding-top: 56.25%; // TODO: see comment above. 34 | 35 | iframe { 36 | position: absolute; 37 | top: 0; 38 | left: 0; 39 | width: 100%; 40 | height: 100%; 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve the Textpattern forum website. 4 | --- 5 | 6 | **Describe the bug** 7 | A clear and concise description of what the bug is. 8 | 9 | **To reproduce** 10 | Steps to reproduce the behaviour: 11 | 1. Go to '...' 12 | 2. Click on '....' 13 | 3. Scroll down to '....' 14 | 4. See error 15 | 16 | **Expected behaviour** 17 | A clear and concise description of what you expected to happen. 18 | 19 | **Screenshots** 20 | If applicable, add screenshots to help explain your problem. 21 | 22 | **Desktop (please complete the following information):** 23 | - OS: [e.g. iOS] 24 | - Browser [e.g. chrome, safari] 25 | - Version [e.g. 22] 26 | 27 | **Smartphone (please complete the following information):** 28 | - Device: [e.g. iPhone6] 29 | - OS: [e.g. iOS8.1] 30 | - Browser [e.g. stock browser, safari] 31 | - Version [e.g. 22] 32 | 33 | **Additional context** 34 | Add any other context about the problem here. 35 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (C) 2024 Team Textpattern 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a 6 | copy of this software and associated documentation files (the "Software"), 7 | to deal in the Software without restriction, including without limitation 8 | the rights to use, copy, modify, merge, publish, distribute, sublicense, 9 | and/or sell copies of the Software, and to permit persons to whom the 10 | Software is furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 19 | WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "textpattern-forum", 3 | "version": "1.6.4", 4 | "repository": { 5 | "type": "git", 6 | "url": "https://github.com/textpattern/textpattern-forum" 7 | }, 8 | "bugs": { 9 | "url": "https://github.com/textpattern/textpattern-forum/issues" 10 | }, 11 | "devDependencies": { 12 | "@lodder/grunt-postcss": "3.1.1", 13 | "autoprefixer": "10.4.23", 14 | "cssnano": "7.1.2", 15 | "grunt": "1.6.1", 16 | "grunt-cli": "1.5.0", 17 | "grunt-concurrent": "3.0.0", 18 | "grunt-contrib-clean": "2.0.1", 19 | "grunt-contrib-copy": "1.0.0", 20 | "grunt-contrib-jshint": "3.2.0", 21 | "grunt-contrib-watch": "1.1.0", 22 | "grunt-replace-regex": "1.0.3", 23 | "grunt-sass": "4.0.1", 24 | "grunt-stylelint": "0.20.1", 25 | "grunt-terser": "2.0.0", 26 | "load-grunt-tasks": "5.1.0", 27 | "sass": "1.91.0", 28 | "stylelint": "16.26.1", 29 | "stylelint-config-standard-scss": "16.0.0", 30 | "sass": "1.97.0", 31 | "stylelint-order": "7.0.0" 32 | }, 33 | "dependencies": { 34 | "jquery": "3.7.1", 35 | "prismjs": "1.30.0", 36 | "textpattern-branding": "0.3.3" 37 | }, 38 | "optionalDependencies": { 39 | "fibers": "5.0.3" 40 | }, 41 | "browserslist": [ 42 | "> 0.5%", 43 | "Firefox ESR", 44 | "not IE 11" 45 | ], 46 | "license": "MIT" 47 | } 48 | -------------------------------------------------------------------------------- /src/style/Textpattern/sass/modules/_fonts.scss: -------------------------------------------------------------------------------- 1 | @use "../setup"; 2 | 3 | /* Fonts 4 | ========================================================================== */ 5 | 6 | /** 7 | * 'PT Serif' font. 8 | */ 9 | 10 | // Regular 11 | @font-face { 12 | font-family: "PT Serif"; 13 | font-style: normal; 14 | font-weight: 400; 15 | font-display: optional; 16 | src: url("https://forum.textpattern.com/style/Textpattern/fonts/pt-serif-v18-latin-ext-regular.woff2") format("woff2"); 17 | } 18 | 19 | // Regular Italic 20 | @font-face { 21 | font-family: "PT Serif"; 22 | font-style: italic; 23 | font-weight: 400; 24 | font-display: swap; 25 | src: url("https://forum.textpattern.com/style/Textpattern/fonts/pt-serif-v18-latin-ext-italic.woff2") format("woff2"); 26 | } 27 | 28 | // Bold 29 | @font-face { 30 | font-family: "PT Serif"; 31 | font-style: normal; 32 | font-weight: 700; 33 | font-display: optional; 34 | src: url("https://forum.textpattern.com/style/Textpattern/fonts/pt-serif-v18-latin-ext-700.woff2") format("woff2"); 35 | } 36 | 37 | // Bold Italic 38 | @font-face { 39 | font-family: "PT Serif"; 40 | font-style: italic; 41 | font-weight: 700; 42 | font-display: swap; 43 | src: url("https://forum.textpattern.com/style/Textpattern/fonts/pt-serif-v18-latin-ext-700italic.woff2") format("woff2"); 44 | } 45 | -------------------------------------------------------------------------------- /src/style/Textpattern/sass/modules/_alerts.scss: -------------------------------------------------------------------------------- 1 | @use "../setup"; 2 | @use "sass:math"; 3 | 4 | /* Alert messages 5 | ========================================================================== */ 6 | 7 | /** 8 | * Alert labels. 9 | * 10 | * Example HTML: 11 | * 12 | * 13 | * 14 | * 15 | * 16 | */ 17 | 18 | .success { 19 | color: var(--clr-success-text); 20 | } 21 | 22 | .warning { 23 | color: var(--clr-warning-text); 24 | } 25 | 26 | .error { 27 | color: var(--clr-error-text); 28 | } 29 | 30 | .information { 31 | color: var(--clr-info-text); 32 | } 33 | 34 | /** 35 | * Alert boxes. 36 | * 37 | * 1. Prevent really, really long words from breaking layout. 38 | * 39 | * Example HTML: 40 | * 41 | *

42 | *

43 | */ 44 | 45 | .alert-block { 46 | padding: 0.5em 1em; 47 | border: 1px solid; 48 | border-radius: math.div(setup.$border-radius, 2); 49 | word-wrap: break-word; /* 1 */ 50 | 51 | &.success { 52 | border-color: var(--clr-success-brdr); 53 | background: var(--clr-success-bkgd); 54 | } 55 | 56 | &.warning { 57 | border-color: var(--clr-warning-brdr); 58 | background: var(--clr-warning-bkgd); 59 | } 60 | 61 | &.error { 62 | border-color: var(--clr-error-brdr); 63 | background: var(--clr-error-bkgd); 64 | } 65 | 66 | &.information { 67 | border-color: var(--clr-info-brdr); 68 | background: var(--clr-info-bkgd); 69 | } 70 | } 71 | 72 | -------------------------------------------------------------------------------- /src/style/Textpattern/sass/modules/fluxbb/_fluxbb_layout_admin.scss: -------------------------------------------------------------------------------- 1 | @use "../../setup"; 2 | 3 | /* Forum admin layout 4 | ========================================================================== */ 5 | 6 | /** 7 | * Hide the duplicate submit button at top. 8 | */ 9 | 10 | #adminconsole p.submittop { 11 | display: none; 12 | } 13 | 14 | #adminconsole fieldset { 15 | th[scope="row"] { 16 | width: 30%; 17 | } 18 | 19 | input[type="submit"] { 20 | margin: 1em 0; 21 | } 22 | 23 | td span, 24 | th span { 25 | display: block; 26 | margin-top: 0.5em; 27 | } 28 | 29 | td.location span { 30 | display: inline-block; 31 | } 32 | } 33 | 34 | #forumperms thead th, 35 | #forumperms tbody td { 36 | text-align: center; 37 | } 38 | 39 | /** 40 | * Column widths. 41 | */ 42 | 43 | #categoryedit .tcl { 44 | width: 50%; 45 | } 46 | 47 | #edforum .tcl, 48 | #edforum .tc2, 49 | #censoring .tcl, 50 | #censoring .tc2 { 51 | width: 30%; 52 | } 53 | 54 | /** 55 | * User bans table. 56 | */ 57 | 58 | #bans1 { 59 | .tcl { 60 | width: 30%; 61 | } 62 | 63 | .tc3 { 64 | width: 9em; 65 | } 66 | 67 | .tc4, 68 | .tc5, 69 | .tc6 { 70 | display: none; 71 | } 72 | 73 | .tcr { 74 | width: 7em; 75 | } 76 | } 77 | 78 | /** 79 | * User search table (admin). 80 | */ 81 | 82 | #users2 { 83 | .tcl { 84 | width: 20%; 85 | } 86 | 87 | .tc5 { 88 | display: none; 89 | } 90 | } 91 | 92 | /** 93 | * Hide 'select all' link (we filter out inline JavaScript, so it doesn't work). 94 | */ 95 | 96 | .modbuttons a { 97 | display: none; 98 | } 99 | -------------------------------------------------------------------------------- /src/style/Textpattern/sass/modules/fluxbb/_fluxbb_indicators.scss: -------------------------------------------------------------------------------- 1 | @use "../../setup"; 2 | 3 | /* Forum indicators 4 | ========================================================================== */ 5 | 6 | /** 7 | * `tr` hightlight for new posts. 8 | */ 9 | 10 | .inew { 11 | background-color: var(--clr-hilite-box); 12 | } 13 | 14 | /** 15 | * Text highlights. 16 | */ 17 | 18 | .warntext, 19 | #page-delete .forminfo p { 20 | display: block; 21 | padding: 0.5em 1em; // 8px / 16px 22 | border: 1px solid; 23 | border-radius: 0.25em; // 4px / 16px 24 | } 25 | 26 | .stickytext, 27 | .closedtext, 28 | .movedtext { 29 | margin-right: 0.3333333em; 30 | padding: 1px 0.25em; // 4px / 16px 31 | border: 1px solid; 32 | border-radius: 0.25em; // 4px / 16px 33 | } 34 | 35 | .warntext { 36 | border-color: var(--clr-warning-brdr); 37 | background: var(--clr-warning-bkgd); 38 | color: var(--clr-warning-text); 39 | } 40 | 41 | .stickytext { 42 | border-color: var(--clr-success-brdr); 43 | background: var(--clr-success-bkgd); 44 | color: var(--clr-success-text); 45 | } 46 | 47 | .closedtext, 48 | #page-delete .forminfo p { 49 | border-color: var(--clr-error-brdr); 50 | background: var(--clr-error-bkgd); 51 | color: var(--clr-error-text); 52 | } 53 | 54 | .movedtext { 55 | border-color: var(--clr-info-brdr); 56 | background: var(--clr-info-bkgd); 57 | color: var(--clr-info-text); 58 | } 59 | 60 | /** 61 | * Indicate posts participated in. 62 | */ 63 | 64 | .ipost { 65 | @include setup.hide-text; 66 | 67 | display: inline-block; 68 | width: 0.75em; 69 | height: 0.75em; 70 | margin-right: 0.3333333em; 71 | border-radius: 50%; 72 | background-color: var(--clr-hilite); 73 | } 74 | -------------------------------------------------------------------------------- /src/style/Textpattern/sass/modules/_links.scss: -------------------------------------------------------------------------------- 1 | @use "../setup"; 2 | 3 | /* Links 4 | ========================================================================== */ 5 | 6 | /** 7 | * 1. Specify link colour. 8 | * 2. Remove default underline style from non-hover state links. 9 | * 3. Interrupt the decoration line to let the shape of the text show through 10 | * in supported browsers. 11 | * 4. Remove tap delay in modern browsers. 12 | */ 13 | 14 | a { 15 | color: var(--clr-a); /* 1 */ 16 | text-decoration: none; /* 2 */ 17 | text-decoration-skip-ink: auto; /* 3 */ 18 | text-underline-offset: 0.125em; 19 | touch-action: manipulation; /* 4 */ 20 | 21 | &:hover, 22 | &:active { 23 | color: var(--clr-a-interact); 24 | text-decoration: underline; 25 | } 26 | 27 | &:focus { 28 | outline: 1px solid var(--clr-focus); 29 | } 30 | } 31 | 32 | /** 33 | * Additional styling for heading links. 34 | * 35 | * 1. Expanded CSS level 3 `text-decoration-color` property in supported 36 | * browsers, older browsers ignore this addition. 37 | */ 38 | 39 | h1, 40 | h2, 41 | h3, 42 | h4, 43 | h5, 44 | h6 { 45 | a { 46 | color: var(--clr-text-promoted); 47 | 48 | &:hover, 49 | &:active { 50 | color: var(--clr-text-promoted); 51 | text-decoration-color: var(--clr-text-promoted-a50); /* 1 */ 52 | } 53 | } 54 | } 55 | 56 | /** 57 | * Additional styling for links within complementary content and site footer. 58 | */ 59 | 60 | .complementary-content a:not(.button), 61 | .site-footer a { 62 | color: var(--clr-a-alt); 63 | 64 | &:hover, 65 | &:active { 66 | color: var(--clr-a-alt-interact); 67 | } 68 | } 69 | 70 | /** 71 | * Visually hide unfocussed/inactive ‘skip links’. 72 | * 73 | * Example HTML: 74 | * 75 | * 76 | */ 77 | 78 | .a--skip-link { 79 | position: absolute; 80 | z-index: 2; 81 | top: 1px; 82 | left: 1px; 83 | padding: 0.25em 0.5em; 84 | transform: translateY(-5em); 85 | transition: transform 0.25s ease-in-out; 86 | background-color: var(--clr-nav-active); 87 | color: var(--clr-text); 88 | 89 | &:focus, 90 | &:active { 91 | transform: translateY(0); 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /public/humans.txt: -------------------------------------------------------------------------------- 1 | # https://humanstxt.org 2 | # The humans responsible and 3 | # technology colophon 4 | 5 | # TEAM 6 | 7 | Developer: Team Textpattern 8 | Site: https://textpattern.com 9 | GitHub: https://github.com/textpattern 10 | Mastodon: https://indieweb.social/@textpattern 11 | Twitter: https://twitter.com/textpattern 12 | Location: Everywhere 13 | 14 | # TECHNOLOGY COLOPHON 15 | 16 | Standards: HTML5, CSS3 17 | Server: Nginx, Percona Server for MySQL, PHP 18 | Components: 19 | FluxBB: https://fluxbb.org/ 20 | FluxBB_by_Visman: https://github.com/MioVisman/FluxBB_by_Visman 21 | PHP-Textile: https://github.com/textile/php-textile 22 | jQuery: https://jquery.com/ 23 | Prism: https://prismjs.com/ 24 | Software: 25 | Node.js: https://nodejs.org/ 26 | Grunt.js: https://gruntjs.com/ 27 | Composer: https://getcomposer.org/ 28 | git: https://git-scm.com/ 29 | Source: https://github.com/textpattern/textpattern-forum 30 | 31 | 32 | .ttTTttx 33 | xPXTTTTTtt- xppx 34 | pPPTTTTTTTTXxx px xp 35 | .tPTTTTTTTTTTTTt- .t- .t- 36 | xPXTTTTTTTTTTTTTp px xx 37 | -tPTTTTTTTTTTTTTt -x -t 38 | .tPTTTTTTTTTTTTTT. -x .t- 39 | xtXTTTTTTTTTTTTTTTt- xx xx 40 | PxTTTTTTTTTTTTTTTt..-t. -t. .pttx. 41 | xxXTTTTTTTTTTTTTPpp.- px xp xXTt- 42 | -tPTTTTTTTTxTTTXppp... xx px pTTx 43 | xtPTTTTf tTTTxp-... .t-.t. .XTt. 44 | .xxXX- -XTTPxp.- ..Pp tTX- 45 | tTTTtp--xt pTTx 46 | -XTTXtt- .PTP. 47 | xTTp xTTTx 48 | pt pTTTP-.t. 49 | .t- .PTTTP- xx 50 | xx xTTTTTXp-. .t. 51 | -t. -XTx xTTTTt--. px 52 | .t- .PTP. .tTTTTx--.. xp 53 | xx xTTp .PTTTP--. -t. 54 | -t. -XTt pTTTTt.-. px 55 | .t- ..PTX. xTTTTp--.. xp 56 | px .xTTp .PTTTP----..t- 57 | px. .-XTt pTTTTx.p.. -t. 58 | -p. tTX- tTTTXp-p.. px 59 | -xxppTT. -xTTP--.-p 60 | -------------------------------------------------------------------------------- /src/style/Textpattern/sass/modules/fluxbb/_fluxbb_navigation.scss: -------------------------------------------------------------------------------- 1 | @use "../../setup"; 2 | @use "sass:math"; 3 | 4 | /* Forum navigation menu 5 | ========================================================================== */ 6 | 7 | #brdmenu { 8 | ul { 9 | margin: 1em 0 0; 10 | padding: 0; 11 | border-bottom: 1px solid var(--clr-brdr); 12 | list-style: none; 13 | } 14 | 15 | li { 16 | display: inline-block; 17 | } 18 | 19 | a { 20 | display: block; 21 | position: relative; 22 | bottom: -1px; 23 | padding: 0.5em 1em; 24 | border: 1px solid var(--clr-brdr); 25 | border-radius: (math.div(setup.$border-radius, 2)) (math.div(setup.$border-radius, 2)) 0 0; 26 | background-color: var(--clr-bkgd-box); 27 | box-shadow: inset 0 -0.125em 0.25em hsl(0 0% 40% / 0.2); 28 | color: var(--clr-text); 29 | text-decoration: none; 30 | 31 | &:hover { 32 | border-color: var(--clr-brdr-x-dark); 33 | background-color: var(--clr-nav-interact); 34 | } 35 | 36 | &:active { 37 | filter: brightness(0.95); 38 | } 39 | 40 | &:focus { 41 | border-color: var(--clr-focus); 42 | outline: 2px solid transparent; // Allows for repainting in high contrast modes. 43 | background-color: var(--clr-nav-interact); 44 | } 45 | } 46 | } 47 | 48 | #brdmenu .isactive a, 49 | #navextra1 a { 50 | border-bottom-color: var(--clr-bkgd); 51 | background-color: var(--clr-bkgd); 52 | box-shadow: none; 53 | } 54 | 55 | @include setup.dark-mode { 56 | #brdmenu { 57 | ul { 58 | border-bottom-color: var(--clr-brdr-lite); 59 | } 60 | 61 | a { 62 | border-color: var(--clr-brdr-lite); 63 | box-shadow: inset 0 -0.125em 0.25em hsl(0 0% 0% / 0.2); 64 | 65 | &:hover { 66 | border-color: var(--clr-brdr); 67 | } 68 | 69 | &:focus { 70 | border-color: var(--clr-focus); 71 | } 72 | } 73 | } 74 | 75 | #brdmenu .isactive a, 76 | #navextra1 a { 77 | border-bottom-color: var(--clr-bkgd); 78 | background-color: var(--clr-bkgd); 79 | box-shadow: none; 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /src/style/Textpattern/sass/modules/_tables.scss: -------------------------------------------------------------------------------- 1 | @use "../setup"; 2 | 3 | /* Tables 4 | ========================================================================== */ 5 | 6 | /** 7 | * Consistent tables. 8 | */ 9 | 10 | table { 11 | width: 100%; 12 | margin: 1em 0; 13 | border-spacing: 0; 14 | border-collapse: collapse; 15 | } 16 | 17 | /** 18 | * Styling of table captions. 19 | */ 20 | 21 | caption { 22 | margin-bottom: 0.5em; 23 | font-style: italic; 24 | text-align: left; 25 | } 26 | 27 | /** 28 | * Make table cells align top and left by default. 29 | */ 30 | 31 | th, 32 | td { 33 | padding: 0.5em 1em 0.5em 0; 34 | border-bottom: 1px solid var(--clr-brdr); 35 | vertical-align: top; 36 | text-align: left; 37 | 38 | &:empty { 39 | border: 0; 40 | } 41 | 42 | &:last-child { 43 | padding-right: 0; 44 | } 45 | } 46 | 47 | @include setup.dark-mode { 48 | th, 49 | td { 50 | border-bottom-color: var(--clr-brdr-lite); 51 | } 52 | } 53 | 54 | /** 55 | * Table `thead` non-global borders and padding. 56 | */ 57 | 58 | thead { 59 | tr:first-child { 60 | th, 61 | td { 62 | padding-top: 0; 63 | } 64 | } 65 | 66 | tr:last-child { 67 | th, 68 | td { 69 | border-bottom: 2px solid var(--clr-brdr); 70 | } 71 | } 72 | } 73 | 74 | @include setup.dark-mode { 75 | thead tr:last-child { 76 | th, 77 | td { 78 | border-bottom-color: var(--clr-brdr-lite); 79 | } 80 | } 81 | } 82 | 83 | /** 84 | * Table `tfoot` non-global borders and padding. 85 | */ 86 | 87 | tfoot { 88 | th, 89 | td { 90 | padding: 0.6666667em; // 8px / 12px 91 | } 92 | 93 | tr:last-child { 94 | th, 95 | td { 96 | padding-bottom: 0; 97 | border-bottom: 0; 98 | } 99 | } 100 | } 101 | 102 | /** 103 | * Table `tbody` non-global borders. 104 | */ 105 | 106 | tbody tr:first-child { 107 | td, 108 | th { 109 | border-top: 1px solid var(--clr-brdr); 110 | } 111 | } 112 | 113 | @include setup.dark-mode { 114 | tbody tr:first-child { 115 | td, 116 | th { 117 | border-top-color: var(--clr-brdr-lite); 118 | } 119 | } 120 | } 121 | 122 | /** 123 | * Multi-row span vertical cell alignments. 124 | */ 125 | 126 | [rowspan] { 127 | vertical-align: middle; 128 | } 129 | -------------------------------------------------------------------------------- /src/style/Textpattern/fonts/License.txt: -------------------------------------------------------------------------------- 1 | Copyright © 2009 ParaType Ltd. 2 | with Reserved Names ‘PT Sans’ and ‘ParaType’. 3 | 4 | FONT LICENSE 5 | 6 | PERMISSION & CONDITIONS 7 | Permission is hereby granted, free of charge, to any person obtaining a copy of the font software, to use, study, copy, merge, embed, modify, redistribute, and sell modified and unmodified copies of the font software, subject to the following conditions: 8 | 9 | 1) Neither the font software nor any of its individual components, in original or modified versions, may be sold by itself. 10 | 11 | 2) Original or modified versions of the font software may be bundled, redistributed and/or sold with any software, provided that each copy contains the above copyright notice and this license. These can be included either as stand-alone text files, human-readable headers or in the appropriate machine-readable metadata fields within text or binary files as long as those fields can be easily viewed by the user. 12 | 13 | 3) No modified version of the font software may use the Reserved Name(s) or combinations of Reserved Names with other words unless explicit written permission is granted by the ParaType. This restriction only applies to the primary font name as presented to the users. 14 | 15 | 4) The name of ParaType or the author(s) of the font software shall not be used to promote, endorse or advertise any modified version, except to acknowledge the contribution(s) of ParaType and the author(s) or with explicit written permission of ParaType. 16 | 17 | 5) The font software, modified or unmodified, in part or in whole, must be distributed entirely under this license, and must not be distributed under any other license. The requirement for fonts to remain under this license does not apply to any document created using the Font Software. 18 | 19 | TERMINATION & TERRITORY 20 | This license has no limits on time and territory, but it becomes null and void if any of the above conditions are not met. 21 | 22 | DISCLAIMER 23 | THE FONT SOFTWARE IS PROVIDED ‘AS IS’, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL PARATYPE BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM OTHER DEALINGS IN THE FONT SOFTWARE. 24 | 25 | ParaType Ltd 26 | https://www.paratype.ru/ 27 | -------------------------------------------------------------------------------- /src/style/Textpattern/sass/modules/_code-highlighting.scss: -------------------------------------------------------------------------------- 1 | @use "../setup"; 2 | 3 | /* Code highlighting (via Prism.js) 4 | ========================================================================== */ 5 | 6 | code[class*="language-"], 7 | pre[class*="language-"] { 8 | direction: ltr; 9 | hyphens: none; 10 | text-align: left; 11 | word-wrap: normal; 12 | word-break: normal; 13 | word-spacing: normal; 14 | white-space: pre; 15 | } 16 | 17 | /** 18 | * Inline code. 19 | */ 20 | 21 | :not(pre) > code[class*="language-"] { 22 | white-space: normal; 23 | } 24 | 25 | /** 26 | * Syntax colours/styles. 27 | */ 28 | 29 | .token.comment, 30 | .token.prolog, 31 | .token.doctype, 32 | .token.cdata { 33 | color: hsl(210 13% 50%); 34 | } 35 | 36 | .token.punctuation { 37 | color: hsl(0 0% 60%); 38 | } 39 | 40 | .namespace { 41 | opacity: 0.7; 42 | } 43 | 44 | .token.property, 45 | .token.tag, 46 | .token.boolean, 47 | .token.number, 48 | .token.constant, 49 | .token.symbol, 50 | .token.deleted { 51 | color: hsl(327 100% 30%); 52 | } 53 | 54 | .token.selector, 55 | .token.attr-name, 56 | .token.string, 57 | .token.char, 58 | .token.builtin, 59 | .token.inserted { 60 | color: hsl(80 100% 30%); 61 | } 62 | 63 | .token.operator, 64 | .token.entity, 65 | .token.url, 66 | .language-css .token.string, 67 | .style .token.string { 68 | color: hsl(30 30% 50%); 69 | } 70 | 71 | .token.atrule, 72 | .token.attr-value, 73 | .token.keyword { 74 | color: hsl(198 100% 33%); 75 | } 76 | 77 | .token.function { 78 | color: hsl(348 68% 58%); 79 | } 80 | 81 | .token.regex, 82 | .token.important, 83 | .token.variable { 84 | color: hsl(39 100% 47%); 85 | } 86 | 87 | .token.important, 88 | .token.bold { 89 | font-weight: 700; 90 | } 91 | 92 | .token.italic { 93 | font-style: italic; 94 | } 95 | 96 | .token.entity { 97 | cursor: help; 98 | } 99 | 100 | @include setup.dark-mode { 101 | .token.punctuation { 102 | color: var(--clr-text-white-enforced); 103 | } 104 | 105 | .token.property, 106 | .token.tag, 107 | .token.boolean, 108 | .token.number, 109 | .token.constant, 110 | .token.symbol, 111 | .token.deleted { 112 | color: var(--clr-error-text); 113 | } 114 | 115 | .token.selector, 116 | .token.attr-name, 117 | .token.string, 118 | .token.char, 119 | .token.builtin, 120 | .token.inserted { 121 | color: var(--clr-success-text); 122 | } 123 | 124 | .token.operator, 125 | .token.entity, 126 | .token.url, 127 | .language-css .token.string, 128 | .style .token.string { 129 | color: var(--clr-warning-text); 130 | } 131 | 132 | .token.atrule, 133 | .token.attr-value, 134 | .token.keyword { 135 | color: var(--clr-info-text); 136 | } 137 | } 138 | -------------------------------------------------------------------------------- /src/style/Textpattern/sass/modules/fluxbb/_fluxbb_icons.scss: -------------------------------------------------------------------------------- 1 | @use "../../setup"; 2 | 3 | /* Forum icons 4 | ========================================================================== */ 5 | 6 | /** 7 | * Don't show icons on topic lists. 8 | */ 9 | 10 | .icon { 11 | display: none; 12 | } 13 | 14 | /** 15 | * Illustrated icons on main index page. 16 | */ 17 | 18 | #page-index .icon { 19 | display: block; 20 | width: 60px; 21 | height: 60px; 22 | margin-right: 1em; 23 | float: left; 24 | background-image: url("../img/forum-icons.png"); 25 | background-size: 1140px 120px; 26 | background-position-y: 0; 27 | 28 | @media (min-resolution: 1.25dppx), (min-resolution: 120dpi) { 29 | background-image: url("../img/forum-icons@2x.png"); 30 | } 31 | 32 | &.icon-new { 33 | background-position-y: -60px; 34 | } 35 | 36 | .nosize { 37 | display: none; 38 | } 39 | } 40 | 41 | @include setup.dark-mode { 42 | #page-index .icon { 43 | background-image: url("../img/dark-forum-icons.png"); 44 | 45 | @media (min-resolution: 1.25dppx), (min-resolution: 120dpi) { 46 | background-image: url("../img/dark-forum-icons@2x.png"); 47 | } 48 | } 49 | } 50 | 51 | #idx1 tbody { 52 | tr:nth-child(1) .icon { 53 | background-position-x: 0; 54 | } 55 | 56 | tr:nth-child(2) .icon { 57 | background-position-x: -60px; 58 | } 59 | 60 | tr:nth-child(3) .icon { 61 | background-position-x: -120px; 62 | } 63 | 64 | tr:nth-child(4) .icon { 65 | background-position-x: -180px; 66 | } 67 | } 68 | 69 | #idx2 tbody { 70 | tr:nth-child(1) .icon { 71 | background-position-x: -240px; 72 | } 73 | 74 | tr:nth-child(2) .icon { 75 | background-position-x: -300px; 76 | } 77 | 78 | tr:nth-child(3) .icon { 79 | background-position-x: -360px; 80 | } 81 | 82 | tr:nth-child(4) .icon { 83 | background-position-x: -420px; 84 | } 85 | 86 | tr:nth-child(5) .icon { 87 | background-position-x: -480px; 88 | } 89 | 90 | tr:nth-child(6) .icon { 91 | background-position-x: -540px; 92 | } 93 | 94 | tr:nth-child(7) .icon { 95 | background-position-x: -600px; 96 | } 97 | 98 | tr:nth-child(8) .icon { 99 | background-position-x: -660px; 100 | } 101 | } 102 | 103 | #idx3 tbody { 104 | tr:nth-child(1) .icon { 105 | background-position-x: -720px; 106 | } 107 | 108 | tr:nth-child(2) .icon { 109 | background-position-x: -780px; 110 | } 111 | 112 | tr:nth-child(3) .icon { 113 | background-position-x: -840px; 114 | } 115 | 116 | tr:nth-child(4) .icon { 117 | background-position-x: -900px; 118 | } 119 | 120 | tr:nth-child(5) .icon { 121 | background-position-x: -960px; 122 | } 123 | 124 | tr:nth-child(6) .icon { 125 | background-position-x: -1020px; 126 | } 127 | 128 | tr:nth-child(7) .icon { 129 | background-position-x: -1080px; 130 | } 131 | } 132 | -------------------------------------------------------------------------------- /src/style/Textpattern/sass/modules/_social.scss: -------------------------------------------------------------------------------- 1 | @use "../setup"; 2 | 3 | /* Social media 4 | ========================================================================== */ 5 | 6 | /** 7 | * Link list of social media channel icons. 8 | * 9 | * Example HTML: 10 | * 11 | *

16 | */ 17 | 18 | .social-channels { 19 | padding: 0; 20 | list-style: none; 21 | 22 | li { 23 | display: inline-block; 24 | margin-right: 0.5em; 25 | } 26 | 27 | a { 28 | @include setup.hide-text; 29 | 30 | display: block; 31 | width: 32px; 32 | height: 32px; 33 | background-size: 32px 32px; 34 | 35 | &:hover { 36 | filter: brightness(1.1); 37 | } 38 | 39 | &.github { 40 | background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 32 32'%3E%3Cpath fill='%23fff' stroke='%23fff' d='M0 0h32v32H0z'/%3E%3Cpath fill='%23171515' d='M16,4C9.4,4,4,9.4,4,16c0,5.3,3.4,9.8,8.2,11.4c0.6,0.1,0.8-0.3,0.8-0.6c0-0.3,0-1,0-2c-3.3,0.7-4-1.6-4-1.6c-0.5-1.4-1.3-1.8-1.3-1.8c-1.1-0.7,0.1-0.7,0.1-0.7c1.2,0.1,1.8,1.2,1.8,1.2c1.1,1.8,2.8,1.3,3.5,1c0.1-0.8,0.4-1.3,0.8-1.6C11.1,21,8.3,20,8.3,15.4c0-1.3,0.5-2.4,1.2-3.2C9.5,11.8,9,10.6,9.7,9c0,0,1-0.3,3.3,1.2c1-0.3,2-0.4,3-0.4c1,0,2,0.1,3,0.4C21.3,8.7,22.3,9,22.3,9c0.7,1.7,0.2,2.9,0.1,3.2c0.8,0.8,1.2,1.9,1.2,3.2c0,4.6-2.8,5.6-5.5,5.9c0.4,0.4,0.8,1.1,0.8,2.2c0,1.6,0,2.9,0,3.3c0,0.3,0.2,0.7,0.8,0.6C24.6,25.8,28,21.3,28,16C28,9.4,22.6,4,16,4z'/%3E%3C/svg%3E"); 41 | } 42 | 43 | &.mastodon { 44 | background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 32 32'%3E%3Cpath fill='%231f232b' stroke='%23fff' d='M0 0h32v32H0z'/%3E%3Cpath fill='%233088d4' d='m27 18.5c-.3 1.8-3 3.7-6.1 4.1-1.6.2-3.2.4-4.9.3-2.8-.1-4.9-.7-4.9-.7v.8c.4 2.8 2.7 2.9 4.9 3s4.2-.6 4.2-.6l.1 2.1s-1.6.9-4.4 1c-1.5.1-3.5 0-5.7-.6-4.7-1.4-5.6-6.6-5.7-11.9 0-1.6 0-3.1 0-4.3 0-5.4 3.5-7 3.5-7 1.8-.8 4.8-1.2 8-1.2 3.2 0 6.2.4 8 1.2 0 0 3.5 1.6 3.5 7 0 0 0 4-.5 6.8zm-4.6-9.6c-.7-.8-1.6-1.2-2.7-1.2-1.3 0-2.3.5-3 1.5l-.7 1.2-.6-1.1c-.7-1-1.7-1.5-3-1.5-1.1 0-2 .4-2.7 1.2s-1 1.9-1 3.2v6.6h2.6v-6.4c0-1.3.6-2 1.7-2 1.2 0 1.9.8 1.9 2.4v3.5h2.6v-3.5c0-1.6.6-2.4 1.9-2.4 1.1 0 1.7.7 1.7 2v6.4h2.6v-6.6c-.3-1.4-.7-2.5-1.3-3.3z'/%3E%3C/svg%3E"); 45 | } 46 | 47 | &.twitter { 48 | background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 32 32'%3E%3Cpath fill='%2300aced' stroke='%23fff' d='M0 0h32v32H0z'/%3E%3Cpath fill='%23fff' d='M26.7,9.4c-0.8,0.3-1.6,0.6-2.5,0.7c0.9-0.5,1.6-1.4,1.9-2.4c-0.8,0.5-1.8,0.9-2.8,1c-0.8-0.9-1.9-1.4-3.2-1.4c-2.4,0-4.4,2-4.4,4.4c0,0.3,0,0.7,0.1,1c-3.6-0.2-6.9-1.9-9-4.6c-0.4,0.6-0.6,1.4-0.6,2.2c0,1.5,0.8,2.9,1.9,3.6c-0.7,0-1.4-0.2-2-0.5l0,0c0,2.1,1.5,3.9,3.5,4.3c-0.4,0.1-0.8,0.2-1.2,0.2c-0.3,0-0.6,0-0.8,0c0.6,1.7,2.2,3,4,3c-1.5,1.2-3.4,1.9-5.4,1.9c-0.4,0-0.7,0-1-0.1c1.9,1.2,4.2,2,6.7,2c8.1,0,12.5-6.7,12.5-12.5c0-0.2,0-0.4,0-0.6C25.3,11,26.1,10.3,26.7,9.4z'/%3E%3C/svg%3E"); 49 | } 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /.github/CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Covenant Code of Conduct 2 | 3 | ## Our pledge 4 | 5 | In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation. 6 | 7 | ## Our standards 8 | 9 | Examples of behaviour that contributes to creating a positive environment include: 10 | 11 | * Using welcoming and inclusive language 12 | * Being respectful of differing viewpoints and experiences 13 | * Gracefully accepting constructive criticism 14 | * Focusing on what is best for the community 15 | * Showing empathy towards other community members 16 | 17 | Examples of unacceptable behaviour by participants include: 18 | 19 | * The use of sexualized language or imagery and unwelcome sexual attention or advances 20 | * Trolling, insulting/derogatory comments, and personal or political attacks 21 | * Public or private harassment 22 | * Publishing others' private information, such as a physical or electronic address, without explicit permission 23 | * Other conduct which could reasonably be considered inappropriate in a professional setting 24 | 25 | ## Our responsibilities 26 | 27 | Project maintainers are responsible for clarifying the standards of acceptable behaviour and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behaviour. 28 | 29 | Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviours that they deem inappropriate, threatening, offensive, or harmful. 30 | 31 | ## Scope 32 | 33 | This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers. 34 | 35 | ## Enforcement 36 | 37 | Instances of abusive, harassing, or otherwise unacceptable behaviour may be reported by contacting the project team at enquiries@designhive.com. The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately. 38 | 39 | Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership. 40 | 41 | ## Attribution 42 | 43 | This Code of Conduct is adapted from the [Contributor Covenant](http://contributor-covenant.org), [version 1.4](http://contributor-covenant.org/version/1/4/). 44 | -------------------------------------------------------------------------------- /public/api/index.php: -------------------------------------------------------------------------------- 1 | xmlToArray($xml)) 39 | { 40 | foreach ($array as &$value) 41 | { 42 | if (!is_array($value) || !isset($value[0])) 43 | { 44 | $value = array($value); 45 | } 46 | } 47 | 48 | return json_encode($array); 49 | } 50 | else 51 | { 52 | if ($buffer) 53 | { 54 | header('Content-Type: application/json'); 55 | header('HTTP/1.0 404 Not Found'); 56 | return json_encode(array('errors' => (array) $buffer)); 57 | } 58 | } 59 | 60 | return json_encode((array) $buffer); 61 | } 62 | 63 | /** 64 | * Converts XML to Array. 65 | * 66 | * @param mixed $xml The document 67 | */ 68 | 69 | public function xmlToArray($xml) 70 | { 71 | if (count($xml->children()) === 0) 72 | { 73 | return (string) $xml; 74 | } 75 | 76 | $array = array(); 77 | 78 | foreach ($xml->children() as $element => $node) 79 | { 80 | $data = array(); 81 | 82 | if (!$node->attributes()) 83 | { 84 | $data = $this->xmlToArray($node); 85 | } 86 | else 87 | { 88 | if (count($node->children())) 89 | { 90 | $data = $data + $this->xmlToArray($node); 91 | } 92 | else 93 | { 94 | $data[] = (string) $node; 95 | } 96 | 97 | foreach ($node->attributes() as $name => $value) 98 | { 99 | $data[$name] = (string) $value; 100 | } 101 | } 102 | 103 | if (count($xml->{$element}) > 1) 104 | { 105 | if (!isset($array[$element])) 106 | { 107 | $array[$element] = array(); 108 | } 109 | 110 | $array[$element][] = $data; 111 | } 112 | else 113 | { 114 | $array[$element] = $data; 115 | } 116 | } 117 | 118 | return $array; 119 | } 120 | } 121 | 122 | new Textpattern_Fluxbb_Api(); 123 | include dirname(dirname(__FILE__)) . '/extern.php'; 124 | -------------------------------------------------------------------------------- /src/style/Textpattern/sass/modules/_buttons.scss: -------------------------------------------------------------------------------- 1 | @use "../setup"; 2 | 3 | /* Buttons 4 | ========================================================================== */ 5 | 6 | /** 7 | * 1. Correct `button` style inheritance in Firefox and Opera. 8 | */ 9 | 10 | button { 11 | text-transform: none; /* 1 */ 12 | } 13 | 14 | /** 15 | * Remove the inner border and padding in Firefox. 16 | */ 17 | 18 | button::-moz-focus-inner, 19 | [type="button"]::-moz-focus-inner, 20 | [type="reset"]::-moz-focus-inner, 21 | [type="submit"]::-moz-focus-inner { 22 | padding: 0; 23 | border-style: none; 24 | } 25 | 26 | /** 27 | * 1. Remove browser-specific default styling. 28 | * 2. Improve usability and consistency of cursor style between image-type 29 | * `input` and others. 30 | */ 31 | 32 | button, 33 | [type="button"], 34 | [type="reset"], 35 | [type="submit"], 36 | .button, 37 | .postlink a, 38 | .subscribelink a { 39 | @include setup.gradient-linear(var(--clr-btn-grad-from), var(--clr-btn-grad-to)); 40 | 41 | display: inline-block; 42 | position: relative; 43 | width: auto; 44 | height: auto; 45 | padding: 0.25em 1em; // 4px / 16px 46 | border: 1px solid var(--clr-btn-brdr); 47 | border-radius: 1em; 48 | background-clip: padding-box; 49 | box-shadow: 0 2px 0 var(--clr-btn-shadow); 50 | color: var(--clr-text-btn); 51 | font-weight: 400; 52 | text-align: center; 53 | appearance: none; /* 2 */ 54 | cursor: pointer; /* 1 */ 55 | user-select: none; 56 | 57 | &:hover, 58 | &:active { 59 | border-color: var(--clr-btn-brdr-interact); 60 | color: var(--clr-text-btn-interact); 61 | text-decoration: none; 62 | } 63 | 64 | &:hover { 65 | filter: brightness(1.05); 66 | } 67 | 68 | &:active { 69 | top: 2px; 70 | box-shadow: none; 71 | filter: brightness(0.95); 72 | } 73 | 74 | &:focus { 75 | border-color: var(--clr-focus); 76 | outline: 2px solid transparent; // Allows for repainting in high contrast modes. 77 | } 78 | } 79 | 80 | /** 81 | * Primary buttons. 82 | * 83 | * Example HTML: 84 | * 85 | * 86 | */ 87 | 88 | .button-primary, 89 | .postlink a, 90 | .blockform [name="submit"] { 91 | @include setup.gradient-linear(var(--clr-btn-primary-grad-from), var(--clr-btn-primary-grad-to)); 92 | 93 | border-color: var(--clr-btn-primary-brdr); 94 | box-shadow: 0 2px 0 var(--clr-btn-primary-shadow); 95 | font-weight: 700; 96 | 97 | &:hover, 98 | &:active { 99 | border-color: var(--clr-btn-primary-brdr-interact); 100 | } 101 | 102 | &:active { 103 | box-shadow: none; 104 | } 105 | 106 | &:focus { 107 | border-color: var(--clr-focus); 108 | } 109 | } 110 | 111 | /** 112 | * Disbaled button additional styling. 113 | * 114 | * Example HTML: 115 | * 116 | * 117 | */ 118 | 119 | button[disabled], 120 | [type="button"][disabled], 121 | [type="reset"][disabled], 122 | [type="submit"][disabled], 123 | .button.disabled { 124 | top: 0 !important; 125 | background: var(--clr-btn-bkgd-disabled) !important; 126 | } 127 | -------------------------------------------------------------------------------- /public/addons/copyable_captcha.php: -------------------------------------------------------------------------------- 1 | bind('register_after_validation', array($this, 'hook_register_after_validation')); 23 | $manager->bind('register_before_header', array($this, 'hook_register_before_header')); 24 | $manager->bind('register_before_submit', array($this, 'hook_register_before_submit')); 25 | } 26 | 27 | function load_lang() 28 | { 29 | global $pun_user; 30 | 31 | if (isset($this->lang)) return; 32 | 33 | $user_lang = file_exists(PUN_ROOT.'lang/'.$pun_user['language'].'/copyable_captcha.php') 34 | ? $pun_user['language'] 35 | : 'English'; 36 | require PUN_ROOT.'lang/'.$user_lang.'/copyable_captcha.php'; 37 | 38 | $this->lang = $lang_copyable_captcha; 39 | } 40 | 41 | function hook_register_after_validation() 42 | { 43 | global $errors, $cookie_name, $cookie_seed; 44 | 45 | if (isset($_POST['req_word']) && isset($_COOKIE[$cookie_name.'_captcha']) && substr_count($_COOKIE[$cookie_name.'_captcha'], '-') === 1) { 46 | list($hash, $time) = explode('-', $_COOKIE[$cookie_name.'_captcha']); 47 | $word = $_POST['req_word']; 48 | if ((int)$time <= time() - 120 || $hash !== sha1(strtolower($word).$cookie_seed.'secret'.$time)) { 49 | $this->load_lang(); 50 | $errors[] = $this->lang['Captcha error']; 51 | } 52 | } else { 53 | $this->load_lang(); 54 | $errors[] = $this->lang['Captcha error']; 55 | } 56 | } 57 | 58 | 59 | function hook_register_before_header() 60 | { 61 | global $required_fields, $errors, $cookie_name, $cookie_seed; 62 | 63 | $this->load_lang(); 64 | $required_fields['req_word'] = $this->lang['Captcha']; 65 | 66 | $time = time(); 67 | $word = random_pass(mt_rand(4, 6)); 68 | $hash = sha1(strtolower($word).$cookie_seed.'secret'.$time); 69 | forum_setcookie($cookie_name.'_captcha', $hash.'-'.$time, $time + 120); 70 | 71 | $array = str_split($word); 72 | $mixin = random_pass(mt_rand(1, 3)); 73 | $i = -1; 74 | $this->styles = ''; 75 | foreach (str_split($mixin) as $ch) { 76 | $i = mt_rand($i+1, count($array)); 77 | array_splice($array, $i, 0, $ch); 78 | $this->styles .= '.masq i:nth-child('.($i + 1).'){display:none;} '; 79 | } 80 | $this->spans = ''.implode('', $array).''; 81 | } 82 | 83 | 84 | function hook_register_before_submit() 85 | { 86 | global $lang_common; 87 | 88 | $this->load_lang(); 89 | 90 | ?> 91 |
92 |
93 | lang['Captcha legend'] ?> 94 |
95 | 96 |

lang['Captcha info'], $this->spans) ?>

97 | 98 |
99 |
100 |
101 | 109 | */ 110 | 111 | #site-navigation-toggle { 112 | @include setup.hide-text; 113 | 114 | display: none; 115 | position: absolute; 116 | z-index: 2; 117 | top: 0.75rem; 118 | right: 5%; 119 | width: 32px; 120 | height: 32px; 121 | margin-top: 1px; 122 | border: 1px solid var(--clr-bkgd); 123 | background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 32 32'%3E%3Cpath fill='%23333' d='M4 6h24v4H4zm0 8h24v4H4zm0 8h24v4H4z'/%3E%3C/svg%3E"); 124 | background-size: 32px 32px; 125 | user-select: none; 126 | -webkit-touch-callout: none; /* 1 */ 127 | 128 | .js & { 129 | display: block; 130 | } 131 | 132 | &.site-navigation-toggle-active { 133 | background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 32 32'%3E%3Cg fill='%23333'%3E%3Cpath d='m6.1 23.1 17-17 2.8 2.8-17 17z'/%3E%3Cpath d='m8.9 6.1 17 17-2.8 2.8-17-17z'/%3E%3C/g%3E%3C/svg%3E"); 134 | } 135 | 136 | &:hover { 137 | border-color: var(--clr-brdr-x-dark); 138 | } 139 | 140 | &:focus { 141 | border-color: var(--clr-focus); 142 | outline: 2px solid transparent; // Allows for repainting in high contrast modes. 143 | } 144 | } 145 | 146 | @include setup.dark-mode { 147 | #site-navigation-toggle { 148 | background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 32 32'%3E%3Cpath fill='%23ced4da' d='M4 6h24v4H4zm0 8h24v4H4zm0 8h24v4H4z'/%3E%3C/svg%3E"); 149 | 150 | &:hover { 151 | border-color: var(--clr-brdr-x-lite); 152 | } 153 | 154 | &.site-navigation-toggle-active { 155 | background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 32 32'%3E%3Cg fill='%23ced4da'%3E%3Cpath d='m6.1 23.1 17-17 2.8 2.8-17 17z'/%3E%3Cpath d='m8.9 6.1 17 17-2.8 2.8-17-17z'/%3E%3C/g%3E%3C/svg%3E"); 156 | } 157 | 158 | &:focus { 159 | border-color: var(--clr-focus); 160 | } 161 | } 162 | } 163 | -------------------------------------------------------------------------------- /src/style/Textpattern/sass/modules/_icons.scss: -------------------------------------------------------------------------------- 1 | @use "../setup"; 2 | 3 | /* Icons 4 | ========================================================================== */ 5 | 6 | /** 7 | * Only using heart icon on this site. 8 | * 9 | * Example HTML: 10 | * 11 | * 12 | * 13 | */ 14 | 15 | .ui-icon { 16 | display: inline-block; 17 | width: 16px; 18 | height: 16px; 19 | margin-bottom: -2px; 20 | overflow: hidden; 21 | vertical-align: baseline; 22 | text-indent: -9999px; 23 | } 24 | 25 | @include setup.dark-mode { 26 | .ui-icon { 27 | filter: brightness(3) sepia(1) hue-rotate(168deg) saturate(33%); 28 | } 29 | 30 | .button .ui-icon { 31 | filter: none; 32 | } 33 | } 34 | 35 | .ui-icon-mail-closed { background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath fill='%23333' d='M1 3h14v10H1V3zm7 6c-.875 0-1.25-.5-1.25-.5L3.25 12h9.5l-3.5-3.5S8.875 9 8 9zm-6 3l4-4-4-4v8zm12 0V4l-4 4 4 4zM9.25 7.5l3.5-3.5h-9.5l3.5 3.5S7.562 8 8 8s1.25-.5 1.25-.5z'/%3E%3C/svg%3E"); } 36 | .ui-icon-home { background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cg fill='%23333'%3E%3Cpath d='M13 14H3V8l5-5 5 5v6zM9 9H7v4h2V9z'/%3E%3Cpath d='M8 2L2 8H1l7-7 7 7h-1z'/%3E%3C/g%3E%3C/svg%3E"); } 37 | .ui-icon-heart { background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath fill='%23333' d='M10.5 2c2.5-.5 4.979 2.174 3.5 5.5C12 12 8 14 8 14s-4-2-6-6.5C.522 4.174 3 1.5 5.5 2 7.522 2.404 8 4 8 4s.479-1.596 2.5-2z'/%3E%3C/svg%3E"); } 38 | .ui-extra-icon-twitter { background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath fill='%23333' d='M15 3.465a5.515 5.515 0 0 1-1.648.478 3.016 3.016 0 0 0 1.262-1.678c-.555.346-1.168.6-1.822.693A2.795 2.795 0 0 0 10.698 2c-1.586 0-2.87 1.357-2.87 3.031 0 .237 0 .469.074.693-2.385-.127-4.499-1.333-5.9-3.168a3.15 3.15 0 0 0-.388 1.524c0 1.052.506 1.98 1.276 2.524-.47 0-.912-.153-1.299-.379 0 1.468.983 2.694 2.302 2.973a2.747 2.747 0 0 1-.757.106h-.539c.365 1.205 1.424 2.078 2.622 2.078a5.56 5.56 0 0 1-3.563 1.299c-.232 0-.46 0-.656-.043A7.818 7.818 0 0 0 5.398 14c5.279 0 8.165-4.62 8.165-8.626v-.392c.566-.375 1.053-.908 1.437-1.517z'/%3E%3C/svg%3E"); } 39 | .ui-extra-icon-mastodon { background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath fill='%23333' d='m14.223 9.393c-.191.988-1.712 2.068-3.458 2.278-.911.109-1.807.209-2.763.165-1.563-.072-2.797-.375-2.797-.375 0 .153.009.298.028.435.203 1.55 1.53 1.643 2.787 1.686 1.268.044 2.398-.314 2.398-.314l.052 1.152s-.887.479-2.468.567c-.872.048-1.954-.022-3.214-.357-2.734-.727-3.204-3.654-3.276-6.624-.021-.883-.008-1.714-.008-2.41 0-3.037 1.981-3.927 1.981-3.927.999-.461 2.713-.654 4.494-.669h.044c1.782.015 3.497.208 4.495.669 0 0 1.981.89 1.981 3.927.001 0 .025 2.241-.276 3.797zm-2.633-5.352c-.395-.442-.911-.668-1.553-.668-.742 0-1.304.287-1.676.86l-.361.608-.361-.608c-.372-.573-.934-.86-1.676-.86-.641 0-1.158.226-1.553.668-.383.442-.573 1.039-.573 1.791v3.677h1.45v-3.569c0-.752.315-1.134.945-1.134.697 0 1.046.453 1.046 1.349v1.954h1.442v-1.954c0-.896.349-1.349 1.046-1.349.63 0 .946.382.946 1.134v3.569h1.45v-3.677c.001-.752-.19-1.349-.572-1.791z'/%3E%3C/svg%3E"); } 40 | .ui-extra-icon-github { background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath fill='%23333' d='M7.999 1a7 7 0 0 0-2.212 13.642c.35.064.478-.152.478-.337 0-.166-.006-.606-.009-1.191-1.947.423-2.358-.938-2.358-.938-.318-.809-.777-1.024-.777-1.024-.636-.434.048-.426.048-.426.702.05 1.072.721 1.072.721.624 1.07 1.638.761 2.037.582.064-.452.245-.761.444-.936-1.554-.177-3.188-.777-3.188-3.46 0-.764.273-1.389.72-1.878-.072-.176-.312-.888.069-1.852 0 0 .588-.188 1.925.718A6.683 6.683 0 0 1 8 4.385c.594.003 1.193.08 1.752.236 1.336-.906 1.923-.718 1.923-.718.382.964.142 1.675.07 1.853.449.489.72 1.114.72 1.878 0 2.689-1.637 3.281-3.196 3.454.251.216.475.643.475 1.296 0 .936-.009 1.691-.009 1.92 0 .187.126.405.481.337A7.001 7.001 0 0 0 7.999 1z'/%3E%3C/svg%3E"); } 41 | .ui-extra-icon-gitlab { background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath fill='%23333' d='m3.363 1.685c.078-.247.427-.247.506.002l1.631 4.814h5l1.631-4.814c.08-.249.427-.249.506 0l2.337 7.246c.072.222-.007.464-.192.602l-6.782 4.965-6.781-4.965c-.185-.138-.264-.381-.193-.602z'/%3E%3C/svg%3E"); } 42 | .ui-extra-icon-bitbucket { background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath fill='%23333' d='m1.376 2.001c-.244.038-.41.268-.37.5l1.994 10.999c.036.208.277.503.5.501h9c.223.002.464-.293.5-.501l1.994-10.999c.04-.233-.126-.462-.37-.5zm8.124 8h-3l-.75-4h4.5z'/%3E%3C/svg%3E"); } 43 | 44 | /** 45 | * Red heart. 46 | */ 47 | 48 | .button:hover, 49 | .button:active, 50 | .button:focus { 51 | .ui-icon-heart { 52 | background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath fill='%23e00' d='M10.5 2c2.5-.5 4.979 2.174 3.5 5.5C12 12 8 14 8 14s-4-2-6-6.5C.522 4.174 3 1.5 5.5 2 7.522 2.404 8 4 8 4s.479-1.596 2.5-2z'/%3E%3C/svg%3E"); 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/style/Textpattern/sass/modules/_typography.scss: -------------------------------------------------------------------------------- 1 | @use "../setup"; 2 | @use "sass:math"; 3 | 4 | /* Typography 5 | ========================================================================== */ 6 | 7 | /** 8 | * Establish baseline. 9 | * 10 | * 1. Prevent adjustments of font size after orientation changes in iOS. 11 | */ 12 | 13 | html { 14 | font-size: setup.$base-font-size; 15 | line-height: setup.$base-line-height; 16 | text-size-adjust: 100%; /* 1 */ 17 | } 18 | 19 | /** 20 | * Global font. 21 | * 22 | * 1. Enable font ligatures globally, where supported by OpenType fonts. 23 | */ 24 | 25 | body { 26 | font-family: var(--font-sans-serif); 27 | font-feature-settings: "liga"; /* 1 */ 28 | } 29 | 30 | /** 31 | * Harmonize size, style and vertical margin of headings. 32 | */ 33 | 34 | h1, 35 | h2, 36 | h3, 37 | h4, 38 | h5, 39 | h6 { 40 | clear: both; 41 | font-family: var(--font-serif); 42 | } 43 | 44 | main { 45 | h1, 46 | h2, 47 | h3, 48 | h4, 49 | h5, 50 | h6, { 51 | color: var(--clr-text-promoted); 52 | } 53 | } 54 | 55 | h1, 56 | h2, 57 | h3 { 58 | letter-spacing: -0.25px; 59 | } 60 | 61 | h1 { 62 | margin: 0.6315789em 0; // 24px / 38px 63 | font-size: 2.375rem; // 38px / 16px 64 | line-height: 1.1842105; // 45px / 38px 65 | } 66 | 67 | h2 { 68 | margin: 0.8571429em 0; // 24px / 28px 69 | font-size: 1.75rem; // 28px / 16px 70 | line-height: 1.25; // 35px / 28px 71 | } 72 | 73 | h3 { 74 | margin: 1em 0; // 22px 75 | font-size: 1.375rem; // 22px / 16px 76 | line-height: 1.3181818; // 29px / 22px 77 | } 78 | 79 | h4 { 80 | margin: 0.8888889em 0; // 16px / 18px 81 | font-size: 1.125rem; // 18px / 16px 82 | line-height: 1.4444444; // 26px / 18px 83 | } 84 | 85 | h5, 86 | h6 { 87 | margin: 1em 0; // 16px 88 | font-size: 1rem; 89 | line-height: setup.$small-line-height; 90 | } 91 | 92 | /** 93 | * Add the correct font weight in Chrome, Edge, and Safari. 94 | */ 95 | 96 | b, 97 | strong { 98 | font-weight: 700; 99 | } 100 | 101 | /** 102 | * Add vertical margin to addresses. 103 | */ 104 | 105 | address { 106 | margin: 1em 0; 107 | } 108 | 109 | /** 110 | * Oxford English quote behaviour (quotes: ‘ ’, quotes within quotes: “ ”). 111 | */ 112 | 113 | q, 114 | blockquote { 115 | quotes: "\2018" "\2019" "\201C" "\201D"; 116 | } 117 | 118 | /** 119 | * Additional styling for blockquotes. 120 | */ 121 | 122 | blockquote { 123 | margin: 1em 0; 124 | padding: 1px 1em 1px 1.5em; 125 | border-left: 0.25em solid var(--clr-hilite); 126 | border-radius: 0 setup.$border-radius setup.$border-radius 0; 127 | background-color: var(--clr-hilite-box); 128 | } 129 | 130 | /** 131 | * 1. Remove the bottom border in Chrome 57+. 132 | * 2. Add the correct text decoration in Chrome, Edge, Opera, and Safari. 133 | */ 134 | 135 | abbr[title] { 136 | border-bottom: 0; /* 1 */ 137 | text-decoration: underline dotted; /* 2 */ 138 | } 139 | 140 | /** 141 | * Consistent styling for `mark` and `var` tags. 142 | */ 143 | 144 | mark, 145 | var { 146 | padding: 0 0.25em; // 0 4px 147 | border-radius: math.div(setup.$border-radius, 2); 148 | background: var(--clr-hilite-box); 149 | color: var(--clr-text); 150 | } 151 | 152 | /** 153 | * Harmonize size and style of computer text. 154 | * 155 | * 1. Don't use ligatures on monospace font. 156 | */ 157 | 158 | pre { white-space: pre-wrap; } 159 | 160 | pre, 161 | code, 162 | kbd, 163 | samp { 164 | border: 1px solid var(--clr-brdr-x-lite); 165 | border-radius: 0.2857143em; // 4px / 14px 166 | background-color: var(--clr-bkgd-box); 167 | color: var(--clr-text); 168 | font-family: var(--font-monospaced); 169 | font-feature-settings: normal; /* 1 */ 170 | font-size: setup.$code-font-size; 171 | } 172 | 173 | code, 174 | kbd, 175 | samp { 176 | padding: 1px 0.2142857em; // 3px / 14px 177 | } 178 | 179 | /** 180 | * Additional stylng for preformatted text/code. 181 | * 182 | * 1. Truncate deep code boxes. 183 | * 2. Contain overflow in all browsers. 184 | * 3. Don't wrap long words. 185 | * 4. Overflow by default is bad. 186 | * 5. Set tab size to 4 spaces. 187 | */ 188 | 189 | pre { 190 | box-sizing: border-box; 191 | max-height: 50vh; /* 1 */ 192 | padding: 0.5714286em 1.1428571em; // 8px / 14px + 16px / 14px 193 | overflow-x: auto; /* 2 */ 194 | word-wrap: normal; /* 3 */ 195 | white-space: pre-wrap; /* 4 */ 196 | tab-size: 4; /* 5 */ 197 | 198 | code { 199 | padding: 0; 200 | border: 0; 201 | background-color: transparent; 202 | font-size: 1em; // 14px 203 | hyphens: none; 204 | word-wrap: normal; 205 | word-break: normal; 206 | word-spacing: normal; 207 | white-space: pre; 208 | } 209 | } 210 | 211 | /** 212 | * Prevent `sub` and `sup` elements from affecting the line height in all browsers. 213 | */ 214 | 215 | sub, 216 | sup.footnote, // override Textile class 217 | sup { 218 | position: relative; 219 | font-size: 0.75em; // 12px / 16px 220 | line-height: 0; 221 | vertical-align: baseline; 222 | } 223 | 224 | sup { 225 | top: -0.5em; 226 | } 227 | 228 | sub { 229 | bottom: -0.25em; 230 | } 231 | 232 | /** 233 | * Harmonize size and style of small text. 234 | */ 235 | 236 | small, 237 | tfoot, 238 | .footnote { 239 | font-size: setup.$small-font-size; 240 | } 241 | 242 | /** 243 | * 1. Show the overflow in Edge and IE. 244 | * 2. Add the correct box sizing in Firefox. 245 | */ 246 | 247 | hr { 248 | box-sizing: content-box; /* 2 */ 249 | height: 0; 250 | overflow: visible; /* 1 */ 251 | border: 0; // remove the default `hr` border 252 | border-bottom: 1px solid var(--clr-brdr); 253 | } 254 | -------------------------------------------------------------------------------- /src/style/Textpattern/sass/screen.scss: -------------------------------------------------------------------------------- 1 | @use "setup"; 2 | @forward "modules"; 3 | 4 | /* ========================================================================== 5 | CSS custom variables 6 | ========================================================================== */ 7 | 8 | /* stylelint-disable declaration-colon-space-after */ 9 | 10 | :root { 11 | // font families 12 | --font-serif: "PT Serif", Georgia, serif; 13 | --font-sans-serif: system-ui, -apple-system, "Segoe UI", Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol"; 14 | --font-monospaced: Menlo, Consolas, Monaco, monospace; 15 | // text colours 16 | --clr-text: hsl(0 0% 20%); 17 | --clr-text-promoted: hsl(0 0% 17%); 18 | --clr-text-promoted-a50: hsl(0 0% 17% / 0.5); 19 | --clr-text-demoted: hsl(0 0% 40%); 20 | --clr-text-form: hsl(0 0% 0%); 21 | --clr-text-placeholder: hsl(0 0% 60%); 22 | --clr-text-black-enforced: hsl(0 0% 20%); 23 | --clr-text-white-enforced: hsl(0 0% 100%); 24 | // interaction colours 25 | --clr-a: hsl(216 100% 35%); 26 | --clr-a-interact: hsl(216 100% 50%); 27 | --clr-a-alt: hsl(216 100% 80%); 28 | --clr-a-alt-interact: hsl(216 100% 95%); 29 | --clr-focus: hsl(216 100% 50% / 1); 30 | --clr-nav-interact: hsl(216 95% 85%); 31 | --clr-nav-active: hsl(216 100% 95%); 32 | // neutral colours 33 | --clr-bkgd: hsl(0 0% 100%); 34 | --clr-bkgd-box: hsl(0 0% 97%); 35 | --clr-bkgd-form: hsl(0 0% 100%); 36 | --clr-bkgd-form-disabled: hsl(0 0% 89%); 37 | --clr-grad-from: hsl(0 0% 93%); 38 | --clr-grad-to: hsl(0 0% 87%); 39 | // accent colours 40 | --clr-hilite: hsl(48 100% 63%); 41 | --clr-hilite-enforced: hsl(48 100% 63%); 42 | --clr-strong-hilite-box: hsl(48 100% 76%); 43 | --clr-hilite-box: hsl(48 100% 94%); 44 | // border colours 45 | --clr-brdr-x-lite: hsl(0 0% 85%); 46 | --clr-brdr-lite: hsl(0 0% 82.5%); 47 | --clr-brdr: hsl(0 0% 80%); 48 | --clr-brdr-dark: hsl(0 0% 75%); 49 | --clr-brdr-x-dark: hsl(0 0% 70%); 50 | // button colours 51 | --clr-text-btn: hsl(0 0% 20%); 52 | --clr-text-btn-interact: hsl(0 0% 17%); 53 | --clr-btn-grad-from: hsl(0 0% 93%); 54 | --clr-btn-grad-to: hsl(0 0% 87%); 55 | --clr-btn-brdr: hsl(0 0% 87%); 56 | --clr-btn-brdr-interact: hsl(0 0% 77%); 57 | --clr-btn-shadow: hsl(0 0% 67%); 58 | --clr-btn-primary-grad-from: hsl(48 100% 63%); 59 | --clr-btn-primary-grad-to: hsl(48 100% 57%); 60 | --clr-btn-primary-brdr: hsl(48 100% 57%); 61 | --clr-btn-primary-brdr-interact: hsl(48 100% 47%); 62 | --clr-btn-primary-shadow: hsl(48 100% 37%); 63 | --clr-btn-bkgd-disabled: hsl(0 0% 89%); 64 | // alert colours 65 | --clr-success-text: hsl(120 60% 34%); 66 | --clr-success-bkgd: hsl(120 40% 90%); 67 | --clr-success-brdr: hsl(102 40% 68%); 68 | --clr-warning-text: hsl(41 100% 40%); 69 | --clr-warning-bkgd: hsl(41 64% 91%); 70 | --clr-warning-brdr: hsl(41 64% 71%); 71 | --clr-error-text: hsl(4 69% 36%); 72 | --clr-error-bkgd: hsl(4 43% 91%); 73 | --clr-error-brdr: hsl(4 43% 78%); 74 | --clr-info-text: hsl(200 50% 45%); 75 | --clr-info-bkgd: hsl(200 78% 95%); 76 | --clr-info-brdr: hsl(200 78% 82%); 77 | } 78 | 79 | @include setup.dark-mode { 80 | :root { 81 | // dark mode text colours 82 | --clr-text: hsl(210 14% 83%); 83 | --clr-text-promoted: hsl(0 0% 100%); 84 | --clr-text-promoted-a50: hsl(0 0% 100% / 0.5); 85 | --clr-text-demoted: hsl(210 14% 77%); 86 | --clr-text-form: hsl(0 0% 100%); 87 | --clr-text-placeholder: hsl(210 6% 48%); 88 | // interaction colours 89 | --clr-a: hsl(204 100% 81%); 90 | --clr-a-interact: hsl(204 100% 87%); 91 | --clr-focus: hsl(312 100% 50%); 92 | --clr-nav-interact: hsl(214 45% 19%); 93 | --clr-nav-active: hsl(214 51% 22%); 94 | // neutral colours 95 | --clr-bkgd: hsl(210 11% 24%); 96 | --clr-bkgd-box: hsl(210 11% 21%); 97 | --clr-bkgd-form: hsl(210 11% 18%); 98 | --clr-bkgd-form-disabled: hsl(210 11% 18%); 99 | --clr-grad-from: hsl(210 7% 30%); 100 | --clr-grad-to: hsl(210 7% 36%); 101 | // accent colours 102 | --clr-hilite: hsl(48 100% 63%); 103 | --clr-strong-hilite-box: hsl(48 42% 47%); 104 | --clr-hilite-box: hsl(48 20% 30%); 105 | // border colours 106 | --clr-brdr-x-lite: hsl(210 7% 33%); 107 | --clr-brdr-lite: hsl(210 7% 43%); 108 | --clr-brdr: hsl(210 7% 53%); 109 | --clr-brdr-dark: hsl(210 7% 21%); 110 | --clr-brdr-x-dark: hsl(210 7% 6%); 111 | // alert colours 112 | --clr-success-text: hsl(100 60% 50%); 113 | --clr-success-bkgd: hsl(109 27% 20%); 114 | --clr-success-brdr: hsl(100 60% 50% / 0.33); 115 | --clr-warning-text: hsl(40 100% 62%); 116 | --clr-warning-bkgd: hsl(49 35% 21%); 117 | --clr-warning-brdr: hsl(40 100% 62% / 0.33); 118 | --clr-error-text: hsl(337 100% 60%); 119 | --clr-error-bkgd: hsl(348 34% 21%); 120 | --clr-error-brdr: hsl(337 100% 60% / 0.43); 121 | --clr-info-text: hsl(207 100% 63%); 122 | --clr-info-bkgd: hsl(207 68% 17%); 123 | --clr-info-brdr: hsl(207 100% 63% / 0.38); 124 | } 125 | } 126 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Textpattern support forum 2 | 3 | This repository contains the source code for the [Textpattern support forum](https://forum.textpattern.com/). 4 | 5 | Requires an installation of our [customized clone of FluxBB](https://github.com/textpattern/fluxbb/tree/feature-textpattern-forum). 6 | 7 | ## Supported web browsers 8 | 9 | * Chrome, Edge, Firefox, Safari and Opera the last two recent stable releases. 10 | * Firefox ESR latest major point release. 11 | 12 | Older versions of the above and other browsers may work, but these are the ones we verify. 13 | 14 | Building this repository requires: 15 | 16 | * [Node.js](https://nodejs.org/) 17 | * [Grunt](https://gruntjs.com/) 18 | * [Composer](https://getcomposer.org/) 19 | 20 | Environment must consist of: 21 | 22 | * Apache >=2.2 23 | * PHP >=7.4 24 | * MySQL >=5.0.6 25 | * Unix-like OS, e.g. Linux or macOS 26 | 27 | ## Setup 28 | 29 | ### Installing required tools 30 | 31 | The project uses [Grunt](https://gruntjs.com/) to run tasks and [Sass](http://sass-lang.com/) for CSS pre-processing. This creates a few dependencies in addition to your normal PHP required by FluxBB. First make sure you have base dependencies installed: [Node.js](https://nodejs.org/) and [Grunt](https://gruntjs.com/). You can install Node using the [installer](https://nodejs.org/), Composer using the [installer](https://getcomposer.org/), and Grunt with npm: 32 | 33 | ```ShellSession 34 | $ npm install -g grunt-cli 35 | ``` 36 | 37 | Consult the Grunt documentation for more instructions if necessary. 38 | 39 | ### Setting up Apache virtual host 40 | 41 | The `public/` directory is intended to be set as the server's document root. You can do this by adding a new virtual host to your `httpd.conf`. Along the lines of: 42 | 43 | ```apache 44 | 45 | VirtualHost "/absolute/path/to/textpattern-forum/public" 46 | ServerName forum.textpattern.test 47 | 48 | ``` 49 | 50 | On a local development server, after this you can use your hosts file to point the development domain to correct location (e.g. back to home), run a local DNS server that resolves .test TLDs, or use a [xip.io](http://xip.io/) domain. 51 | 52 | ### Installing dependencies 53 | 54 | After you have the base dependencies taken care of, you can install the project's dependencies. Navigate to the project's directory, and run the dependency managers: 55 | 56 | ```ShellSession 57 | $ cd textpattern-forum 58 | $ npm install 59 | $ composer install 60 | ``` 61 | 62 | **npm** installs Node modules for Grunt and **composer** installs PHP libraries. 63 | 64 | ### Installing FluxBB 65 | 66 | Once you have Grunt installed, you can then install our [customized clone of FluxBB](https://github.com/textpattern/fluxbb/tree/feature-textpattern-forum) - place it in the `public/` directory. Complete FluxBB's installation by following the normal [Installation steps](https://fluxbb.org/docs/v1.5/installing), and use [this as your config.php template](https://github.com/textpattern/textpattern-forum/blob/main/src/setup/config.php.dist). 67 | 68 | ### Updating and patching FluxBB 69 | 70 | Periodically we update our [customized clone of FluxBB](https://github.com/textpattern/fluxbb/tree/feature-textpattern-forum). To update your FluxBB installation, simply install files from that repository again. 71 | 72 | You may need to [adjust the write permissions](https://fluxbb.org/docs/v1.5/installing#write-permissions) on the `public/cache/` directory after updating. 73 | 74 | ## Building 75 | 76 | This repository hosts sources and needs to be built before it can be used. After you have installed all dependencies, you will be able to run tasks using Grunt, including building: 77 | 78 | ```ShellSession 79 | $ grunt @task@ 80 | ``` 81 | 82 | Where the `@task@` is either `build` or `watch`. 83 | 84 | * The `build` task builds the project. 85 | * The `watch` task will launch a task that watches for file changes; the project is then automatically built if a source file is modified. 86 | 87 | ## REST API 88 | 89 | We offer a public API that can be used to retrieve data from the forums and topics. The public end point can be found from `https://forum.textpattern.com/api`. Data can be retrieved as JSON, and options can be passed optional HTTP query parameters. This API is read-only, and all requests must be done using HTTP GET method. You can also ping resource existence with HEAD, but any other methods are rejected. 90 | 91 | ### Response codes 92 | 93 | HTTP status codes can be used to detect the type of response. The server responds with: 94 | 95 | * 200: Successful response. 96 | * 401: You will need to log in to access this resource. The resource may be removed, or private. 97 | * 404: The resource has been removed, or has never existed. 98 | * 500: Internal server error. 99 | * 503: Server is under maintenance. 100 | 101 | ### Authentication 102 | 103 | Authentication happens using basic HTTP method and regular forum user account. 104 | 105 | ```ShellSession 106 | $ curl -u "username" https://forum.textpattern.com/api/ 107 | ``` 108 | 109 | If you request a private or removed resource without being logged in, you will be treated with 401 response: 110 | 111 | ```ShellSession 112 | $ curl -I https://forum.textpattern.com/api/posts/401 113 | ``` 114 | 115 | Responds with: 116 | 117 | ``` 118 | HTTP/1.0 401 Unauthorized 119 | Date: Tue, 15 Oct 2013 09:16:42 GMT 120 | Server: Apache 121 | WWW-Authenticate: Basic realm="Textpattern CMS Support Forum External Syndication" 122 | Connection: close 123 | Content-Type: application/json; charset=UTF-8 124 | ``` 125 | 126 | ### Topics 127 | 128 | ``` 129 | GET https://forum.textpattern.com/api/topics/:forum 130 | ``` 131 | 132 | Returns topics from the specified forum. 133 | 134 | #### Optional parameters 135 | 136 | * **limit**: number items to show. A value between 1 and 50. Defaults to 15. 137 | * **sort**: either `last_post` or `posted`. 138 | 139 | #### Example request 140 | 141 | ```ShellSession 142 | $ curl https://forum.textpattern.com/api/topics/2 143 | ``` 144 | 145 | Response headers: 146 | 147 | ``` 148 | HTTP/1.1 200 OK 149 | Date: Sun, 13 Oct 2013 11:24:49 GMT 150 | Server: Apache 151 | Content-Type: application/json; charset=UTF-8 152 | ``` 153 | 154 | Response body: 155 | 156 | ``` 157 | { 158 | "url": ["https:\/\/forum.textpattern.com\/index.php"], 159 | "topic": [ 160 | { 161 | "title": "Better way to upload media", 162 | "link": "https:\/\/forum.textpattern.com\/viewtopic.php?id=40096&action=new", 163 | "content": "

+ lots<\/p>", 164 | "author": { 165 | "name": "tye", 166 | "uri": "https:\/\/forum.textpattern.com\/profile.php?id=5751" 167 | }, 168 | "posted": "26 September 2013 21:51", 169 | "postedutc": "2013-09-24T16:18:48Z", 170 | "id": "40096" 171 | } 172 | ] 173 | } 174 | ``` 175 | 176 | ### Posts 177 | 178 | ``` 179 | GET https://forum.textpattern.com/api/posts/:topic 180 | ``` 181 | 182 | Returns replies from a specific public topic. 183 | 184 | #### Optional parameters 185 | 186 | * **limit**: number items to show. A value between 1 and 50. Defaults to 15. 187 | 188 | #### Example request 189 | 190 | ```ShellSession 191 | $ curl https://forum.textpattern.com/api/posts/40092 192 | ``` 193 | 194 | Response headers: 195 | 196 | ``` 197 | HTTP/1.1 200 OK 198 | Date: Sun, 13 Oct 2013 12:24:49 GMT 199 | Server: Apache 200 | Content-Type: application/json; charset=UTF-8 201 | ``` 202 | 203 | Response body: 204 | 205 | ``` 206 | { 207 | "url": ["https:\/\/forum.textpattern.com\/viewtopic.php?id=40092"], 208 | "post": [ 209 | { 210 | "title": "Re: Tag tree best practise: to nest or not to nest", 211 | "link": "https:\/\/forum.textpattern.com\/viewtopic.php?pid=275473#p275473", 212 | "content": "

Stef, this is really useful – I’m on the right track. Thank you very much.<\/p>", 213 | "author": { 214 | "name": "gaekwad", 215 | "uri": "https:\/\/forum.textpattern.com\/profile.php?id=7456" 216 | }, 217 | "posted": "26 September 2013 21:51", 218 | "postedutc": "2013-09-24T16:18:48Z", 219 | "id": "275473" 220 | } 221 | ] 222 | } 223 | ``` 224 | 225 | ## Contributing 226 | 227 | Want to help out with the development of Textpattern CMS? Please refer to the [Contributing documentation](https://docs.textpattern.com/development/contributing) for full details. 228 | 229 | ## License 230 | 231 | Licensed under MIT license. 232 | -------------------------------------------------------------------------------- /src/style/Textpattern/maintenance.tpl: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | Go to main content 30 |

31 | 35 | 49 |
50 |
51 |

Textpattern CMS support forum

52 | 53 |
54 |
55 |
56 | 117 | 118 | 119 | 120 | -------------------------------------------------------------------------------- /src/style/Textpattern/js/app.js: -------------------------------------------------------------------------------- 1 | (function () 2 | { 3 | 'use strict'; 4 | 5 | // Load objects as variables. 6 | 7 | var code = document.querySelectorAll('pre code'), 8 | navmenu = document.getElementById('site-navigation'); 9 | 10 | // Syntax highlighting, via 'Prism'. 11 | // Applies syntax highlighting to `code` HTML elements. 12 | // More info - https://prismjs.com. 13 | 14 | if (code.length) { 15 | var elems = document.querySelectorAll('.language-txp'); 16 | 17 | [].forEach.call(elems, function(el) { 18 | el.classList.add('language-html'); 19 | el.classList.remove('language-txp'); 20 | }); 21 | 22 | Prism.highlightAll(); 23 | } 24 | 25 | // Responsive navigation menu. 26 | 27 | if (navmenu) { 28 | var navtoggle = document.getElementById('site-navigation-toggle'), 29 | navlist = document.getElementById('site-navigation-list'); 30 | 31 | navtoggle.addEventListener('click', function(e) 32 | { 33 | e.preventDefault(); 34 | navtoggle.classList.toggle('site-navigation-toggle-active'); 35 | navmenu.classList.toggle('site-navigation-open'); 36 | }); 37 | 38 | navlist.addEventListener('focusin', function() 39 | { 40 | navtoggle.classList.add('site-navigation-toggle-active'); 41 | navmenu.classList.add('site-navigation-open'); 42 | }); 43 | 44 | navlist.addEventListener('focusout', function() 45 | { 46 | navtoggle.classList.remove('site-navigation-toggle-active'); 47 | navmenu.classList.remove('site-navigation-open'); 48 | }); 49 | } 50 | 51 | // Quoting. 52 | 53 | $(function () 54 | { 55 | var field = $('#quickpostform textarea[name=req_message]'), button; 56 | 57 | if (!field.length) { 58 | return; 59 | } 60 | 61 | $('.postlink a').eq(0).attr('href', '#quickpostform'); 62 | 63 | button = $('Quote').on('click', function () 64 | { 65 | var $this = $(this), 66 | tagStart, 67 | tagEnd, 68 | paragraph, 69 | post = $this.parents('.blockpost').eq(0), 70 | name = post.find('.postleft dl dt').eq(0).text(), 71 | message = post.find('.postmsg').eq(0).clone().find('.postedit, table').remove().end(), 72 | link = post.find('h2 a').eq(0).attr('href'), 73 | postId = post.attr('id').substr(1), 74 | value = $.trim(field.val()); 75 | 76 | // Remove quotes. 77 | 78 | message.find('blockquote').each(function () 79 | { 80 | var bq = $(this), prev = bq.prev('h6, p'); 81 | 82 | if (prev.length && $.trim(prev.text()).substr(-1) === ':') { 83 | prev.remove(); 84 | } 85 | 86 | bq.remove(); 87 | }); 88 | 89 | // Compress code blocks to a single line. 90 | 91 | message.find('pre').each(function () 92 | { 93 | $(this).after('

@' + $.trim($('

').text($(this).text()).html().split('\n').slice(0, 1).join('')) + '...@

').remove(); 94 | }); 95 | 96 | // Links. 97 | 98 | message.find('a').each(function () 99 | { 100 | $(this).prepend('"').append('":' + $('
').text($(this).attr('href')).html()); 101 | }); 102 | 103 | // Images. 104 | 105 | message.find('img').each(function () 106 | { 107 | $(this).after('!' + $('
').text($(this).attr('src')).html() + '!').remove(); 108 | }); 109 | 110 | // Spans. 111 | 112 | message.find('strong').prepend('*').append('*'); 113 | message.find('b').prepend('**').append('**'); 114 | message.find('cite').prepend('??').append('??'); 115 | message.find('em').prepend('_').append('_'); 116 | message.find('i').prepend('__').append('__'); 117 | message.find('del').prepend('-').append('-'); 118 | message.find('ins').prepend('+').append('+'); 119 | message.find('sub').prepend('~').append('~'); 120 | message.find('sup').prepend('^').append('^'); 121 | message.find('code').prepend('@').append('@'); 122 | 123 | // Headings. 124 | 125 | message.find('h1, h2, h3, h4, h5, h6').prepend('*').append('*'); 126 | 127 | // Lists. Textile will wrap the lists in paragraphs as of 3.5.x. 128 | 129 | $.each({'ol' : '#', 'ul' : '*'}, function (type, marker) 130 | { 131 | message.children(type).each(function () 132 | { 133 | var items = [], list = $(this); 134 | 135 | list.find('li').each(function () 136 | { 137 | var bullet = ''; 138 | 139 | for (var i = 0; i < $(this).parents(list).length / 2; i++) { 140 | bullet += marker; 141 | } 142 | 143 | items.push(bullet + ' ' + $.trim($(this).clone().children(type).remove().end().html())); 144 | }); 145 | 146 | list.after('

' + items.join('\n') + '

').remove(); 147 | }); 148 | }); 149 | 150 | paragraph = message.find('h1, h2, h3, h4, h5, h6, p'); 151 | 152 | if (paragraph.length > 1) { 153 | tagStart = '\n\nbq.. '; 154 | tagEnd = '\n\np. '; 155 | } else { 156 | tagStart = '\n\nbq. '; 157 | tagEnd = '\n\n'; 158 | } 159 | 160 | message = $.trim(paragraph.append('\n\n').text()); 161 | 162 | if (value) { 163 | value = $.trim(value).replace(/\r?\n\r?\np\.$/, '') + '\n\n'; 164 | } 165 | 166 | name = $.trim(name).replace(/==/, ''); 167 | 168 | if (message) { 169 | value = value + 'h6. ==' + name + '== wrote "#' + postId + '":./' + link + ':' + tagStart + message + tagEnd; 170 | } else { 171 | value = value + 'h6. In reply to ==' + name + '== "#' + postId + '":./' + link + ':\n\n'; 172 | } 173 | 174 | field.val(value).focus(); 175 | 176 | if ($.type(field[0].setSelectionRange) !== 'undefined') { 177 | field[0].setSelectionRange(value.length, value.length); 178 | } 179 | }); 180 | 181 | $('.postfootright ul').append($('
  • ').html($('').html(button))); 182 | }); 183 | 184 | // Embed widgets. 185 | 186 | $(function () 187 | { 188 | var loadTwitter = false, 189 | tweetRegex = /^https?:\/\/twitter\.com\/(#!\/)?[a-z0-9]+\/status(es)?\/[0-9]+$/i, 190 | youtubeRegex = /^https?:\/\/(?:www\.)?(?:youtube\.com\/watch(?:\/|\?v=)|youtu\.be\/)([a-z0-9\-\_]+)$/i; 191 | 192 | $('.postmsg > p > a').each(function () 193 | { 194 | var $this = $(this), href = $this.attr('href'), matches; 195 | 196 | if ($this.parent().text() !== $this.text()) { 197 | return; 198 | } 199 | 200 | if (tweetRegex.test(href)) { 201 | loadTwitter = true; 202 | 203 | $this.parent().after( 204 | $('