diff --git a/citizen.php b/citizen.php new file mode 100644 index 00000000..71ef8d1b --- /dev/null +++ b/citizen.php @@ -0,0 +1,14 @@ +get( 'headelement' ); + $loggedinclass = 'not-logged'; + + // Add class if logged in + if ( $this->getSkin()->getUser()->isLoggedIn() ) { + $loggedinclass .= 'logged-in'; + } + + $html .= Html::rawElement( 'div', [ 'class' => $loggedinclass, 'id' => 'mw-wrapper' ], + // Header + Html::rawElement( 'header', [ 'class' => 'mw-header-container', 'id' => 'mw-navigation' ], + Html::rawElement( 'div', [ 'class' => 'mw-header-icons'], + // Site navigation menu + $this->getHamburgerMenu() + ) . + Html::rawElement( 'div', [ 'class' => 'mw-header-icons'], + // User icons + Html::rawElement( 'div', [ 'class' => 'mw-header', 'id' => 'user-icons' ], + $this->getUserIcons() + ) . + // Search bar + $this->getSearchButton() + ) + ) . + // Main body + Html::rawElement( 'main', [ 'class' => 'mw-body', 'id' => 'content', 'role' => 'main' ], + // Container for compatiblity with extensions + Html::rawElement( 'section', [ 'id' => 'mw-body-container' ], + $this->getSiteNotice() . + $this->getNewTalk() . + $this->getIndicators() . + // Page editing and tools + $this->getPageTools() . + Html::rawElement( 'h1', + [ + 'class' => 'firstHeading', + 'lang' => $this->get( 'pageLanguage' ) + ], + $this->get( 'title' ) + ) . + Html::rawElement( 'div', [ 'id' => 'siteSub' ], + $this->getMsg( 'tagline' )->parse() + ) . + Html::rawElement( 'div', [ 'class' => 'mw-body-content' ], + Html::rawElement( 'div', [ 'id' => 'contentSub' ], + $this->getPageSubtitle() . + Html::rawElement( + 'p', + [], + $this->get( 'undelete' ) + ) + ) . + $this->get( 'bodycontent' ) . + $this->getClear() . + Html::rawElement( 'div', [ 'class' => 'printfooter' ], + $this->get( 'printfooter' ) + ) . + $this->getPageLinks() . + $this->getCategoryLinks() + ) . + $this->getDataAfterContent() . + $this->get( 'debughtml' ) + ) + ) . + $this->getFooterBlock() . + // Site title for sidebar + Html::rawElement( 'div', [ 'id' => 'mw-sidebar-sitename', 'role' => 'banner' ], + $this->getSiteTitle('link') + ) . + $this->getBottomBar() + ); + + $html .= $this->getTrail(); + $html .= Html::closeElement( 'body' ); + $html .= Html::closeElement( 'html' ); + + echo $html; + } + + /** + * Generates the bottom bar + * @return string html + */ + protected function getBottomBar() { + + $linkDiscord = 'https://discord.gg/3kjftWK'; + $titleDiscord = 'Contact Us on Discord'; + $textDiscord = 'Discord'; + /* + $linkReddit = 'https://www.reddit.com/r/starcitizen'; + $titleReddit = 'Visit /r/starcitizen'; + $textReddit = 'Reddit'; + */ + + $html = Html::openElement( 'div', [ 'id' => 'mw-bottombar' ] ); + + $html .= Html::rawElement( 'div', [ 'id' => 'mw-bottombar-contact' ], + Html::rawElement( 'div', [ 'class' => 'citizen-ui-icon', 'id' => 'citizen-ui-discord' ], + Html::rawElement( 'a', [ 'href' => $linkDiscord, 'title' => $titleDiscord, 'rel' => 'noopener noreferrer', 'target' => '_blank' ], $textDiscord ) + ) + /* + Html::rawElement( 'div', [ 'class' => 'citizen-ui-icon', 'id' => 'citizen-ui-reddit' ], + Html::rawElement( 'a', [ 'href' => $linkReddit, 'title' => $titleReddit, 'target' => '_blank' ], $textReddit ) + ) + */ + ); + $html .= Html::closeElement( 'div' ); + + return $html; + } + + /** + * Generates the search button + * @return string html + */ + protected function getSearchButton() { + $titleButton = 'Toggle Search'; + + $html = Html::rawElement( 'div', [ 'class' => 'mw-header-end', 'id' => 'site-search' ], + Html::rawElement( 'input', [ 'type' => 'checkbox', 'role' => 'button', 'title' => $titleButton ]) . + + // Search button + Html::rawElement( 'div', [ 'id' => 'search-icon-container' ], + Html::rawElement( 'div', [ 'id' => 'search-icon' ] ) + ) . + + // Search form + $this->getSearch() + ); + return $html; + } + + /** + * Generates the hamburger menu + * @return string html + */ + protected function getHamburgerMenu() { + $titleButton = 'Toggle Menu'; + + $html = Html::openElement( 'div', [ 'class' => 'mw-header-end', 'id' => 'mw-header-menu' ]); + $html .= Html::rawElement( 'input', [ 'type' => 'checkbox', 'role' => 'button', 'title' => $titleButton ]); + + // Actual hamburger + $html .= Html::openElement( 'div', [ 'id' => 'mw-header-menu-toggle' ]); + for ($i = 1; $i <= 3; $i++) { + $html .= Html::rawElement( 'span' ); + } + $html .= Html::closeElement( 'div' ); + // Get sidebar links + $html .= Html::rawElement( 'div', [ 'id' => 'mw-header-menu-drawer' ], + Html::rawElement( 'div', [ 'id' => 'mw-header-menu-drawer-container' ], + $this->getSiteTitle('text') . + // Container for navigation and tools + Html::rawElement( 'div', [ 'id' => 'p-nt-container' ], + $this->getSiteNavigation() + ) . + $this->getUserLinks() + ) + ); + $html .= Html::closeElement( 'div' ); + + return $html; + } + + /** + * Generates the sitetitle + * @return string html + */ + protected function getSiteTitle( $option ) { + $html = ''; + $language = $this->getSkin()->getLanguage(); + $siteTitle = $language->convert( $this->getMsg( 'sitetitle' )->escaped() ); + + switch ( $option ) { + case 'link': + $html .= Html::rawElement( + 'a', + [ + 'id' => 'p-banner', + 'class' => 'mw-wiki-title', + 'href' => $this->data['nav_urls']['mainpage']['href'] + ] + Linker::tooltipAndAccesskeyAttribs( 'p-logo' ), + $siteTitle + ); + break; + case 'text': + $html .= Html::rawElement( + 'span', + [ + 'id' => 'p-banner', + 'class' => 'mw-wiki-title', + ], + $siteTitle + ); + break; + } + + return $html; + } + + /** + * Generates the description for footer + * @return string html + */ + protected function getFooterDesc() { + $html = ''; + $language = $this->getSkin()->getLanguage(); + $siteDesc = $language->convert( $this->getMsg( 'citizen-footer-desc' )->escaped() ); + + $html .= Html::rawElement( + 'span', + [ + 'id' => 'mw-footer-desc' + ], + $siteDesc + ); + + return $html; + } + + /** + * Generates the tagline for footer + * @return string html + */ + protected function getFooterTagline() { + $html = ''; + $language = $this->getSkin()->getLanguage(); + $siteTagline = $language->convert( $this->getMsg( 'citizen-footer-tagline' )->escaped() ); + + $html .= Html::rawElement( + 'span', + [ + 'id' => 'mw-footer-tagline' + ], + $siteTagline + ); + + return $html; + } + + /** + * Generates the logo + * @param string $id + * + * @return string html + */ + protected function getLogo( $id = 'p-logo' ) { + $html = Html::openElement( + 'div', + [ + 'id' => $id, + 'class' => 'mw-portlet', + 'role' => 'banner' + ] + ); + $html .= Html::element( + 'a', + [ + 'href' => $this->data['nav_urls']['mainpage']['href'], + 'class' => 'mw-wiki-logo', + ] + Linker::tooltipAndAccesskeyAttribs( 'p-logo' ) + ); + $html .= Html::closeElement( 'div' ); + + return $html; + } + + /** + * Generates the search form + * @return string html + */ + protected function getSearch() { + $html = Html::openElement( + 'form', + [ + 'action' => $this->get( 'wgScript' ), + 'role' => 'search', + 'class' => 'mw-portlet', + 'id' => 'p-search' + ] + ); + $html .= Html::hidden( 'title', $this->get( 'searchtitle' ) ); + $html .= Html::rawElement( + 'h3', + [], + Html::label( $this->getMsg( 'search' )->text(), 'searchInput' ) + ); + $html .= $this->makeSearchInput( [ 'id' => 'searchInput' ] ); + $html .= $this->makeSearchButton( 'go', [ 'id' => 'searchGoButton', 'class' => 'searchButton' ] ); + $html .= Html::closeElement( 'form' ); + + return $html; + } + + /** + * Generates the sidebar + * Set the elements to true to allow them to be part of the sidebar + * Or get rid of this entirely, and take the specific bits to use wherever you actually want them + * * Toolbox is the page/site tools that appears under the sidebar in vector + * * Languages is the interlanguage links on the page via en:... es:... etc + * * Default is each user-specified box as defined on MediaWiki:Sidebar; you will still need a foreach loop + * to parse these. + * @return string html + */ + protected function getSiteNavigation() { + $html = ''; + + $sidebar = $this->getSidebar(); + $sidebar['SEARCH'] = false; + $sidebar['TOOLBOX'] = true; + $sidebar['LANGUAGES'] = false; + + foreach ( $sidebar as $name => $content ) { + if ( $content === false ) { + continue; + } + // Numeric strings gets an integer when set as key, cast back - T73639 + $name = (string)$name; + + switch ( $name ) { + case 'SEARCH': + $html .= $this->getSearch(); + break; + case 'TOOLBOX': + $html .= $this->getPortlet( 'tb', $this->getToolbox(), 'toolbox' ); + break; + case 'LANGUAGES': + $html .= $this->getLanguageLinks(); + break; + default: + $html .= $this->getPortlet( $name, $content['content'] ); + break; + } + } + return $html; + } + /** + * Generates user icon bar + * @return string html + */ + protected function getUserIcons() { + + $personalTools = $this->getPersonalTools(); + $html = ''; + + // Create the Echo badges and ULS + $extraTools = []; + if ( isset( $personalTools['notifications-alert'] ) ) { + $extraTools['notifications-alert'] = $personalTools['notifications-alert']; + } + if ( isset( $personalTools['notifications-notice'] ) ) { + $extraTools['notifications-notice'] = $personalTools['notifications-notice']; + } + if ( isset( $personalTools['uls'] ) ) { + $extraTools['uls'] = $personalTools['uls']; + } + + // Place the extra icons/outside stuff + if ( !empty( $extraTools ) ) { + $iconList = ''; + foreach ( $extraTools as $key => $item ) { + $iconList .= $this->makeListItem( $key, $item ); + } + + $html .= Html::rawElement( + 'div', + [ 'id' => 'p-personal-extra', 'class' => 'p-body' ], + Html::rawElement( 'ul', [], $iconList ) + ); + } + return $html; + } + + /** + * Generates user tools menu + * @return string html + */ + protected function getUserLinks() { + + $personalTools = $this->getPersonalTools(); + + $html = ''; + + // Move the Echo badges and ULS out of default list + $extraTools = []; + if ( isset( $personalTools['notifications-alert'] ) ) { + unset( $personalTools['notifications-alert'] ); + } + if ( isset( $personalTools['notifications-notice'] ) ) { + unset( $personalTools['notifications-notice'] ); + } + if ( isset( $personalTools['uls'] ) ) { + unset( $personalTools['uls'] ); + } + + $html .= Html::openElement( 'div', [ 'id' => 'mw-user-links' ] ); + $html .= $this->getPortlet( 'personal', $personalTools, 'personaltools' ); + $html .= Html::closeElement( 'div' ); + + return $html; + } + + /** + * In other languages list + * + * @return string html + */ + protected function getLanguageLinks() { + $html = ''; + if ( $this->data['language_urls'] !== false ) { + $html .= $this->getPortlet( 'lang', $this->data['language_urls'], 'otherlanguages' ); + } + + return $html; + } + + /** + * Language variants. Displays list for converting between different scripts in the same language, + * if using a language where this is applicable (such as latin vs cyric display for serbian). + * + * @return string html + */ + protected function getVariants() { + $html = ''; + if ( count( $this->data['content_navigation']['variants'] ) > 0 ) { + $html .= $this->getPortlet( + 'variants', + $this->data['content_navigation']['variants'] + ); + } + + return $html; + } + + /** + * Generates page-related tools + * @return string html + */ + protected function getPageTools() { + $html = ''; + // Only display if user is logged in + // TODO: Make it check for EDIT permission instead + if ( $this->getSkin()->getUser()->isLoggedIn() ) { + + $html .= Html::openElement( 'div', [ 'class' => 'mw-side', 'id' => 'page-tools' ]); + // 'View' actions for the page: view, edit, view history, etc + $html .= $this->getPortlet( + 'views', + $this->data['content_navigation']['views'] + ); + // Other actions for the page: move, delete, protect, everything else + $html .= $this->getPortlet( + 'actions', + $this->data['content_navigation']['actions'] + ); + $html .= Html::closeElement( 'div' ); + } + return $html; + } + + /** + * Generates page-related links at the bottom + * @return string html + */ + protected function getPageLinks() { + // Namespaces: links for 'content' and 'talk' for namespaces with talkpages. Otherwise is just the content. + // Usually rendered as tabs on the top of the page. + $html = $this->getPortlet( + 'namespaces', + $this->data['content_navigation']['namespaces'] + ); + // Language variant options + $html .= $this->getVariants(); + + return $html; + } + + /** + * Generates siteNotice, if any + * @return string html + */ + protected function getSiteNotice() { + return $this->getIfExists( 'sitenotice', [ + 'wrapper' => 'div', + 'parameters' => [ 'id' => 'siteNotice' ] + ] ); + } + + /** + * Generates new talk message banner, if any + * @return string html + */ + protected function getNewTalk() { + return $this->getIfExists( 'newtalk', [ + 'wrapper' => 'div', + 'parameters' => [ 'class' => 'usermessage' ] + ] ); + } + + /** + * Generates subtitle stuff, if any + * @return string html + */ + protected function getPageSubtitle() { + return $this->getIfExists( 'subtitle', [ 'wrapper' => 'p' ] ); + } + + /** + * Generates category links, if any + * @return string html + */ + protected function getCategoryLinks() { + return $this->getIfExists( 'catlinks' ); + } + + /** + * Generates data after content stuff, if any + * @return string html + */ + protected function getDataAfterContent() { + return $this->getIfExists( 'dataAfterContent' ); + } + + /** + * Simple wrapper for random if-statement-wrapped $this->data things + * + * @param string $object name of thing + * @param array $setOptions + * + * @return string html + */ + protected function getIfExists( $object, $setOptions = [] ) { + $options = $setOptions + [ + 'wrapper' => 'none', + 'parameters' => [] + ]; + + $html = ''; + + if ( $this->data[$object] ) { + if ( $options['wrapper'] == 'none' ) { + $html .= $this->get( $object ); + } else { + $html .= Html::rawElement( + $options['wrapper'], + $options['parameters'], + $this->get( $object ) + ); + } + } + + return $html; + } + + /** + * Generates a block of navigation links with a header + * + * @param string $name + * @param array|string $content array of links for use with makeListItem, or a block of text + * @param null|string|array $msg + * @param array $setOptions random crap to rename/do/whatever + * + * @return string html + */ + protected function getPortlet( $name, $content, $msg = null, $setOptions = [] ) { + // random stuff to override with any provided options + $options = $setOptions + [ + // extra classes/ids + 'id' => 'p-' . $name, + 'class' => 'mw-portlet', + 'extra-classes' => '', + // what to wrap the body list in, if anything + 'body-wrapper' => 'nav', + 'body-id' => null, + 'body-class' => 'mw-portlet-body', + // makeListItem options + 'list-item' => [ 'text-wrapper' => [ 'tag' => 'span' ] ], + // option to stick arbitrary stuff at the beginning of the ul + 'list-prepend' => '', + // old toolbox hook support (use: [ 'SkinTemplateToolboxEnd' => [ &$skin, true ] ]) + 'hooks' => '' + ]; + + // Handle the different $msg possibilities + if ( $msg === null ) { + $msg = $name; + } elseif ( is_array( $msg ) ) { + $msgString = array_shift( $msg ); + $msgParams = $msg; + $msg = $msgString; + } + $msgObj = $this->getMsg( $msg ); + if ( $msgObj->exists() ) { + if ( isset( $msgParams ) && !empty( $msgParams ) ) { + $msgString = $this->getMsg( $msg, $msgParams )->parse(); + } else { + $msgString = $msgObj->parse(); + } + } else { + $msgString = htmlspecialchars( $msg ); + } + + $labelId = Sanitizer::escapeIdForAttribute( "p-$name-label" ); + + if ( is_array( $content ) ) { + $contentText = Html::openElement( 'ul', + [ 'lang' => $this->get( 'userlang' ), 'dir' => $this->get( 'dir' ) ] + ); + $contentText .= $options['list-prepend']; + foreach ( $content as $key => $item ) { + $contentText .= $this->makeListItem( $key, $item, $options['list-item'] ); + } + // Compatibility with extensions still using SkinTemplateToolboxEnd or similar + if ( is_array( $options['hooks'] ) ) { + foreach ( $options['hooks'] as $hook ) { + if ( is_string( $hook ) ) { + $hookOptions = []; + } else { + // it should only be an array otherwise + $hookOptions = array_values( $hook )[0]; + $hook = array_keys( $hook )[0]; + } + $contentText .= $this->deprecatedHookHack( $hook, $hookOptions ); + } + } + + $contentText .= Html::closeElement( 'ul' ); + } else { + $contentText = $content; + } + + // Special handling for role=search and other weird things + $divOptions = [ + 'role' => 'navigation', + 'id' => Sanitizer::escapeIdForAttribute( $options['id'] ), + 'title' => Linker::titleAttrib( $options['id'] ), + 'aria-labelledby' => $labelId + ]; + if ( !is_array( $options['class'] ) ) { + $class = [ $options['class'] ]; + } + if ( !is_array( $options['extra-classes'] ) ) { + $extraClasses = [ $options['extra-classes'] ]; + } + $divOptions['class'] = array_merge( $class, $extraClasses ); + + $labelOptions = [ + 'id' => $labelId, + 'lang' => $this->get( 'userlang' ), + 'dir' => $this->get( 'dir' ) + ]; + + if ( $options['body-wrapper'] !== 'none' ) { + $bodyDivOptions = [ 'class' => $options['body-class'] ]; + if ( is_string( $options['body-id'] ) ) { + $bodyDivOptions['id'] = $options['body-id']; + } + $body = Html::rawElement( $options['body-wrapper'], $bodyDivOptions, + $contentText . + $this->getAfterPortlet( $name ) + ); + } else { + $body = $contentText . $this->getAfterPortlet( $name ); + } + + $html = Html::rawElement( 'div', $divOptions, + Html::rawElement( 'h3', $labelOptions, $msgString ) . + $body + ); + + return $html; + } + + /** + * Wrapper to catch output of old hooks expecting to write directly to page + * We no longer do things that way. + * + * @param string $hook event + * @param array $hookOptions args + * + * @return string html + */ + protected function deprecatedHookHack( $hook, $hookOptions = [] ) { + $hookContents = ''; + ob_start(); + Hooks::run( $hook, $hookOptions ); + $hookContents = ob_get_contents(); + ob_end_clean(); + if ( !trim( $hookContents ) ) { + $hookContents = ''; + } + + return $hookContents; + } + + /** + * Better renderer for getFooterIcons and getFooterLinks, based on Vector + * + * @param array $setOptions Miscellaneous other options + * * 'id' for footer id + * * 'order' to determine whether icons or links appear first: 'iconsfirst' or links, though in + * practice we currently only check if it is or isn't 'iconsfirst' + * * 'link-prefix' to set the prefix for all link and block ids; most skins use 'f' or 'footer', + * as in id='f-whatever' vs id='footer-whatever' + * * 'icon-style' to pass to getFooterIcons: "icononly", "nocopyright" + * * 'link-style' to pass to getFooterLinks: "flat" to disable categorisation of links in a + * nested array + * + * @return string html + */ + protected function getFooterBlock( $setOptions = [] ) { + // Set options and fill in defaults + $options = $setOptions + [ + 'id' => 'footer', + 'order' => 'linksfirst', + 'link-prefix' => 'footer', + 'icon-style' => 'icononly', + 'link-style' => 'flat' + ]; + + $validFooterIcons = $this->getFooterIcons( $options['icon-style'] ); + $validFooterLinks = $this->getFooterLinks( $options['link-style'] ); + $html = ''; + + $html .= Html::openElement( 'footer', [ + 'id' => $options['id'], + 'role' => 'contentinfo', + 'lang' => $this->get( 'userlang' ), + 'dir' => $this->get( 'dir' ) + ] ); + + $iconsHTML = ''; + if ( count( $validFooterIcons ) > 0 ) { + $iconsHTML .= Html::openElement( 'div', [ 'id' => "{$options['link-prefix']}-container-icons"] ); + $iconsHTML .= Html::openElement( 'div', [ 'id' => "footer-bottom-container"] ); + + // Get tagline + $iconsHTML .= $this -> getFooterTagline(); + + $iconsHTML .= Html::openElement( 'ul', [ 'id' => "{$options['link-prefix']}-icons" ] ); + foreach ( $validFooterIcons as $blockName => $footerIcons ) { + $iconsHTML .= Html::openElement( 'li', [ + 'id' => Sanitizer::escapeIdForAttribute( + "{$options['link-prefix']}-{$blockName}ico" + ), + 'class' => 'footer-icons' + ] ); + foreach ( $footerIcons as $icon ) { + $iconsHTML .= $this->getSkin()->makeFooterIcon( $icon ); + } + $iconsHTML .= Html::closeElement( 'li' ); + } + $iconsHTML .= Html::closeElement( 'ul' ); + $iconsHTML .= Html::closeElement( 'div' ); + $iconsHTML .= Html::closeElement( 'div' ); + } + + $linksHTML = ''; + if ( count( $validFooterLinks ) > 0 ) { + $linksHTML .= Html::openElement( 'div', [ 'id' => "{$options['link-prefix']}-container-list" ] ); + if ( $options['link-style'] == 'flat' ) { + $linksHTML .= Html::openElement( 'ul', [ + 'id' => "{$options['link-prefix']}-list", + 'class' => 'footer-places' + ] ); + + // Site logo + $linksHTML .= Html::rawElement( 'li', [ 'id' => 'sitelogo' ], + $this->getLogo() + ); + // Site title + $linksHTML .= Html::rawElement( 'li', [ 'id' => 'sitetitle' ], + $this->getSiteTitle('text') + ); + // Site description + $linksHTML .= Html::rawElement( 'li', [ 'id' => 'sitedesc' ], + $this->getFooterDesc() + ); + + foreach ( $validFooterLinks as $link ) { + $linksHTML .= Html::rawElement( + 'li', + [ 'id' => Sanitizer::escapeIdForAttribute( $link ) ], + $this->get( $link ) + ); + } + $linksHTML .= Html::closeElement( 'ul' ); + } else { + $linksHTML .= Html::openElement( 'div', [ 'id' => "{$options['link-prefix']}-list" ] ); + foreach ( $validFooterLinks as $category => $links ) { + $linksHTML .= Html::openElement( 'ul', + [ 'id' => Sanitizer::escapeIdForAttribute( + "{$options['link-prefix']}-{$category}" + ) ] + ); + foreach ( $links as $link ) { + $linksHTML .= Html::rawElement( + 'li', + [ 'id' => Sanitizer::escapeIdForAttribute( + "{$options['link-prefix']}-{$category}-{$link}" + ) ], + $this->get( $link ) + ); + } + $linksHTML .= Html::closeElement( 'ul' ); + } + // Site title + $linksHTML .= Html::rawElement( 'li', [ 'id' => 'footer-sitetitle' ], + $this->getSiteTitle('text') + ); + // Site logo + $linksHTML .= Html::rawElement( 'li', [ 'id' => 'footer-sitelogo' ], + $this->getLogo() + ); + $linksHTML .= Html::closeElement( 'div' ); + } + $linksHTML .= Html::closeElement( 'div' ); + } + + if ( $options['order'] == 'iconsfirst' ) { + $html .= $iconsHTML . $linksHTML; + } else { + $html .= $linksHTML . $iconsHTML; + } + + $html .= $this->getClear() . Html::closeElement( 'footer' ); + + return $html; + } +} diff --git a/includes/SkinCitizen.php b/includes/SkinCitizen.php new file mode 100644 index 00000000..e2aaa02f --- /dev/null +++ b/includes/SkinCitizen.php @@ -0,0 +1,52 @@ +addMeta( 'viewport', + 'width=device-width, initial-scale=1' + ); + // Edge compatibility + $out->addMeta( 'http:X-UA-Compatible', + 'IE=edge' + ); + + $out->addModuleStyles( [ + 'mediawiki.skinning.content.externallinks', + 'skins.citizen', + 'skins.citizen.icons', + 'skins.citizen.icons.ca', + 'skins.citizen.icons.p', + 'skins.citizen.icons.toc', + 'skins.citizen.icons.es', + 'skins.citizen.icons.n', + 'skins.citizen.icons.t', + 'skins.citizen.icons.pt', + 'skins.citizen.icons.footer', + 'skins.citizen.icons.badges' + ] ); + $out->addModules( [ + 'skins.citizen.js' + ] ); + } + + /** + * @param $out OutputPage + */ + function setupSkinUserCss( OutputPage $out ) { + parent::setupSkinUserCss( $out ); + } +} diff --git a/licenses/Lato OFL.txt b/licenses/Lato OFL.txt new file mode 100644 index 00000000..98383e3d --- /dev/null +++ b/licenses/Lato OFL.txt @@ -0,0 +1,93 @@ +Copyright (c) 2010-2014 by tyPoland Lukasz Dziedzic (team@latofonts.com) with Reserved Font Name "Lato" + +This Font Software is licensed under the SIL Open Font License, Version 1.1. +This license is copied below, and is also available with a FAQ at: +http://scripts.sil.org/OFL + + +----------------------------------------------------------- +SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007 +----------------------------------------------------------- + +PREAMBLE +The goals of the Open Font License (OFL) are to stimulate worldwide +development of collaborative font projects, to support the font creation +efforts of academic and linguistic communities, and to provide a free and +open framework in which fonts may be shared and improved in partnership +with others. + +The OFL allows the licensed fonts to be used, studied, modified and +redistributed freely as long as they are not sold by themselves. The +fonts, including any derivative works, can be bundled, embedded, +redistributed and/or sold with any software provided that any reserved +names are not used by derivative works. The fonts and derivatives, +however, cannot be released under any other type of license. The +requirement for fonts to remain under this license does not apply +to any document created using the fonts or their derivatives. + +DEFINITIONS +"Font Software" refers to the set of files released by the Copyright +Holder(s) under this license and clearly marked as such. This may +include source files, build scripts and documentation. + +"Reserved Font Name" refers to any names specified as such after the +copyright statement(s). + +"Original Version" refers to the collection of Font Software components as +distributed by the Copyright Holder(s). + +"Modified Version" refers to any derivative made by adding to, deleting, +or substituting -- in part or in whole -- any of the components of the +Original Version, by changing formats or by porting the Font Software to a +new environment. + +"Author" refers to any designer, engineer, programmer, technical +writer or other person who contributed to the Font Software. + +PERMISSION & CONDITIONS +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: + +1) Neither the Font Software nor any of its individual components, +in Original or Modified Versions, may be sold by itself. + +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. + +3) No Modified Version of the Font Software may use the Reserved Font +Name(s) unless explicit written permission is granted by the corresponding +Copyright Holder. This restriction only applies to the primary font name as +presented to the users. + +4) The name(s) of the Copyright Holder(s) 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 the +Copyright Holder(s) and the Author(s) or with their explicit written +permission. + +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. + +TERMINATION +This license becomes null and void if any of the above conditions are +not met. + +DISCLAIMER +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 THE +COPYRIGHT HOLDER 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. diff --git a/licenses/Titillium Web OFL.txt b/licenses/Titillium Web OFL.txt new file mode 100644 index 00000000..bbaa23a6 --- /dev/null +++ b/licenses/Titillium Web OFL.txt @@ -0,0 +1,93 @@ +Copyright (c) 2009-2011 by Accademia di Belle Arti di Urbino and students of MA course of Visual design. Some rights reserved. + +This Font Software is licensed under the SIL Open Font License, Version 1.1. +This license is copied below, and is also available with a FAQ at: +http://scripts.sil.org/OFL + + +----------------------------------------------------------- +SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007 +----------------------------------------------------------- + +PREAMBLE +The goals of the Open Font License (OFL) are to stimulate worldwide +development of collaborative font projects, to support the font creation +efforts of academic and linguistic communities, and to provide a free and +open framework in which fonts may be shared and improved in partnership +with others. + +The OFL allows the licensed fonts to be used, studied, modified and +redistributed freely as long as they are not sold by themselves. The +fonts, including any derivative works, can be bundled, embedded, +redistributed and/or sold with any software provided that any reserved +names are not used by derivative works. The fonts and derivatives, +however, cannot be released under any other type of license. The +requirement for fonts to remain under this license does not apply +to any document created using the fonts or their derivatives. + +DEFINITIONS +"Font Software" refers to the set of files released by the Copyright +Holder(s) under this license and clearly marked as such. This may +include source files, build scripts and documentation. + +"Reserved Font Name" refers to any names specified as such after the +copyright statement(s). + +"Original Version" refers to the collection of Font Software components as +distributed by the Copyright Holder(s). + +"Modified Version" refers to any derivative made by adding to, deleting, +or substituting -- in part or in whole -- any of the components of the +Original Version, by changing formats or by porting the Font Software to a +new environment. + +"Author" refers to any designer, engineer, programmer, technical +writer or other person who contributed to the Font Software. + +PERMISSION & CONDITIONS +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: + +1) Neither the Font Software nor any of its individual components, +in Original or Modified Versions, may be sold by itself. + +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. + +3) No Modified Version of the Font Software may use the Reserved Font +Name(s) unless explicit written permission is granted by the corresponding +Copyright Holder. This restriction only applies to the primary font name as +presented to the users. + +4) The name(s) of the Copyright Holder(s) 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 the +Copyright Holder(s) and the Author(s) or with their explicit written +permission. + +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. + +TERMINATION +This license becomes null and void if any of the above conditions are +not met. + +DISCLAIMER +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 THE +COPYRIGHT HOLDER 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. diff --git a/resources/components/bottombar.less b/resources/components/bottombar.less new file mode 100644 index 00000000..57eb9529 --- /dev/null +++ b/resources/components/bottombar.less @@ -0,0 +1,52 @@ +// +// Citizen - Bottombar Styles +// https://starcitizen.tools +// + +#mw-bottombar { + position: fixed; + bottom: 0; + display: flex; + justify-content: space-between; + transform: translate(0px, @header-height + @margin-side); + transition: @transition-transform; + + &-contact { + display: flex; + margin: @margin-side; + padding: 0 @margin-side / 2; + background-color: #7289da; // Discord color + border-radius: 100%; + .boxshadow(4); + transition: @transition-transform-quick, @transition-box-shadow-quick; + + .citizen-ui-icon { + > a { + width: @icon-box-size + @icon-padding; + height: @header-height; + display: flex; + align-items: center; + justify-content: center; + text-indent: -1000px; // Hide text + + &:after { + display: block; + .resource-loader-menu-icon; + transition: @transition-opacity; + opacity: 1; + } + + &:hover { + &:after { + opacity: 0.7; + } + } + } + } + } +} + +// Movable navigation bar +.nav-up ~ #mw-bottombar { + transform: none; +} diff --git a/resources/components/common.less b/resources/components/common.less new file mode 100644 index 00000000..0f651b66 --- /dev/null +++ b/resources/components/common.less @@ -0,0 +1,667 @@ +/* + * Citizen - Common Styles + * https://starcitizen.tools +*/ + +@import 'mediawiki.mixins'; + +/* + * Framework +*/ + +html { + font-size: @html-font-size; + scroll-padding-top: @header-height + @margin-side; // fixed header offset, supported by major browsers + scroll-behavior: smooth; // not supported by IE, Edge, Safari, and Opera, use JQuery as fallback +} + +html, +body { + height: 100%; + margin: 0; + padding: 0; + font-family: @fonts; + // font-smoothing: antialiased; + // -webkit-font-smoothing: antialiased; /* Chrome, Safari */ + // -moz-osx-font-smoothing: grayscale; /* Firefox */ + +} + +ul { + list-style-type: square; +} + +ol { + list-style-type: none; +} + +ul, ol { + padding: 0; +} + +p, ul, ol { + margin: 0.8rem 0 0 0; +} + +pre, code, tt, kbd, samp, .mw-code { + font-family: @fonts-monospace; + font-size: @content-monospace-size; +} + +pre, +code, +.mw-code { + color: @base-0; + background-color: @base-90; + border: 1px solid @base-80; +} + +code { + padding: 1px 4px; +} + +pre, +.mw-code { + padding: 1rem; + /* Wrap lines in overflow. T2260, T103780 */ + white-space: pre-wrap; +} + +td { + > p, + > ul, + > ol { + &:first-child { + margin-top: 0; // Remove margin for the first element in td + } + } +} + +a { + color: @color-link; + text-decoration: none!important; + + &:not( [ href ] ) { + cursor: pointer; /* Always cursor:pointer even without href */ + } + + &:hover { + color: @color-link-active; + } + + &.new { + color: @color-link-new!important; // Override visited + + &:hover { + color: @color-link-new-active!important; + } + } + + &:visited { + color: @color-link; + + &:hover { + color: @color-link-active; + } + } +} + +.error { + padding: 2px 4px; + background-color: @red-90; + font-size: unset; + font-weight: 400; +} + +.firstHeading { + padding-top: 1.2rem; + line-height: 1.2; +} + +/* + * Content +*/ + +.mw-body, +.parsoid-body { + margin-top: @header-height + @margin-side; + padding: 0 @margin-side; + min-height: 60vh; // avoid footer being in the middle of the page + direction: ltr; +} + +.mw-wiki-title { + font-family: @fonts-secondary!important; + text-transform: uppercase; + + a& { + color: @base-50; + transition: @transition-opacity; + + &:hover, + &:active, + &:focus { + color: @base-30; + text-decoration: none; + } + } +} + +.mw-body { + // h1's can exist outside of mw-body-content so some heading styles + // need to be defined in mw-body as well + & h1, + &-content h1, + &-content h2, + &-content h3, + &-content h4 { + font-family: @fonts-secondary; + } + + & h1, + &-content h1 { + font-size: @content-h1-size; + } + + .firstHeading { + margin: 0; + font-weight: 600; + overflow: inherit; // black magic to wrap in small screen devices + } + + #siteSub { + display: block; + margin: .4rem 0 1.6rem; + color: @base-30; + font-size: @content-caption-size; + } + + .mw-indicators { + float: right; + line-height: @content-line-height; + font-size: @content-body-size; + /* Ensure that this is displayed on top of .mw-body-content and clickable */ + position: relative; + z-index: 1; + } + + .mw-indicator { + display: inline-block; + zoom: 1; + *display: inline; // stylelint-disable declaration-block-no-duplicate-properties + } + + .firstHeading, + #siteSub { + .content-center; + } +} + +.mw-body-content { + position: relative; + .content-center; + line-height: @content-line-height; + font-size: @content-body-size; + z-index: 0; + color: @color-content-text; + + #mw-content-text { + + .mw-parser-output { + + .mw-headline { + order: -1; // Make sure that header is the first + } + + p { + overflow-wrap: break-word; + } + + &>h1, &>h2 { + margin-top: @content-margin-top * 3; + } + + &>h3, &>h4, &>h5, &>h6, &>p+p { + margin-top: @content-margin-top * 2; + } + + &>h1+h2, &>h2+h3, &>h3+h4, &>h4+h5, &>h5+h6, &>p, &>table { + margin-top: @content-margin-top; + } + + &>h1, &>h2, &>h3, &>h4, &>h5, &>h6 { + display: flex; + align-items: center; + justify-content: space-between; + } + + a:not(.external) { + .link-content-text(@color-link-active); + + &.new { + background-image: linear-gradient(to right, @color-link-new-active 0, @color-link-new-active 100%); + } + + /* Doesn't work for some reason + &:visited { + background-image: linear-gradient(to right, @color-link-visited 0, @color-link-visited 100%)!important; + } + */ + } + + .mw-editsection { + position: absolute; + display: flex; + margin: 0; + left: 0; + transform: ~'translateX(calc(-100% - @{margin-side}))'; + + a { + .resource-loader-icon-link-small; + padding: @margin-side / 4; + opacity: @opacity-icon; + transition: @transition-opacity; + text-indent: -9999px; // Hide text + background: 0!important; // Cancel above styles + + &:before { + .resource-loader-icon; + background-size: contain; + display: block; + } + + &:hover, + &:active, + &:focus { + opacity: @opacity-icon-active; + } + } + + > span { + display: none; + } + } + + .toc { + position: fixed; + max-width: 450px; + height: ~'calc( 100vh - @{header-height} * 2 - @{margin-side} * 4 )'; + top: @header-height; + right: 0; + padding: @margin-side * 2 @margin-side; + color: #cccccc; + overflow: auto; + + &::-webkit-scrollbar { + width: 0; // Hide bar on toc + } + + @top: linear-gradient(white, rgba(255, 255, 255, 0.001)); + @bottom: linear-gradient(rgba(255, 255, 255, 0.001), white); + + &:before { + top: @header-height; + .gradient-overflow(@top); + } + + &:after { + bottom: @header-height; + .gradient-overflow(@bottom); + } + + .toctitle { + h2 { + color: @base-50; + font-size: @ui-menu-text-big; + } + } + + .toctoggle { + display: none; + } + + .toctext { + max-width: 250px; + display: flex; + } + + a { + display: inline-block; + margin-top: @content-margin-top; + color: @base-50; + background: 0; + + &:hover { + color: @base-30!important; + } + } + + &level { + + &-1 { + font-size: @content-h2-size * @toc-scaling; + } + + &-2 { + font-size: @content-h3-size * @toc-scaling; + } + + &-3 { + font-size: @content-h4-size * @toc-scaling; + } + + &-4 { + font-size: @content-h5-size * @toc-scaling; + } + + &-5 { + font-size: @content-h6-size * @toc-scaling; + } + } + .tocnumber { + .mixin-screen-reader-text; + } + + &.tochidden { + > ul { + display: block!important; // Force display + } + } + + > ul { + direction: rtl; // Hack to force right alignment, need to fix for RTL + margin: @content-margin-top / 2 3px 0 0; + position: relative; + z-index: 2; + border-right: 1px dashed; + display: block; + + > li { + margin-right: -3px; + } + } + + ul { + list-style-type: disc; + list-style-position: inside; + } + + ul, .toctitle { + text-align: right; + } + } + } + } + + p { + line-height: inherit; + } + + h2 { + font-size: @content-h2-size; + } + + h3 { + font-size: @content-h3-size; + } + + h4 { + font-size: @content-h4-size; + } + + h5 { + font-size: @content-h5-size; + } + + h6 { + font-size: @content-h6-size; + } + + table { + margin: 0; + } + + h1, h2, h3, h4, h5, h6 { + margin: 0; + padding: 0; + color: @color-content-header; + font-weight: 400; + } + + h5, h6 { + font-weight: 600; + } + + ul { + margin: 0.8rem 0 0 1.6rem; + } +} + +// Namespace button +#p-namespaces { + margin: 0 @negative-margin; + padding: @margin-side; + + &-label { + .mixin-screen-reader-text; + } + + ul{ + margin: 1.6rem 0 0 0; + display: flex; + justify-content: flex-end; // Right align + + li { + list-style: none; + + a { + display: flex; + align-items: center; + padding: 0.4rem 0.8rem; + border: 1px solid @base-80; + background-color: @base-90; + transition: @transition-background-quick, @transition-box-shadow-quick; + .boxshadow(1); + + &:hover { + background-color: @base-80; + .boxshadow(2); + } + + span { + color: @base-20; + } + + &:after { + order: -1; + content: ""; + position: relative; + width: 14px; + height: 14px; + margin-right: 8px; + background-size: contain; + background-repeat: no-repeat; + background-position: center; + opacity: 0.5; + } + } + } + } +} + +.catlinks { + margin: 0 @negative-margin; + padding: @margin-side; + line-height: 1.2; + + .mw-normal-catlinks { + font-size: 0; // Hide colon + + > a { + display: block; + color: @color-content-caption; + font-size: @content-caption-size; + text-transform: uppercase; + letter-spacing: 1px; + } + + > ul { + margin: 0; + padding-top: @content-margin-top; + display: flex; + flex-wrap: wrap; + font-size: @content-caption-size; // Reset font + + li { + display: block; + margin: 0 @margin-side / 2 @margin-side / 2 0; + padding: 0; + border: 0; + + &:first-of-type { + margin-left: 0; + } + + a { + padding: @margin-side / 4 @margin-side / 2; + display: block; + border: 1px solid @base-90; + background-color: @base-90; + color: @color-content-caption!important; // Override other styles + .boxshadow(1); + transition: @transition-background-quick, + @transition-color-quick, + @transition-border-quick, + @transition-box-shadow-quick; + + &:hover { + background-color: @color-link-active; + border-color: @color-link-active; + color:@base-100!important; + .boxshadow(2); + } + &.new:hover { + background-color: @color-link-new-active; + border-color: @color-link-new-active; + } + } + } + } + } +} + +// TODO: Flexible value +@screen1: @page-width + @margin-side * 2; +@screen2: @footer-width; +@screen3: @footer-width + @margin-side * 8; + +@media only screen and (max-width: @screen1) { + .catlinks, + #p-namespaces { + margin: 0!important; // somehow got overrided + padding: @margin-side 0; + } +} + +@media only screen and (max-width: @screen2) { + .mw-editsection { + position: relative!important; + transform: none!important; + } + + .catlinks, + #p-namespaces { + margin: 0 ~"calc((100vw - @{page-width}) / -2)"; + } +} + +@media only screen and (max-width: @screen3) { + .webfonts-changed .toc { + display: block!important; // Hide until everything is loaded + } + + .mw-body-content #mw-content-text .mw-parser-output .toc { + + display: none; + background: @base-100; + z-index: 1; + height: 100vh; + margin-top: -@header-height; + padding: 0; + .boxshadow(3); + + &:before, + &:after { + content: unset; // Disable fade + } + + .toctoggle { + display: block; + font-size: 0; + + a { + position: fixed; + z-index: 7; + right: 0; + bottom: 0; + margin: @margin-side; + padding: 0 @margin-side / 2; + width: 39px; + height: 56px; + display: block; + background-color: @base-90; + border-radius: 100%; + .boxshadow(4); + transform: translate(0px, @header-height + @margin-side); + transition: @transition-opacity, @transition-transform, @transition-box-shadow-quick; + + &:hover { + .boxshadow(5); + + &:before { + opacity: @opacity-icon-active; + } + } + + &:before { + .resource-loader-icon; + display: block; + opacity: @opacity-icon; + } + } + } + + .toctitle h2 { + display: none; + } + + &.tochidden { + > ul { + display: none!important; // Reset hide + transform: translateX(300px + @margin-side); + } + } + + > ul { + margin: 0 @margin-side; + padding: @header-height + @margin-side 0 @header-height + @margin-side * 2; // More scroll spaces + transform: none; + transition: @transition-transform; + } + } + + .nav-up { + ~ .mw-body .mw-body-content #mw-content-text .mw-parser-output .toc .toctoggle a { + transform: none; + } + } +} + +/* +// Logged in styles +.not-logged { + .mw-editsection { + display: none!important; // Hide edit icons when not logged in + } +} +*/ diff --git a/resources/components/footer.less b/resources/components/footer.less new file mode 100644 index 00000000..3bd5a0b1 --- /dev/null +++ b/resources/components/footer.less @@ -0,0 +1,219 @@ +// +// Citizen - Footer Styles +// https://starcitizen.tools +// + + +#footer { + z-index: 9; // High enough so it covers the floating UI + overflow: hidden; //stop background hacks from destroying viewbox + position: relative; + direction: ltr; + margin-top: @margin-side * 2; + color: @color-footer-text; + background: @color-footer-background-50; + font-size: @ui-menu-text; + line-height: @footer-line-height; + + a { + color: @color-footer-link; + + &:hover, + &:active, + &:focus { + color: @color-footer-link-active; + text-decoration: none; + } + } + + ul, li { + margin: 0; + } + + li { + list-style: none; + } + + div { + display: flex; + } + + // Bless Flexbox for saving me from PHP nightmare + // OPTIMIZE: Implement nightmare + &-list { + margin: 0 auto!important; + max-width: @footer-width; + display: flex; + flex-wrap: wrap; + + > li { + position: relative; + padding-left: @margin-side; + padding-right: @margin-side; + } + + #lastmod { + order: 1; + padding-top: 12px; + padding-bottom: 12px; + display: flex; + + a { + margin-right: 5px; + } + + // Change icon + &:before { + margin-right: @icon-padding; + .resource-loader-list-icon; + opacity: @opacity-icon; + } + + // Background + &:after { + content: ""; + background-color: @color-footer-background-60; + height: 100%; + width: 600vw; // so long so it is always there + top: 0; + margin: 0 -100vw; // so long so you can't see the end + display: block; + z-index: -1; + position: absolute; + overflow: hidden; // now you literally can't see the end + } + } + + #sitelogo { + order: 2; + } + + #sitetitle { + order: 3; + width: 100%; + margin-top: @margin-side * 3; + margin-bottom: @margin-side / 2; + + .mw-wiki-title { + color: @base-90; + font-size: 20px; + letter-spacing: 2px; + } + } + + #sitedesc { + order: 4; + margin-top: @margin-side / 2; + } + + #about { + order: 10; + } + + #privacy { + order: 11; + } + + #disclaimer { + order: 12; + } + + #about, + #privacy, + #disclaimer { + margin: 0 @margin-side / 2; + padding: 0; + + a { + padding: 10px; + display: block; + } + } + + #sitedesc, + #copyright { + margin-bottom: @margin-side / 2; + width: 100%; + } + + #copyright{ + margin-top: @margin-side; + order: 20; + opacity: 0.5; + font-size: 12px; + } + } + + &-container-icons { + margin-top: @margin-side * 2; + background-color: @color-footer-background-40; + + #footer-bottom-container { + margin: 0 auto; + padding: @margin-side / 2 0; + width: 100%; + max-width: @footer-width; + display: flex; + flex-wrap: wrap; + align-items: center; + justify-content: space-between; + + #mw-footer-tagline { + padding: 10px 20px; + } + + #footer-icons { + padding: 0 10px; + display: flex; + align-items: center; + flex-wrap: wrap; + + a { + padding: 15px 10px; + height: 50px; + display: block; + opacity: 0.5; + transition: @transition-opacity; + + &:before { + content:""; + .resource-loader-icon; + display: block; + background-size: contain; + } + + &:hover { + opacity: 0.7; + } + + + img { + display: none; // hide placeholder images + } + } + } + } + } + + // Icon styles + &-madebyico a { + width: 50px; + } + + &-gdprcomplianceico a { + width: 50px; + } + + &-monitoredbyico a { + width: 95px; + margin-bottom: -3px; //dirty fix + } + + &-poweredbyico a { + width: 95px; + } + + &-copyrightico a { + width: 110px; + } +} diff --git a/resources/components/navigation.less b/resources/components/navigation.less new file mode 100644 index 00000000..687be56b --- /dev/null +++ b/resources/components/navigation.less @@ -0,0 +1,347 @@ +/* + * Citizen - Navigation Styles + * https://starcitizen.tools +*/ + +/* + * Header +*/ + +.mw-header-container { + position: fixed; + z-index: 10; + top: 0; + width: 100vw; + height: @header-height; + display: flex; + justify-content: space-between; + font-family: @fonts-secondary; + transition: @transition-transform; + + ul { + list-style: none; + } + + ul, li { + margin: 0; + display: block; + } + + // Hide header when scroll + &.nav-up { + transform: translate(0px, -@header-height); + } + + .mw-header-icons { + display: inherit; + } + + .mw-header-end { + width: @icon-box-size + @margin-side + @icon-padding; + height: @header-height; + user-select: none; + + // Input button hack + > input { + width: inherit; + height: inherit; + position: absolute; + z-index: 8; + margin: 0; + display: block; + opacity: 0; + cursor: pointer; + -webkit-touch-callout: none; + } + } +} +/* + * Hamburger menu + * Modified from https://codepen.io/erikterwan/pen/EVzeRP and https://codepen.io/oxla/pen/zgvqmM + */ +#mw-header-menu { + + .mw-wiki-title { + letter-spacing: 2px; + } + + input { + &:checked { + + // Show drawer + ~ #mw-header-menu-drawer { + transform: none; + will-change: none; + } + + // Transform all the slices of hamburger into a crossmark + ~ #mw-header-menu-toggle > span { + opacity: @opacity-icon; + transform: rotate(45deg) translate(-5px, -7px); + + // Reflect line + &:nth-last-child(2) { + transform: rotate(-45deg) translate(-2px, 6px); + } + + // Hide line + &:nth-last-child(3) { + opacity: 0; + transform: rotate(0deg) scale(0.2, 0.2); + } + } + } + // Hover state + &:hover ~ #mw-header-menu-toggle > span { + opacity: @opacity-icon-active; + + &:first-child { + transform: translate(-50%,0); + } + } + } + + &-toggle { + width: @icon-size; + height: @icon-size; + margin: (@header-height - @icon-size) / 2 @icon-padding (@header-height - @icon-size) / 2 (@icon-margin * 2 + @margin-side * 2) / 2; + overflow: hidden; + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + + span { + z-index: 5; + margin: 1.5px 0; + width: @icon-size; + height: 2px; + display: block; + background: @base-0; + opacity: @opacity-icon; + transform-origin: 4px 0px; + transition: @transition-transform, + @transition-background-quick, + @transition-opacity; + + &:first-child { + transform-origin: 0% 0%; + } + &:nth-last-child(2) { + transform-origin: 0% 100%; + } + } + } + + &-drawer { + position: absolute; + z-index: 4; + top: 0; + padding-top: @header-height; + width: @drawer-width; + max-width: 100vw; // In case if someone has super small screen + height: 100vh; + .boxshadow(3); + background: @menu-background; + transform-origin: 0% 0%; + transform: translate(-110%, 0); // Shadow bleeding with 100% + transition: @transition-transform; + will-change: transform; // Help with performance + + &-container { + height: ~"calc(100vh - @{header-height})"; + display: flex; + flex-direction: column; + justify-content: space-between; + transition: @transition-height; + + .mw-wiki-title { + padding: @margin-side; + } + + #p-nt-container { + overflow: auto; + flex-grow: 1; + } + + #p-navigation-label { + .mixin-screen-reader-text; + } + + #mw-user-links { + + #p-personal { + margin-top: @margin-side / 2; + padding-top: @margin-side / 2; + border-top: 1px solid @base-80; + + h3 { + .mixin-screen-reader-text; + } + + #pt-userpage { + margin-bottom: @margin-side / 2; + + a { + justify-content: unset; + + &:after { + margin: 0; + width: @icon-box-size; + height: @icon-box-size; + } + } + + span { + order: 2; + padding-left: @margin-side; + } + } + + #pt-login { + a { + .button-blue; + + &:hover, + &:active, + &:focus { + .button-blue-active; + } + } + } + + #pt-logout { + a { + .button-red; + + &:hover, + &:active, + &:focus { + .button-red-active; + } + } + } + } + } + + h3 { + margin: @margin-side / 2 0 0 0; + padding: @margin-side / 2 @margin-side; + color: @color-item-header; + font-size: @ui-menu-header; + font-weight: normal; + letter-spacing: 1px; + } + + span { + display: block; + } + + a { + .menu-item-link; + align-items: center; + justify-content: space-between; + padding: @padding-menu-item-big; + font-size: @ui-menu-text-big; + font-family: @fonts; + + &:after { + .resource-loader-list-icon; + margin-left: @icon-padding; + opacity: 0.4; + display: block; + background-size: contain; + transition: @transition-opacity-quick; + } + + &:hover { + .menu-item-link-hover; + + &:after { + opacity: 0.6; + } + } + + &:active { + .menu-item-link-active; + } + + &:focus { + .menu-item-link-focus; + } + } + } + } +} + +// Sidebar site title +#mw-sidebar-sitename { + position: fixed; + visibility: visible; + top: @sidebar-sitename-height + @header-height + @margin-side; + left: @margin-side; + font-size: 11px; + letter-spacing: 4px; + transform: translateY(0) rotate(-90deg); + transform-origin: top left; + transition: @transition-transform, @transition-opacity; +} + +// Nav up stuff +.nav-up { + ~ #mw-sidebar-sitename { + transform: translateY(-54px) rotate(-90deg); + } + + #mw-header-menu-drawer-container { + height: 100vh; + } +} + +// Bypass calculation +@mw-sidebar-sitename-max-width: @margin-side * 5 + @page-width; + +@media only screen and (max-width: @mw-sidebar-sitename-max-width) { + #mw-sidebar-sitename { + z-index: -1; // remove link + opacity: 0; // hide visual + } +} + +/* + * User icon bar + */ +#p-personal-extra { + ul { + height: 56px; + display: flex; + align-items: center; + } +} + +/* + * Hide stuff + */ +#feedlinks, +#pt-anontalk, +#pt-anoncontribs { + display: none; +} + +// RTL tweaks +.rtl { + #mw-sidebar-sitename { + left: unset; + right: @margin-side; + transform: translateY(0) rotate(90deg); + transform-origin: top right; + } + + .nav-up ~ #mw-sidebar-sitename { + transform: translateY(-54px) rotate(90deg); + } + + #mw-header-menu-drawer { + transform: translate(100%, 0); + } +} diff --git a/resources/components/page-tools.less b/resources/components/page-tools.less new file mode 100644 index 00000000..cdd6f75a --- /dev/null +++ b/resources/components/page-tools.less @@ -0,0 +1,151 @@ +// +// Citizen - Page Tools Styles +// https://starcitizen.tools +// TODO: RTL styles and more flexible +// + +// Hide selected item +.mw-portlet li.selected { + .mixin-screen-reader-text; +} + +#page-tools { + z-index: 5; + position: absolute; + margin-top: 1.3rem; + display: flex; + transform: translateX(~"calc( (100vw - @{page-width}) / 2 - @{margin-side} * 2 - 100%)"); // magic + + h3 { + .mixin-screen-reader-text; + } + + ul { + margin: 0; + display: flex; + list-style: none; + } + + li { + margin: 0; + } + + #p-views { + li > a { + .resource-loader-icon-link; + padding: 5px; + opacity: @opacity-icon; + transition: @transition-opacity; + + &:hover { + opacity: @opacity-icon-active; + } + + &:after { + .resource-loader-icon; + } + + span { + .mixin-screen-reader-text; + } + } + } + + #p-actions { + > nav { + .resource-loader-icon-link; + padding: 5px; + cursor: pointer; + // transition: @transition-opacity-quick; - Hidden behind the menu anyways + + // TODO: Need to make value more flexible + ul { + z-index: -1; + pointer-events: none; + .menu-container; + position: absolute; + opacity: 0; + .boxshadow(4); + transition: @transition-opacity-quick, @transition-box-shadow-quick; + + a { + .menu-item-link; + justify-content: space-between; + font-size: @ui-menu-text; + padding: @padding-menu-item; + + &:after { + .resource-loader-list-icon; + margin-left: @icon-padding; + opacity: @opacity-icon; + } + + &:hover, + &:active, + &:focus { + &:after { + opacity: @opacity-icon-active; + } + } + + &:hover { + .menu-item-link-hover; + } + + &:active { + .menu-item-link-active; + } + + &:focus { + .menu-item-link-focus; + } + } + } + + &:before { + .resource-loader-menu-icon; + opacity: @opacity-icon; + } + +/* + * Hidden behind the menu anyways + * &:hover:after { + * opacity: @opacity-icon-active; + * } +*/ + + &:hover ul { + z-index: 5; + opacity: 1; + pointer-events: auto; + } + } + } +} + +// TODO: Flexible value +@media only screen and (max-width: 1250px) { + #page-tools { + position: relative; + margin-left: @margin-side / 2; + float: right; + transform: none; + + #p-actions > nav ul { + right: 0; + } + } +} + +@media only screen and (max-width: 500px) { + #page-tools { + position: relative; + margin-left: 0; + transform: none; + float: none; + + #p-actions > nav ul { + right: unset; + } + } +} diff --git a/resources/components/search.less b/resources/components/search.less new file mode 100644 index 00000000..d252483b --- /dev/null +++ b/resources/components/search.less @@ -0,0 +1,166 @@ +// +// Citizen - Search Styles +// https://starcitizen.tools +// + +// TODO: Make it configurable and flexible +#site-search { + + #p-search { + position: absolute; + z-index: -1; // Not interactable + margin: 7px 0 8px; // 1px h3 screen reader + top: 0; + right: @icon-box-size + @icon-padding * 2; + opacity: 0; + .boxshadow(4); + transition: @transition-opacity; + + // Hide title + h3 { + .mixin-screen-reader-text; + } + + // Search field + #searchInput { + padding: 12px 15px; + width: 0; + max-width: calc(~"100vw -" @icon-box-size * 2 + @icon-padding * 4 + @margin-side ); + border: 1px solid @base-90; + transition: @transition-width, @transition-box-shadow; + + &:focus { + outline: 0; + .boxshadow(5); + } + } + + // Search field button + #searchGoButton { + .button-blue; + width: @icon-box-size + @icon-padding * 2; + height: 41px; + border: 0; + cursor: pointer; //somehow it is not pointer + + &:hover, + &:active, + &:focus { + .button-blue-active; + } + } + } + + #search-icon-container { + display: flex; + align-items: center; + justify-content: center; + height: inherit; + + #search-icon { + opacity: @opacity-icon; + position: absolute; + margin-top: -2px; + margin-left: -2px; + width: 10px; + height: 10px; + border: solid 2px @base-0; + border-radius: 100%; + transform: rotate(-45deg); + transition: @transition-transform, + @transition-height, + @transition-opacity, + @transition-border-color; + + &:before, + &:after { + content: ''; + position: absolute; + width: 2px; + background-color: @base-0; + transition: inherit; + } + + &:before{ + top: 10px; + left: 3px; + height: 10px; + } + + &:after { + opacity: 0; + top: -1px; + left: 4px; + height: 18px; + transform: rotate(-90deg); + } + } + } + + > input { + &:checked { + ~ #p-search { + z-index: 5; + opacity: 1; + + #searchInput { + width: 400px; + } + } + + ~ #search-icon-container #search-icon { + border-color: transparent; + + &:before { + height: 18px; + transform: translate(1px, -11px); + } + + &:after { + opacity: 1; + } + + &:hover { + ~ #search-icon-container #search-icon { + border-color: @base-0; + + &:after { + opacity: 0; + } + } + } + } + + &:hover { + ~ #search-icon-container #search-icon { + border-color: @base-0; + + &:after { + height: 12px; + } + } + } + } + + &:hover { + ~ #search-icon-container #search-icon { + opacity: @opacity-icon-active; + + &:before { + height: 5px; + transform: translate(0px, 5px); + } + } + } + } +} + +// RTL tweaks +.rtl { + #site-search { + #p-search { + left: @icon-box-size + @margin-side + @icon-padding; + right: unset; + } + } +} diff --git a/resources/components/wikitable.less b/resources/components/wikitable.less new file mode 100644 index 00000000..b16a8c0c --- /dev/null +++ b/resources/components/wikitable.less @@ -0,0 +1,42 @@ +// +// Citizen - Wikitable Styles +// https://starcitizen.tools +// + +table.wikitable { + margin-top: @content-margin-top * 2!important; + background-color: transparent; + color: @base-20; + border: 0; + + // TEMP solution to fix overflow + display: block; + max-width: 100vw; + overflow: auto; + + tr { + vertical-align: top; + + th { + padding: @margin-side / 2 @margin-side @margin-side 0; + border: 0; + border-top: 1px solid currentColor; + color: @base-30; + background-color: transparent; + font-size: @content-caption-size; + letter-spacing: 1px; + text-transform: uppercase; + text-align: left; + } + + td { + border: 0; + border-bottom: 1px solid @base-80; + padding: @margin-side / 2 @margin-side @margin-side / 2 0; + } + + &:hover { + background-color: @base-90; + } + } +} diff --git a/resources/font-face.less b/resources/font-face.less new file mode 100644 index 00000000..bad610c3 --- /dev/null +++ b/resources/font-face.less @@ -0,0 +1,82 @@ +// Font-face stylesheet + +// Directory of hosted font +@font-directory: 'fonts/'; + +@font-face { + font-family: 'Titillium Web'; + src: url('@{font-directory}TitilliumWeb-Regular.eot'); + src: local('Titillium Web Regular'), local('TitilliumWeb-Regular'), + url('@{font-directory}TitilliumWeb-Regular.eot?#iefix') format('embedded-opentype'), + url('@{font-directory}TitilliumWeb-Regular.woff2') format('woff2'), + url('@{font-directory}TitilliumWeb-Regular.woff') format('woff'), + url('@{font-directory}TitilliumWeb-Regular.ttf') format('truetype'); + font-weight: normal; + font-style: normal; + font-display: swap; +} + +@font-face { + font-family: 'Roboto'; + src: url('@{font-directory}Roboto-Italic.eot'); + src: local('Roboto Italic'), local('Roboto-Italic'), + url('@{font-directory}Roboto-Italic.eot?#iefix') format('embedded-opentype'), + url('@{font-directory}Roboto-Italic.woff2') format('woff2'), + url('@{font-directory}Roboto-Italic.woff') format('woff'), + url('@{font-directory}Roboto-Italic.ttf') format('truetype'); + font-weight: normal; + font-style: italic; + font-display: swap; +} + +@font-face { + font-family: 'Titillium Web'; + src: url('@{font-directory}TitilliumWeb-Bold.eot'); + src: local('Titillium Web Bold'), local('TitilliumWeb-Bold'), + url('@{font-directory}TitilliumWeb-Bold.eot?#iefix') format('embedded-opentype'), + url('@{font-directory}TitilliumWeb-Bold.woff2') format('woff2'), + url('@{font-directory}TitilliumWeb-Bold.woff') format('woff'), + url('@{font-directory}TitilliumWeb-Bold.ttf') format('truetype'); + font-weight: bold; + font-style: normal; + font-display: swap; +} + +@font-face { + font-family: 'Titillium Web'; + src: url('@{font-directory}TitilliumWeb-Italic.eot'); + src: local('Titillium Web Italic'), local('TitilliumWeb-Italic'), + url('@{font-directory}TitilliumWeb-Italic.eot?#iefix') format('embedded-opentype'), + url('@{font-directory}TitilliumWeb-Italic.woff2') format('woff2'), + url('@{font-directory}TitilliumWeb-Italic.woff') format('woff'), + url('@{font-directory}TitilliumWeb-Italic.ttf') format('truetype'); + font-weight: normal; + font-style: italic; + font-display: swap; +} + +@font-face { + font-family: 'Roboto'; + src: url('@{font-directory}Roboto-Bold.eot'); + src: local('Roboto Bold'), local('Roboto-Bold'), + url('@{font-directory}Roboto-Bold.eot?#iefix') format('embedded-opentype'), + url('@{font-directory}Roboto-Bold.woff2') format('woff2'), + url('@{font-directory}Roboto-Bold.woff') format('woff'), + url('@{font-directory}Roboto-Bold.ttf') format('truetype'); + font-weight: bold; + font-style: normal; + font-display: swap; +} + +@font-face { + font-family: 'Roboto'; + src: url('@{font-directory}Roboto-Regular.eot'); + src: local('Roboto'), local('Roboto-Regular'), + url('@{font-directory}Roboto-Regular.eot?#iefix') format('embedded-opentype'), + url('@{font-directory}Roboto-Regular.woff2') format('woff2'), + url('@{font-directory}Roboto-Regular.woff') format('woff'), + url('@{font-directory}Roboto-Regular.ttf') format('truetype'); + font-weight: normal; + font-style: normal; + font-display: swap; +} diff --git a/resources/fonts/Roboto-Bold.eot b/resources/fonts/Roboto-Bold.eot new file mode 100644 index 00000000..e928a0d9 Binary files /dev/null and b/resources/fonts/Roboto-Bold.eot differ diff --git a/resources/fonts/Roboto-Bold.ttf b/resources/fonts/Roboto-Bold.ttf new file mode 100644 index 00000000..e612852d Binary files /dev/null and b/resources/fonts/Roboto-Bold.ttf differ diff --git a/resources/fonts/Roboto-Bold.woff b/resources/fonts/Roboto-Bold.woff new file mode 100644 index 00000000..4536546c Binary files /dev/null and b/resources/fonts/Roboto-Bold.woff differ diff --git a/resources/fonts/Roboto-Bold.woff2 b/resources/fonts/Roboto-Bold.woff2 new file mode 100644 index 00000000..4c8d525f Binary files /dev/null and b/resources/fonts/Roboto-Bold.woff2 differ diff --git a/resources/fonts/Roboto-Italic.eot b/resources/fonts/Roboto-Italic.eot new file mode 100644 index 00000000..b7b7b0e8 Binary files /dev/null and b/resources/fonts/Roboto-Italic.eot differ diff --git a/resources/fonts/Roboto-Italic.ttf b/resources/fonts/Roboto-Italic.ttf new file mode 100644 index 00000000..b85c4356 Binary files /dev/null and b/resources/fonts/Roboto-Italic.ttf differ diff --git a/resources/fonts/Roboto-Italic.woff b/resources/fonts/Roboto-Italic.woff new file mode 100644 index 00000000..d15b4b3b Binary files /dev/null and b/resources/fonts/Roboto-Italic.woff differ diff --git a/resources/fonts/Roboto-Italic.woff2 b/resources/fonts/Roboto-Italic.woff2 new file mode 100644 index 00000000..ca6d6c4f Binary files /dev/null and b/resources/fonts/Roboto-Italic.woff2 differ diff --git a/resources/fonts/Roboto-Regular.eot b/resources/fonts/Roboto-Regular.eot new file mode 100644 index 00000000..a88ce3f7 Binary files /dev/null and b/resources/fonts/Roboto-Regular.eot differ diff --git a/resources/fonts/Roboto-Regular.ttf b/resources/fonts/Roboto-Regular.ttf new file mode 100644 index 00000000..cb8ffcf1 Binary files /dev/null and b/resources/fonts/Roboto-Regular.ttf differ diff --git a/resources/fonts/Roboto-Regular.woff b/resources/fonts/Roboto-Regular.woff new file mode 100644 index 00000000..5421d5dd Binary files /dev/null and b/resources/fonts/Roboto-Regular.woff differ diff --git a/resources/fonts/Roboto-Regular.woff2 b/resources/fonts/Roboto-Regular.woff2 new file mode 100644 index 00000000..b6487a6f Binary files /dev/null and b/resources/fonts/Roboto-Regular.woff2 differ diff --git a/resources/fonts/Roboto-RegularItalic.ttf b/resources/fonts/Roboto-RegularItalic.ttf new file mode 100644 index 00000000..5fd05c3b Binary files /dev/null and b/resources/fonts/Roboto-RegularItalic.ttf differ diff --git a/resources/fonts/TitilliumWeb-Bold.eot b/resources/fonts/TitilliumWeb-Bold.eot new file mode 100644 index 00000000..040bd7b0 Binary files /dev/null and b/resources/fonts/TitilliumWeb-Bold.eot differ diff --git a/resources/fonts/TitilliumWeb-Bold.ttf b/resources/fonts/TitilliumWeb-Bold.ttf new file mode 100644 index 00000000..b51a4d63 Binary files /dev/null and b/resources/fonts/TitilliumWeb-Bold.ttf differ diff --git a/resources/fonts/TitilliumWeb-Bold.woff b/resources/fonts/TitilliumWeb-Bold.woff new file mode 100644 index 00000000..e0d7f131 Binary files /dev/null and b/resources/fonts/TitilliumWeb-Bold.woff differ diff --git a/resources/fonts/TitilliumWeb-Bold.woff2 b/resources/fonts/TitilliumWeb-Bold.woff2 new file mode 100644 index 00000000..fc9283a5 Binary files /dev/null and b/resources/fonts/TitilliumWeb-Bold.woff2 differ diff --git a/resources/fonts/TitilliumWeb-Italic.eot b/resources/fonts/TitilliumWeb-Italic.eot new file mode 100644 index 00000000..c930406f Binary files /dev/null and b/resources/fonts/TitilliumWeb-Italic.eot differ diff --git a/resources/fonts/TitilliumWeb-Italic.ttf b/resources/fonts/TitilliumWeb-Italic.ttf new file mode 100644 index 00000000..3f8d1be3 Binary files /dev/null and b/resources/fonts/TitilliumWeb-Italic.ttf differ diff --git a/resources/fonts/TitilliumWeb-Italic.woff b/resources/fonts/TitilliumWeb-Italic.woff new file mode 100644 index 00000000..f80105ae Binary files /dev/null and b/resources/fonts/TitilliumWeb-Italic.woff differ diff --git a/resources/fonts/TitilliumWeb-Italic.woff2 b/resources/fonts/TitilliumWeb-Italic.woff2 new file mode 100644 index 00000000..8902a5d1 Binary files /dev/null and b/resources/fonts/TitilliumWeb-Italic.woff2 differ diff --git a/resources/fonts/TitilliumWeb-Regular.eot b/resources/fonts/TitilliumWeb-Regular.eot new file mode 100644 index 00000000..1c9db214 Binary files /dev/null and b/resources/fonts/TitilliumWeb-Regular.eot differ diff --git a/resources/fonts/TitilliumWeb-Regular.ttf b/resources/fonts/TitilliumWeb-Regular.ttf new file mode 100644 index 00000000..a54ad4b9 Binary files /dev/null and b/resources/fonts/TitilliumWeb-Regular.ttf differ diff --git a/resources/fonts/TitilliumWeb-Regular.woff b/resources/fonts/TitilliumWeb-Regular.woff new file mode 100644 index 00000000..90cf46f2 Binary files /dev/null and b/resources/fonts/TitilliumWeb-Regular.woff differ diff --git a/resources/fonts/TitilliumWeb-Regular.woff2 b/resources/fonts/TitilliumWeb-Regular.woff2 new file mode 100644 index 00000000..e4ed8971 Binary files /dev/null and b/resources/fonts/TitilliumWeb-Regular.woff2 differ diff --git a/resources/fonts/TitilliumWeb-RegularItalic.ttf b/resources/fonts/TitilliumWeb-RegularItalic.ttf new file mode 100644 index 00000000..266d5cb8 Binary files /dev/null and b/resources/fonts/TitilliumWeb-RegularItalic.ttf differ diff --git a/resources/images/badges/CCBYSA4.svg b/resources/images/badges/CCBYSA4.svg new file mode 100644 index 00000000..7a46ae73 --- /dev/null +++ b/resources/images/badges/CCBYSA4.svg @@ -0,0 +1 @@ +CCBYSA4 \ No newline at end of file diff --git a/resources/images/badges/GDPR.svg b/resources/images/badges/GDPR.svg new file mode 100644 index 00000000..9030d8c2 --- /dev/null +++ b/resources/images/badges/GDPR.svg @@ -0,0 +1 @@ +GDPR \ No newline at end of file diff --git a/resources/images/badges/MadeByTheCommunity.svg b/resources/images/badges/MadeByTheCommunity.svg new file mode 100644 index 00000000..97694563 --- /dev/null +++ b/resources/images/badges/MadeByTheCommunity.svg @@ -0,0 +1 @@ +Asset 3 \ No newline at end of file diff --git a/resources/images/badges/MonitoredByWikiApiary.svg b/resources/images/badges/MonitoredByWikiApiary.svg new file mode 100644 index 00000000..48c1cc31 --- /dev/null +++ b/resources/images/badges/MonitoredByWikiApiary.svg @@ -0,0 +1 @@ +Asset 4 \ No newline at end of file diff --git a/resources/images/badges/PoweredByMediawiki.svg b/resources/images/badges/PoweredByMediawiki.svg new file mode 100644 index 00000000..ec6f8115 --- /dev/null +++ b/resources/images/badges/PoweredByMediawiki.svg @@ -0,0 +1 @@ +PoweredByMediawiki \ No newline at end of file diff --git a/resources/images/icons/ToC.svg b/resources/images/icons/ToC.svg new file mode 100644 index 00000000..b71332eb --- /dev/null +++ b/resources/images/icons/ToC.svg @@ -0,0 +1,7 @@ + + + + stripe ToC + + + diff --git a/resources/images/icons/article.svg b/resources/images/icons/article.svg new file mode 100644 index 00000000..820abdd8 --- /dev/null +++ b/resources/images/icons/article.svg @@ -0,0 +1,7 @@ + + + + article + + + diff --git a/resources/images/icons/beta.svg b/resources/images/icons/beta.svg new file mode 100644 index 00000000..7a37c5a7 --- /dev/null +++ b/resources/images/icons/beta.svg @@ -0,0 +1,7 @@ + + + + beaker + + + diff --git a/resources/images/icons/contributions.svg b/resources/images/icons/contributions.svg new file mode 100644 index 00000000..1af18f8f --- /dev/null +++ b/resources/images/icons/contributions.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/resources/images/icons/delete.svg b/resources/images/icons/delete.svg new file mode 100644 index 00000000..1751526a --- /dev/null +++ b/resources/images/icons/delete.svg @@ -0,0 +1,7 @@ + + + + trash + + + diff --git a/resources/images/icons/discord.svg b/resources/images/icons/discord.svg new file mode 100644 index 00000000..15ee8f92 --- /dev/null +++ b/resources/images/icons/discord.svg @@ -0,0 +1,18 @@ + + + + + + + diff --git a/resources/images/icons/discussion.svg b/resources/images/icons/discussion.svg new file mode 100644 index 00000000..e529f5e2 --- /dev/null +++ b/resources/images/icons/discussion.svg @@ -0,0 +1,8 @@ + + + + speech bubbles + + + + diff --git a/resources/images/icons/download.svg b/resources/images/icons/download.svg new file mode 100644 index 00000000..7cdc0067 --- /dev/null +++ b/resources/images/icons/download.svg @@ -0,0 +1 @@ + diff --git a/resources/images/icons/edit.svg b/resources/images/icons/edit.svg new file mode 100644 index 00000000..9577b4f6 --- /dev/null +++ b/resources/images/icons/edit.svg @@ -0,0 +1 @@ + diff --git a/resources/images/icons/eye.svg b/resources/images/icons/eye.svg new file mode 100644 index 00000000..dc7fce7c --- /dev/null +++ b/resources/images/icons/eye.svg @@ -0,0 +1,8 @@ + + + + eye + + + + diff --git a/resources/images/icons/eyeClosed.svg b/resources/images/icons/eyeClosed.svg new file mode 100644 index 00000000..e71ec4b6 --- /dev/null +++ b/resources/images/icons/eyeClosed.svg @@ -0,0 +1,8 @@ + + + + eye closed + + + + diff --git a/resources/images/icons/history.svg b/resources/images/icons/history.svg new file mode 100644 index 00000000..d7567150 --- /dev/null +++ b/resources/images/icons/history.svg @@ -0,0 +1 @@ +history \ No newline at end of file diff --git a/resources/images/icons/history_white.svg b/resources/images/icons/history_white.svg new file mode 100644 index 00000000..ef734dd3 --- /dev/null +++ b/resources/images/icons/history_white.svg @@ -0,0 +1 @@ +history diff --git a/resources/images/icons/home.svg b/resources/images/icons/home.svg new file mode 100644 index 00000000..ff37d418 --- /dev/null +++ b/resources/images/icons/home.svg @@ -0,0 +1 @@ + diff --git a/resources/images/icons/image.svg b/resources/images/icons/image.svg new file mode 100644 index 00000000..0d0a198e --- /dev/null +++ b/resources/images/icons/image.svg @@ -0,0 +1,7 @@ + + + + image + + + diff --git a/resources/images/icons/info.svg b/resources/images/icons/info.svg new file mode 100644 index 00000000..973702e0 --- /dev/null +++ b/resources/images/icons/info.svg @@ -0,0 +1,7 @@ + + + + info + + + diff --git a/resources/images/icons/link.svg b/resources/images/icons/link.svg new file mode 100644 index 00000000..581d0e37 --- /dev/null +++ b/resources/images/icons/link.svg @@ -0,0 +1,8 @@ + + + + link + + + + diff --git a/resources/images/icons/lock.svg b/resources/images/icons/lock.svg new file mode 100644 index 00000000..d6fbab6d --- /dev/null +++ b/resources/images/icons/lock.svg @@ -0,0 +1,7 @@ + + + + lock + + + diff --git a/resources/images/icons/logOut.svg b/resources/images/icons/logOut.svg new file mode 100644 index 00000000..98ca7b4d --- /dev/null +++ b/resources/images/icons/logOut.svg @@ -0,0 +1,8 @@ + + + + log out + + + + diff --git a/resources/images/icons/login.svg b/resources/images/icons/login.svg new file mode 100644 index 00000000..cac442ce --- /dev/null +++ b/resources/images/icons/login.svg @@ -0,0 +1 @@ + diff --git a/resources/images/icons/more.svg b/resources/images/icons/more.svg new file mode 100644 index 00000000..b4e2b0e2 --- /dev/null +++ b/resources/images/icons/more.svg @@ -0,0 +1 @@ +ellipsis \ No newline at end of file diff --git a/resources/images/icons/move.svg b/resources/images/icons/move.svg new file mode 100644 index 00000000..ddbf49b9 --- /dev/null +++ b/resources/images/icons/move.svg @@ -0,0 +1,7 @@ + + + + move + + + diff --git a/resources/images/icons/profile.svg b/resources/images/icons/profile.svg new file mode 100644 index 00000000..4147ed40 --- /dev/null +++ b/resources/images/icons/profile.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/resources/images/icons/random.svg b/resources/images/icons/random.svg new file mode 100644 index 00000000..1792476e --- /dev/null +++ b/resources/images/icons/random.svg @@ -0,0 +1 @@ + diff --git a/resources/images/icons/reddit.svg b/resources/images/icons/reddit.svg new file mode 100644 index 00000000..21726516 --- /dev/null +++ b/resources/images/icons/reddit.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/resources/images/icons/settings.svg b/resources/images/icons/settings.svg new file mode 100644 index 00000000..fbc1f5b4 --- /dev/null +++ b/resources/images/icons/settings.svg @@ -0,0 +1 @@ + diff --git a/resources/images/icons/specialpages.svg b/resources/images/icons/specialpages.svg new file mode 100644 index 00000000..efb3b249 --- /dev/null +++ b/resources/images/icons/specialpages.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/resources/images/icons/unLock.svg b/resources/images/icons/unLock.svg new file mode 100644 index 00000000..2893b6ca --- /dev/null +++ b/resources/images/icons/unLock.svg @@ -0,0 +1,7 @@ + + + + un-lock + + + diff --git a/resources/images/icons/upload.svg b/resources/images/icons/upload.svg new file mode 100644 index 00000000..be053d27 --- /dev/null +++ b/resources/images/icons/upload.svg @@ -0,0 +1,8 @@ + + + + upload + + + + diff --git a/resources/images/icons/userAvatar.svg b/resources/images/icons/userAvatar.svg new file mode 100644 index 00000000..3f47c477 --- /dev/null +++ b/resources/images/icons/userAvatar.svg @@ -0,0 +1,8 @@ + + + + user avatar + + + + diff --git a/resources/images/icons/userNormal.svg b/resources/images/icons/userNormal.svg new file mode 100644 index 00000000..b63e9612 --- /dev/null +++ b/resources/images/icons/userNormal.svg @@ -0,0 +1 @@ + diff --git a/resources/images/icons/userTalk.svg b/resources/images/icons/userTalk.svg new file mode 100644 index 00000000..990cfc39 --- /dev/null +++ b/resources/images/icons/userTalk.svg @@ -0,0 +1,7 @@ + + + + user talk + + + diff --git a/resources/images/icons/ve-edit.svg b/resources/images/icons/ve-edit.svg new file mode 100644 index 00000000..fa13e4d4 --- /dev/null +++ b/resources/images/icons/ve-edit.svg @@ -0,0 +1 @@ +Visual Edit \ No newline at end of file diff --git a/resources/images/icons/warning.svg b/resources/images/icons/warning.svg new file mode 100644 index 00000000..53c5d5ba --- /dev/null +++ b/resources/images/icons/warning.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/resources/images/icons/watchlist.svg b/resources/images/icons/watchlist.svg new file mode 100644 index 00000000..d974bb46 --- /dev/null +++ b/resources/images/icons/watchlist.svg @@ -0,0 +1 @@ + diff --git a/resources/images/icons/whatlinkshere.svg b/resources/images/icons/whatlinkshere.svg new file mode 100644 index 00000000..f4e3214d --- /dev/null +++ b/resources/images/icons/whatlinkshere.svg @@ -0,0 +1,7 @@ + + + + what links here + + + diff --git a/resources/main.js b/resources/main.js new file mode 100644 index 00000000..a9f01d07 --- /dev/null +++ b/resources/main.js @@ -0,0 +1 @@ +/* JavaScript for the Example skin */ diff --git a/resources/mixins.less b/resources/mixins.less new file mode 100644 index 00000000..e7b34a2b --- /dev/null +++ b/resources/mixins.less @@ -0,0 +1,154 @@ +/* + * Citizen - Mixins + * https://starcitizen.tools +*/ + +// To hide objects, but keep them accessible for screen-readers +.hidden() { + position: absolute; + top: -9999px; +} + +// Set content to be at the center +.content-center() { + max-width: @page-width; + margin-left: auto; + margin-right: auto; +} + +// Prepare for RL icons +.resource-loader-icon-link() { + width: @icon-box-size; + height: @icon-box-size; + display: block; +} + +.resource-loader-icon-link-small() { + width: @icon-size; + height: @icon-size; + display: block; +} + +.resource-loader-icon() { + content: ""; + position: absolute; + width: inherit; + height: inherit; + background-repeat: no-repeat; + background-position: center; +} + +.resource-loader-menu-icon() { + content: ""; + position: absolute; + width: @icon-box-size; + height: @icon-box-size; + background-repeat: no-repeat; + background-position: center; +} + +.resource-loader-list-icon() { + content: ""; + position: relative; + flex-shrink: 0; + align-self: center; + width: @icon-size; + height: @icon-size; + background-repeat: no-repeat; + background-position: center; +} + +// Material-like menu +.menu-container() { + padding: 8px 0; + background-color: @menu-background; + display: block; +} + +.menu-item-link() { + display: flex; + color: @color-item-text!important; + transition: @transition-background-quick, @transition-color-quick; +} + +.menu-item-link-hover() { + color: @color-item-text-hover!important; + background-color: @menu-item-link-hover; +} + +.menu-item-link-active() { + color: @color-item-text-hover!important; + background-color: @menu-item-link-active; +} + +.menu-item-link-focus() { + color: @color-item-text-hover!important; + background-color: @menu-item-link-hover; +} + +// Button Styles +.button-blue() { + background-color: @accent-50; + color: @base-80!important; + transition: @transition-background-quick, @transition-color-quick; +} + +.button-blue-active() { + background-color: @accent-10; + color: @base-100!important; +} + +.button-red() { + background-color: @red-50; + color: @base-80!important; + transition: @transition-background-quick, @transition-color-quick; +} + +.button-red-active() { + background-color: @red-30; + color: @base-100!important; +} + +// Link styles +.link-content-text(@color) { + background-image: linear-gradient(to right, @color 0, @color 100%); + background-repeat: no-repeat; + background-size: 0 100%; + transition: @transition-background-quick, @transition-color-quick; + + &:hover, &:active, &:focus { + outline: none; + color: white!important; + background-size: 100% 100%!important; + } +} + +// Gradient overflow +.gradient-overflow(@position) { + content: ""; + position: fixed; + z-index: 3; + width: 100%; + height: @margin-side * 2; + background: @position; +} + +// Box-shadow +// https://codepen.io/sdthornton/pen/wBZdXq +.boxshadow(@level: 1){ + & when (@level = 1) { + box-shadow: 0 1px 3px rgba(0,0,0,0.03), 0 1px 2px rgba(0,0,0,0.06); // Cards + } + & when (@level = 2) { + box-shadow: 0 3px 6px rgba(0,0,0,0.04), 0 3px 6px rgba(0,0,0,0.0575); + } + & when (@level = 3) { + box-shadow: 0 10px 20px rgba(0,0,0,0.0475), 0 6px 6px rgba(0,0,0,0.0575); // Drawer + } + & when (@level = 4) { + box-shadow: 0 14px 28px rgba(0,0,0,0.0625), 0 10px 10px rgba(0,0,0,0.055); // FAB, floating elements + } + & when (@level = 5) { + box-shadow: 0 19px 38px rgba(0,0,0,0.075), 0 15px 12px rgba(0,0,0,0.055); // Dialogs + } +} diff --git a/resources/print.less b/resources/print.less new file mode 100644 index 00000000..7b23cc38 --- /dev/null +++ b/resources/print.less @@ -0,0 +1,9 @@ +/* Styles for print view and printing */ + +/* Hide some extra stuff from print view (some of the navigation is already hidden automatically, but not all) */ +.mw-indicators, +#p-logo, +#catlinks, +#mw-footer { + display: none; +} diff --git a/resources/screen.less b/resources/screen.less new file mode 100644 index 00000000..c71c56ad --- /dev/null +++ b/resources/screen.less @@ -0,0 +1,11 @@ +/* Citizen */ + +@import 'variables.less'; +@import 'mixins.less'; +@import 'components/common.less'; +@import 'components/navigation.less'; +@import 'components/wikitable.less'; +@import 'components/page-tools.less'; +@import 'components/search.less'; +@import 'components/footer.less'; +@import 'components/bottombar.less'; diff --git a/resources/scripts/Header.js b/resources/scripts/Header.js new file mode 100644 index 00000000..0a5e44fb --- /dev/null +++ b/resources/scripts/Header.js @@ -0,0 +1,42 @@ +/* +* Scroll up Header +* Modified from https://codepen.io/sajjad/pen/vgEZNy +*/ + +// Hide header on scroll down +var didScroll; +var lastScrollTop = 0; +var delta = 5; +var navbarHeight = $('.mw-header-container').outerHeight(); + +$(window).scroll(function(event){ + didScroll = true; +}); + +setInterval(function() { + if (didScroll) { + hasScrolled(); + didScroll = false; + } +}, 250); + +function hasScrolled() { + var st = $(this).scrollTop(); + + // Make scroll more than delta + if(Math.abs(lastScrollTop - st) <= delta) + return; + + // If scrolled down and past the navbar, add class .nav-up. + if (st > lastScrollTop && st > navbarHeight){ + // Scroll Down + $('header').removeClass('nav-down').addClass('nav-up'); + } else { + // Scroll Up + if(st + $(window).height() < $(document).height()) { + $('header').removeClass('nav-up').addClass('nav-down'); + } + } + + lastScrollTop = st; +} diff --git a/resources/scripts/ToC.js b/resources/scripts/ToC.js new file mode 100644 index 00000000..e69de29b diff --git a/resources/variables.less b/resources/variables.less new file mode 100644 index 00000000..63f42e0b --- /dev/null +++ b/resources/variables.less @@ -0,0 +1,169 @@ +/* + * Citizen - Navigation Styles + * https://starcitizen.tools +*/ + +// Import MediaWiki-supplied mixins +@import "mediawiki.mixins"; + +/* + * Framework +*/ +@html-font-size: 100%; +@margin-side: 20px; +@page-width: 860px; +@footer-width: 1290px; +@icon-size: 18px; +@icon-box-size: @icon-size + @icon-margin * 2; +@icon-margin: 3px; +@icon-padding: 15px; +@header-height: 56px; +@sidebar-sitename-height: 69px; +@drawer-width: 300px; +@padding-menu-item: 10px 15px; +@padding-menu-item-big: 10px 20px; +@negative-margin: (@footer-width - @page-width) / -2; + +/* + * Colors +*/ + +// Wikimedia colors +@base-0: #000; +@base-10: #222; +@base-20: #54595d; +@base-30: #72777d; +@base-50: #a2a9b1; +@base-80: #eaecf0; +@base-90: #f8f9fa; +@base-100: #fff; + +@accent-10: #2a4b8d; +@accent-50: #36c; + +@red-30: #b32424; +@red-50: #d33; +@red-90: #fee7e6; + +@green-30: #14866d; +@green-50: #00af89; +@green-90: #d5fdf4; + +@yellow-30: #ac6600; +@yellow-50: #fc3; +@yellow-90: #fef6e7; + +@menu-background: @base-100; +@opacity-icon: 0.3; +@opacity-icon-active: 0.5; +@color-item-text: @base-30; +@color-item-text-hover: @base-20; +@color-item-header: @base-10; +@menu-item-link-hover: @base-90; +@menu-item-link-active: @base-80; + +@color-content-text: @base-20; +@color-content-header: @base-10; +@color-content-caption: @base-30; + +@color-link: #3366cc; +@color-link-active: #5b84d6; +@color-link-new: #dd3333; +@color-link-new-active: #e35b5b; +@color-link-visited: #6b4ba1; +@color-link-visited-active: #886eb3; + +// Citizen colors +@color-footer-background-40: #0f1418; +@color-footer-background-50: #131a21; +@color-footer-background-60: #1a252d; +@color-footer-text: #979c9f; +@color-footer-link: #cfdee8; +@color-footer-link-active: @base-80; +/* + +/* + * Transitions +*/ +@transition-color-quick: color 0.2s ease; +@transition-transform: transform 0.5s cubic-bezier(0.77,0.2,0.05,1.0); +@transition-transform-quick: transform 0.2s cubic-bezier(0.77,0.2,0.05,1.0); +@transition-width: width 0.5s cubic-bezier(0.77,0.2,0.05,1.0); +@transition-height: height 0.5s cubic-bezier(0.77,0.2,0.05,1.0); +@transition-background-quick: background 0.2s ease; +@transition-background: background 0.55s ease; +@transition-opacity: opacity 0.55s ease; +@transition-opacity-quick: opacity 0.2s ease; +@transition-border: border 0.55s ease; +@transition-border-quick: border 0.2s ease; +@transition-box-shadow: box-shadow 0.55s ease; +@transition-box-shadow-quick: box-shadow 0.2s ease; +@transition-border-color: border-color 0.55s ease; + +/* + * Fonts +*/ +/** + * System font stack for sans-serif fonts + * + * `Roboto` – Default font, Android 4.0+ system font, OFL licensed + * `-apple-system` ('San Francisco' font) – Support Safari 9+ macOS and iOS, Firefox macOS + * `BlinkMacSystemFont` ('San Francisco' font) – Chrome 48+ macOS and iOS + * `Segoe UI` – Windows Vista & newer + * `Oxygen` - Linux, KDE + * `Ubuntu` - Linux, Ubuntu + * `Cantarell` - Linux, GNOME + * `Helvetica, Arial, sans-serif` – (Generic) Web fallback + * Note that standard `system-ui` value has resulted in unresolved side-effects in certain OS/language combinations as of now and is therefore not included. + */ +@fonts: 'Roboto', -apple-system, BlinkMacSystemFont, "Segoe UI", "Oxygen", "Ubuntu", "Cantarell", "Helvetica Neue", sans-serif; +/** + * Citizen font stack + * + * `Titillium Web` – Futuristic, Closet to Univia Pro, OFL licensed + * `Univia Pro` - Fallback font if Univia Pro is present + * 'Monoid' - Code font, OFL licensed + * Fallback using primary fonts + */ +@fonts-secondary: 'Titillium Web', 'Univia Pro', @fonts; +/** + * System font stack for monospace fonts + * + * `Menlo` – macOS 10.6+ + * `Roboto Mono` - Android 4.0+ + * `Consolas` – Windows Vista & newer + * `Liberation Mono` – Fedora, Ubuntu, … OFL licensed + * `'Courier New', monospace` – (Generic) web font fallback + */ +@fonts-monospace: 'Menlo', 'Roboto Mono', 'Consolas', 'Liberation Mono', 'Courier New', monospace; + +/* + * Text hierarchy +*/ + +// Scaling for content text +@content-scaling: 0.625; +@toc-scaling: 0.75; + +// Wikimedia scale - https://design.wikimedia.org/style-guide/visual-style_typography.html +@content-h1-size: 3.2rem * @content-scaling; +@content-h2-size: 2.4rem * @content-scaling; +@content-h3-size: 2.0rem * @content-scaling; +@content-h4-size: 1.8rem * @content-scaling; +@content-h5-size: 1.6rem * @content-scaling; +@content-h6-size: 1.6rem * @content-scaling; +@content-body-size: 1.6rem * @content-scaling; +@content-lead-paragraph-size: 1.8rem * @content-scaling; +@content-quote-primary-size: 2.0rem * @content-scaling; +@content-quote-secondary-size: 1.4rem * @content-scaling; +@content-caption-size: 1.3rem * @content-scaling; +@content-small-text-size: 1.3rem * @content-scaling; +@content-monospace-size: 1.4rem * @content-scaling; +@content-line-height: 1.6; +@content-margin-top: 0.8rem; + +@ui-menu-text: 14px; +@ui-menu-text-big: 15px; +@ui-menu-header: 16px; + +@footer-line-height: 1.4; diff --git a/skin.json b/skin.json new file mode 100644 index 00000000..98499baa --- /dev/null +++ b/skin.json @@ -0,0 +1,181 @@ +{ + "name": "Citizen", + "namemsg": "skinname-citizen", + "author": "alistair3149", + "url": "https://starcitizen.tools", + "descriptionmsg": "citizen-desc", + "namemsg": "skinname-citizen", + "license-name": "CC-BY-SA-4.0", + "type": "skin", + "requires": { + "MediaWiki": ">= 1.31.0" + }, + "ValidSkinNames": { + "citizen": "Citizen" + }, + "MessagesDirs": { + "Citizen": [ + "i18n" + ] + }, + "ResourceModules": { + "skins.citizen": { + "class": "ResourceLoaderSkinModule", + "styles": { + "resources/screen.less": { + "media": "screen" + }, + "resources/print.less": { + "media": "print" + }, + "resources/font-face.less": {} + } + }, + "skins.citizen.js": { + "scripts": [ + "resources/main.js", + "resources/scripts/Header.js" + ] + }, + "skins.citizen.icons": { + "class": "ResourceLoaderImageModule", + "selector": "#citizen-ui-{name} > *:after", + "defaultColor": "#000", + "useDataURI": false, + "images": { + "discord": "resources/images/icons/discord.svg" + } + }, + "skins.citizen.icons.ca": { + "class": "ResourceLoaderImageModule", + "selector": "#ca-{name} > *:after", + "defaultColor": "#000", + "useDataURI": false, + "images": { + "view": "resources/images/icons/article.svg", + "ve-edit": "resources/images/icons/ve-edit.svg", + "edit": "resources/images/icons/edit.svg", + "history": "resources/images/icons/history.svg", + "delete": "resources/images/icons/delete.svg", + "move": "resources/images/icons/move.svg", + "protect": "resources/images/icons/lock.svg", + "unprotect": "resources/images/icons/unLock.svg", + "watch": "resources/images/icons/eye.svg", + "unwatch": "resources/images/icons/eyeClosed.svg", + "talk": "resources/images/icons/discussion.svg", + "nstab-main": "resources/images/icons/article.svg" + } + }, + "skins.citizen.icons.p": { + "class": "ResourceLoaderImageModule", + "selector": "#p-{name} > *:before", + "defaultColor": "#000", + "useDataURI": false, + "images": { + "actions": "resources/images/icons/more.svg" + } + }, + "skins.citizen.icons.toc": { + "class": "ResourceLoaderImageModule", + "selector": ".toctoggle > a:before", + "defaultColor": "#000", + "useDataURI": false, + "images": { + "": "resources/images/icons/ToC.svg" + } + }, + "skins.citizen.icons.es": { + "class": "ResourceLoaderImageModule", + "selector": ".mw-editsection > a{name}:before", + "defaultColor": "#000", + "useDataURI": false, + "images": { + "": "resources/images/icons/edit.svg", + ".mw-editsection-visualeditor": "resources/images/icons/ve-edit.svg" + } + }, + "skins.citizen.icons.n": { + "class": "ResourceLoaderImageModule", + "selector": "#n-{name} > *:after", + "defaultColor": "#000", + "useDataURI": false, + "images": { + "mainpage-description": "resources/images/icons/home.svg", + "recentchanges": "resources/images/icons/history.svg", + "randompage": "resources/images/icons/random.svg" + } + }, + "skins.citizen.icons.t": { + "class": "ResourceLoaderImageModule", + "selector": "#t-{name} > *:after", + "defaultColor": "#000", + "useDataURI": false, + "images": { + "whatlinkshere": "resources/images/icons/whatlinkshere.svg", + "recentchangeslinked": "resources/images/icons/history.svg", + "upload": "resources/images/icons/upload.svg", + "specialpages": "resources/images/icons/specialpages.svg", + "print": "resources/images/icons/download.svg", + "permalink": "resources/images/icons/link.svg", + "info": "resources/images/icons/info.svg" + } + }, + "skins.citizen.icons.pt": { + "class": "ResourceLoaderImageModule", + "selector": "#pt-{name} > *:after", + "defaultColor": "#000", + "useDataURI": false, + "images": { + "userpage": "resources/images/icons/userNormal.svg", + "mytalk": "resources/images/icons/userTalk.svg", + "preferences": "resources/images/icons/settings.svg", + "betafeatures": "resources/images/icons/beta.svg", + "watchlist": "resources/images/icons/watchlist.svg", + "mycontris": "resources/images/icons/contributions.svg", + "logout": "resources/images/icons/logOut.svg", + "createaccount": "resources/images/icons/userAvatar.svg", + "login": "resources/images/icons/logOut.svg" + } + }, + "skins.citizen.icons.footer": { + "class": "ResourceLoaderImageModule", + "selector": "#footer #{name}:before", + "defaultColor": "#fff", + "useDataURI": false, + "images": { + "lastmod": "resources/images/icons/history_white.svg" + } + }, + "skins.citizen.icons.badges": { + "class": "ResourceLoaderImageModule", + "selector": "#footer-{name}ico a:before", + "defaultColor": "#fff", + "useDataURI": false, + "images": { + "copyright": "resources/images/badges/CCBYSA4.svg", + "poweredby": "resources/images/badges/PoweredByMediawiki.svg", + "monitoredby": "resources/images/badges/MonitoredByWikiApiary.svg", + "gdprcompliance": "resources/images/badges/GDPR.svg", + "madeby": "resources/images/badges/MadeByTheCommunity.svg" + } + } + }, + "ResourceFileModulePaths": { + "localBasePath": "", + "remoteSkinPath": "Citizen" + }, + "ResourceModuleSkinStyles": { + "citizen": { + "+ext.echo.styles.badge": "skinStyles/echo.styles.badge.less", + "+ext.relatedArticles.cards": "skinStyles/ext.relatedArticles.cards.less", + "+ext.relatedArticles.readMore": "skinStyles/ext.relatedArticles.readMore.less", + "+ext.uls.pt": "skinStyles/ext.uls.pt.less", + "+ext.visualEditor.core": "skinStyles/ext.visualEditor.core.less" + } + }, + "AutoloadClasses": { + "SkinCitizen": "includes/SkinCitizen.php", + "CitizenTemplate": "includes/CitizenTemplate.php" + }, + "manifest_version": 1 +} diff --git a/skinStyles/echo.styles.badge.less b/skinStyles/echo.styles.badge.less new file mode 100644 index 00000000..a8fe6078 --- /dev/null +++ b/skinStyles/echo.styles.badge.less @@ -0,0 +1,58 @@ +/* + * Citizen - Echo Styles + * https://starcitizen.tools +*/ + +@import '../resources/variables.less'; + +// Styles for echo badges +#pt-notifications { + &-alert, + &-notice { + + .mw-echo-notifications-badge { + top: -1000px; // Default was -1005px for some reason + margin: 0; + width: @icon-box-size + @icon-padding; + height: @header-height; + + &:hover, + &:focus, + &:active { + &:before { + opacity: 0.6!important; // override all styles + } + } + + // Icon tweaks + &:before { + opacity: 0.4; + background-position: center; + transition: @transition-opacity, @transition-transform; + } + + // Badge tweaks + &:after { + background-color: @red-50; + font-size: 11px; + } + + &.mw-echo-notifications-badge-all-read { + opacity: 0.75; // 0.75 * 0.4 = 0.3 + } + } + } + + // Rotate bell + &-alert { + .mw-echo-notifications-badge { + &:hover, + &:focus, + &:active { + &:before { + transform: rotateZ(20deg); + } + } + } + } +} diff --git a/skinStyles/ext.relatedArticles.cards.less b/skinStyles/ext.relatedArticles.cards.less new file mode 100644 index 00000000..0aad0c6d --- /dev/null +++ b/skinStyles/ext.relatedArticles.cards.less @@ -0,0 +1,28 @@ +/* + * Citizen - Related Articles Styles + * https://starcitizen.tools +*/ + +@import '../resources/variables.less'; +@import '../resources/mixins.less'; + +.ext-related-articles-card-list { + margin-top: 0; + padding-top: @content-margin-top; // Give room for shadows and translate + + .ext-related-articles-card { + border: 0!important; + border-radius: 0!important; + .boxshadow(1); + transition: @transition-transform-quick; + + &:hover { + .boxshadow(2); + transform:translateY(-2px); + } + + > a:hover { + box-shadow: none; + } + } +} diff --git a/skinStyles/ext.relatedArticles.readMore.less b/skinStyles/ext.relatedArticles.readMore.less new file mode 100644 index 00000000..aab3e3bd --- /dev/null +++ b/skinStyles/ext.relatedArticles.readMore.less @@ -0,0 +1,21 @@ +/* + * Citizen - Related Articles Styles + * https://starcitizen.tools +*/ + +@import '../resources/variables.less'; + +.read-more-container { + margin: 0 auto; + max-width: @footer-width; +} + +.ra-read-more { + padding: @margin-side; + + h2 { + margin: 0; + padding: 0; + font-size: @content-caption-size; // In line with other styles + } +} diff --git a/skinStyles/ext.uls.pt.less b/skinStyles/ext.uls.pt.less new file mode 100644 index 00000000..5111454b --- /dev/null +++ b/skinStyles/ext.uls.pt.less @@ -0,0 +1,25 @@ +/* + * Citizen - ULS toggle Styles + * https://starcitizen.tools +*/ + +@import '../resources/variables.less'; + +// Styles for ULS icon +#pt-uls a.uls-trigger { + padding: 0; + display: block; + width: @icon-box-size + @icon-padding; + height: @header-height; + color: transparent; // Hide text + opacity: 0.6; // Replicate color of other icons + background-size: @icon-box-size; + background-position: center; + transition: @transition-opacity; + + &:hover, + &:focus, + &:active { + opacity: 0.8; + } +} diff --git a/skinStyles/ext.visualEditor.core.less b/skinStyles/ext.visualEditor.core.less new file mode 100644 index 00000000..f74a4d84 --- /dev/null +++ b/skinStyles/ext.visualEditor.core.less @@ -0,0 +1,53 @@ +/* + * Citizen - Visual Editor Styles + * https://starcitizen.tools +*/ + +@import '../resources/variables.less'; + +.ve-activated { + #mw-sidebar-sitename { + top: @sidebar-sitename-height + @header-height * 2 + @margin-side; + } + + #page-tools { + z-index: 1; // Fix collision + pointer-events: auto; + opacity: 1; + } +} + +// Fix weird compressed text bug +.ve-init-mw-tempWikitextEditorWidget { + width: 100%!important; +} + +// Match animation +.ve-init-mw-desktopArticleTarget-toolbar-open > .oo-ui-toolbar-bar { + transition: @transition-transform!important; +} + +// Make toolbar more mobile friendly, well at least I did by best +.ve-init-mw-desktopArticleTarget-toolbar { + margin: -20px -20px 20px -20px!important; // Bypass @media screen styles +} + +// Stick with the header +.nav-down ~ .mw-body { + .ve-ui-toolbar-floating > .oo-ui-toolbar-bar { + transform: translateY( @header-height ); + } +} + +.ve-ui-surface-placeholder, .ve-ui-surface .ve-ce-documentNode { + padding: 0; +} + +.ve-init-mw-desktopArticleTarget .CodeMirror { + padding: 0; + line-height: @content-line-height; // Lining up syntax highlighter +} + +.ve-init-mw-desktopArticleTarget .CodeMirror-code *, .ve-init-mw-desktopArticleTarget .ve-ui-mwWikitextSurface .ve-ce-paragraphNode { + line-height: @content-line-height; // Lining up syntax highlighter +}