Moving site

This commit is contained in:
Alice Rhodes 2023-08-15 15:25:21 -04:00
parent e0628632b8
commit ceff01aa32
213 changed files with 15533 additions and 0 deletions

10
.gitignore vendored Normal file
View File

@ -0,0 +1,10 @@
.cache
.cecil
_site/*
.idea/*
*.*~
.code-workspace/*
# Local Netlify folder
.netlify

92
CONTRIBUTING.md Normal file
View File

@ -0,0 +1,92 @@
# Contributing to Veilid
Before you get started, please review our [Code of Conduct](./code_of_conduct.md). We're here to make things better and we cannot do that by treating each other without respect.
## Code Contributions
### Tech Overview
veilid.com is a flat-file website hosted on Netlify and generated using [cecil.app](https://cecil.app/). Cecil is powered by PHP and Twig templates with the content in markdown files.
The site theme uses [Bootstrap](https://getbootstrap.com/) and [Sass](https://sass-lang.com/); [jQuery](https://jquery.com/) is available as more content is added we may need more UI features.
The [Cecil documentation](https://cecil.app/documentation/) is pretty great but here's a quick start guide:
### Local Development
1. Install [PHP 7.4](https://cecil.app/documentation/) or higher
2. [Download and install Cecil](https://cecil.app/download/)
3. Fork and/or clone the website repository at `git@gitlab.com:veilid-tc-hacking/veilid-dot-com.git`
4. In the project directory, run `cecil serve` to run the site locally on port 8000
5. Open `http://localhost:8000/` in your browser to view it
As you make changes to the code, Cecil will reload the website for you so you can see your changes as you work.
- `pages` contains the content for the website in markdown
- files in `static` get served off of `/` in the site URL
- the site theme is in `themes/veilid`
- the Sass files are in `themes/veilid/assets/scss` and get compiled into CSS for you by Cecil — please do not edit the CSS files directly
- `themes/veilid/static` get added to the static content directory
- `themes/veilid/layouts` has all the twig template files
- note that not all twig templates in the theme directory are used on the site
### Code Contribution Do's & Don'ts:
Keeping the following in mind gives your contribution the best chance of landing!
#### <u>Merge Requests</u>
* **Do** create a [feature branch] to work on instead of working directly on `main`. This helps to:
* Protect the process.
* Ensures users are aware of commits on the branch being considered for merge.
* Allows for a location for more commits to be offered without mingling with other contributor changes.
* Allows contributors to make progress while a MR is still being reviewed.
* **Do** follow the [50/72 rule] for Git commit messages.
* **Do** target your merge request to the **main branch**.
* **Do** specify a descriptive title to make searching for your merge request easier.
* **Do** list [verification steps] so your code is testable.
* **Do** reference associated issues in your merge request description.
* **Don't** leave your merge request description blank.
* **Don't** abandon your merge request. Being responsive helps us land your code faster.
* **Don't** submit unfinished code.
## Contributions Without Writing Code
There are numerous ways you can contribute to the growth and success of the Veilid project without writing code:
- Submit bugs as well as feature/enhancement requests. Letting us know you found a bug, have an idea for a new feature, or see a way we can enhance existing features is just as important and useful as writing the code related to those things. Send us detailed information about your issue or idea:
- Features/Enhancements: Describe your idea. If you're able to, sketch out a diagram or mock-up.
- Bugs: Please be sure to include the expected behavior, the observed behavior, and steps to reproduce the problem. Please be descriptive about the environment you've installed your node or application into.
- [Help other users with open issues]. Sometimes all an issue needs is a little conversation to clear up a process or misunderstanding. Please keep the [Code of Conduct](./code_of_conduct.md) in mind.
- Help other contributors test recently submitted merge requests. By pulling down a merge request and testing it, you can help validate new code contributions for stability and quality.
- Report a security or privacy vulnerability. Please let us know if you find ways in which Veilid could handle security and/or privacy in a different or better way. Surely let us know if you find broken or otherwise flawed security and/or privacy functions. You can report these directly to security@veilid.org.
- Add or edit documentation. Documentation is a living and evolving library of knowledge. As such, care, feeding, and even pruning is needed from time to time. If you're a non-native english speaker, you can help by replacing any ambiguous idioms, metaphors, or unclear language that might make our documentation hard to understand.
#### <u>Bug Fixes</u>
* **Do** include reproduction steps in the form of [verification steps].
* **Do** link to any corresponding issues in your commit description.
## Bug Reports
When reporting Veilid issues:
* **Do** write a detailed description of your bug and use a descriptive title.
* **Do** include reproduction steps, stack traces, and anything that might help us fix your bug.
* **Don't** file duplicate reports. Search open issues for similar bugs before filing a new report.
* **Don't** attempt to report issues on a closed PR. New issues should be openned against the `main` branch.
Please report vulnerabilities in Veilid directly to security@veilid.org.
If you're looking for more guidance, talk to other Veilid contributors on the [Veilid Discord].
**Thank you** for taking the few moments to read this far! Together we will build something truly remarkable.
This contributor guide is inspired by the contribution guidelines of the [Metasploit Framework](https://github.com/rapid7/metasploit-framework/blob/master/CONTRIBUTING.md) project found on GitHub.
[Help other users with open issues]:https://gitlab.com/veilid/veilid-dot-com/-/issues
[50/72 rule]:http://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html
[feature branch]:https://docs.gitlab.com/ee/gitlab-basics/feature_branch_workflow.html
[verification steps]:https://docs.gitlab.com/ee/user/markdown.html#task-lists
[Veilid Discord]:https://discord.gg/DmEGxyA87N

View File

@ -0,0 +1,22 @@
# veilid-dot-com
Important documents to read
- [Contributing](./CONTRIBUTING.md)
- [Code of Conduct](./code_of_conduct.md)
- [Cecil Documentation](https://cecil.app/documentation/)
## Website To-Do
The following are known issues or to-build items as of 2023-08-15
- [ ] Move this site to the main Veilid project in Gitlab
- [ ] Create an off-season location for DefCon pages
- [ ] Use Cecil's multi-language capabilities for translations
- Documentation and FAQs
- [ ] for lay people
- [ ] for technical people
- [ ] for cryptography people
- [ ] for legal entities

137
code_of_conduct.md Normal file
View File

@ -0,0 +1,137 @@
# Contributor Covenant Code of Conduct
## Our Pledge
We as members, contributors, and leaders pledge to make participation in our
community a harassment-free experience for everyone, regardless of age, body
size, visible or invisible disability, ethnicity, sex characteristics, gender
identity and expression, level of experience, education, socio-economic status,
nationality, personal appearance, race, caste, color, religion, or sexual
identity and orientation.
We pledge to act and interact in ways that contribute to an open, welcoming,
diverse, inclusive, and healthy community.
## Our Standards
Examples of behavior that contributes to a positive environment for our
community include:
* Demonstrating empathy and kindness toward other people
* Being respectful of differing opinions, viewpoints, and experiences
* Giving and gracefully accepting constructive feedback
* Accepting responsibility and apologizing to those affected by our mistakes,
and learning from the experience
* Focusing on what is best not just for us as individuals, but for the overall
community
Examples of unacceptable behavior include:
* The use of sexualized language or imagery, and sexual attention or advances of
any kind
* Trolling, insulting or derogatory comments, and personal or political attacks
* Public or private harassment
* Publishing others' private information, such as a physical or email address,
without their explicit permission
* Other conduct which could reasonably be considered inappropriate in a
professional setting
## Enforcement Responsibilities
Community leaders are responsible for clarifying and enforcing our standards of
acceptable behavior and will take appropriate and fair corrective action in
response to any behavior that they deem inappropriate, threatening, offensive,
or harmful.
Community leaders have the right and responsibility to remove, edit, or reject
comments, commits, code, wiki edits, issues, and other contributions that are
not aligned to this Code of Conduct, and will communicate reasons for moderation
decisions when appropriate.
## Scope
This Code of Conduct applies within all community spaces, and also applies when
an individual is officially representing the community in public spaces.
Examples of representing our community include using an official e-mail address,
posting via an official social media account, or acting as an appointed
representative at an online or offline event.
## Enforcement
Instances of abusive, harassing, or otherwise unacceptable behavior may be
reported to the community leaders responsible for enforcement at
[security@veilid.org](security@veilid.org).
All complaints will be reviewed and investigated promptly and fairly.
All community leaders are obligated to respect the privacy and security of the
reporter of any incident.
## Enforcement Guidelines
Community leaders will follow these Community Impact Guidelines in determining
the consequences for any action they deem in violation of this Code of Conduct:
### 1. Correction
**Community Impact**: Use of inappropriate language or other behavior deemed
unprofessional or unwelcome in the community.
**Consequence**: A private, written warning from community leaders, providing
clarity around the nature of the violation and an explanation of why the
behavior was inappropriate. A public apology may be requested.
### 2. Warning
**Community Impact**: A violation through a single incident or series of
actions.
**Consequence**: A warning with consequences for continued behavior. No
interaction with the people involved, including unsolicited interaction with
those enforcing the Code of Conduct, for a specified period of time. This
includes avoiding interactions in community spaces as well as external channels
like social media. Violating these terms may lead to a temporary or permanent
ban.
### 3. Temporary Ban
**Community Impact**: A serious violation of community standards, including
sustained inappropriate behavior.
**Consequence**: A temporary ban from any sort of interaction or public
communication with the community for a specified period of time. No public or
private interaction with the people involved, including unsolicited interaction
with those enforcing the Code of Conduct, is allowed during this period.
Violating these terms may lead to a permanent ban.
### 4. Permanent Ban
**Community Impact**: Demonstrating a pattern of violation of community
standards, including sustained inappropriate behavior, harassment of an
individual, or aggression toward or disparagement of classes of individuals.
**Consequence**: A permanent ban from any sort of public interaction within the
community.
## Attribution
This Code of Conduct is adapted from the [Contributor Covenant][homepage],
version 2.1, available at
[https://www.contributor-covenant.org/version/2/1/code_of_conduct.html][v2.1].
Community Impact Guidelines were inspired by
[Mozilla's code of conduct enforcement ladder][Mozilla CoC].
For answers to common questions about this code of conduct, see the FAQ at
[https://www.contributor-covenant.org/faq][FAQ]. Translations are available at
[https://www.contributor-covenant.org/translations][translations].
[homepage]: https://www.contributor-covenant.org
[v2.1]: https://www.contributor-covenant.org/version/2/1/code_of_conduct.html
[Mozilla CoC]: https://github.com/mozilla/diversity
[FAQ]: https://www.contributor-covenant.org/faq
[translations]: https://www.contributor-covenant.org/translations
## Revisions
Veilid Foundation, Inc reserves the right to make revisions to this document
to ensure its continued alignment with our ideals.

37
config.yml Normal file
View File

@ -0,0 +1,37 @@
title: Veilid
baseurl: 'https://veilid.com'
description: Veilid is a project by cDc and friends.
image: img/Veilid-Framework-Cover.png
debug: true
favicon:
enabled: true
image: /favicon.ico
compile:
enabled: true
style: compressed
sourcemap: true
theme:
- veilid
social:
twitter: "veilidnetwork"
fediverse: "@VeilidNetwork@hackers.town"
virtualpages:
- path: contact
redirect: /about-us/contact-us/
- path: discord
redirect: https://discord.gg/5Qx3B9eedU
- path: code
redirect: https://gitlab.com/veilid/veilid
- path: give
redirect: https://buy.stripe.com/6oE9ACboP5r3ag86oo
- path: launch
redirect: /defcon/
pagination:
max: 12
cache:
dir: '.cache'
enabled: false
languages:
- code: en
name: English
locale: en_US

21
netlify.toml Normal file
View File

@ -0,0 +1,21 @@
[build]
publish = "_site"
command = "curl -sSOL https://cecil.app/build.sh && bash ./build.sh"
[build.environment]
PHP_VERSION = "7.4"
[context.production.environment]
CECIL_ENV = "production"
[context.deploy-preview.environment]
CECIL_ENV = "preview"
[[headers]]
for = "/*"
[headers.values]
X-Frame-Options = "SAMEORIGIN"
X-XSS-Protection = "0"
X-Content-Type-Options = "nosniff"
Content-Security-Policy = "default-src 'self'; script-src 'self'"
X-Clacks-Overhead = "GNU Terry Pratchett"

39
pages/about-us/FAQ.md Normal file
View File

@ -0,0 +1,39 @@
---
title: F.A.Q.
description: Frequently asked questions about Veilid
weight: 6
layout: subpage
---
<ul>
<!--
<li>
<h3>Question</h3>
<p>Answer</p>
</li>
-->
<li>
<h3>Is Veilid looking for funding?</h3>
<p>Veilid is not seeking venture capital or investment. We are accepting tax-deductible donations to our non-profit foundation, Veilid Foundation Inc.</p>
</li>
<li>
<h3>Does Veilid have a cryptocurrency?</h3>
Heck no. Veilid does not have a cryptocurrency.
</li>
<li>
<h3>Does Veilid use AI?</h3>
Heck no. Veilid does not use AI.
</li>
<li>
<h3>Does Veilid use blockchain?</h3>
Heck no. Veilid does not use blockchain.
</li>
</ul>
<div class="clearfix my-2">&nbsp;</div>
<div class="focus-text text-center">
Have a question? Email <a href="mailto:press@veilid.org" class="text-white">press@veilid.org</a>
</div>

View File

@ -0,0 +1,13 @@
---
title: Community
description: Join our community of developers.
layout: subpage
weight: 3
---
We want to build a community people who want a better way to connect and communicate.
We want to bring together folks to help build great applications using the Veilid framework.
<a class="mt-3 btn btn-primary btn-lg" href="/discord">Join Us on Discord</a>

View File

@ -0,0 +1,18 @@
---
title: Contact Us
description: How to contact the Veilid project
layout: subpage
weight: 2
---
<h3>Contact Us</h3>
<p>For app support, please email <a href="mailto:support@veilid.com">support@veilid.com</a></p>
<h3>Social Media Accounts</h3>
<ul>
<li><a href="https://twitter.com/cdc_pulpit">cDc on Twitter</a></li>
<li><a href="https://twitter.com/VeilidNetwork">Veilid on Twitter</a></li>
<li><a href="https://bsky.app/profile/cultdeadcow.bsky.social">Veilid on BlueSky</a></li>
<li><a href="https://hackers.town/@veilidnetwork">Veilid on Fedi</a></li>
</ul>

78
pages/about-us/index.md Normal file
View File

@ -0,0 +1,78 @@
---
title: About Us
description: Meet the Veilid Foundation members leading the project as well as contributors.
menu:
main:
weight: 7
layout: subpage
weight: 1
---
<h3>
Veilid Foundation Members
</h3>
<div class="padded-box">
<h4 class="padded-box-title">Christien Rioux</h4>
<p>
Christien Rioux is the primary author and inventor of Veilid's core technology.
A long-time member and figure in the security industry and hacker scene,
Christien is a member of <a href="https://cultdeadcow.com/members.html">CULT OF THE DEAD COW</a>,
and formerly <a href="https://web.archive.org/web/20010118210000/http://www.l0pht.com/">L0pht Heavy Industries</a>,
the formative hacker think-tank.
He has been a company founder and published numerous security tools and advisories over the years,
and is also proprietor of the hacker-fashion line <a href="https://www.hack.xxx/">HACK.XXX</a>.
Christien is a staunch believer that if you want to change the present you need to build the future.
</p>
</div>
<div class="padded-box">
<h4 class="padded-box-title">Katelyn Bowden</h4>
<p>
Katelyn Bowden is a hacker, activist, and <a href="https://cultdeadcow.com/members.html">CULT OF THE DEAD COW</a> member, who embraces the human side of hacking and tech.
Katelyn has dedicated her life to changing the world for the positive- between her work fighting Non-consensual pornography, and her dedication to educating users on security, she is dedicated to making the internet a safer place for everyone. Her alignment is chaotic good, with a hard emphasis on the chaos.
She also creates strange furby art and has over 60 dead things on display in her house.
</p>
</div>
<div class="padded-box">
<h4 class="padded-box-title">Paul Miller</h4>
<p>
Paul Miller is the founder/leader/community organizer of
<a href="https://hackers.town">hackers.town</a>,
<a href="https://home.oniprojekt.ninja/">Projekt:ONI</a> (Optimistic Nihilists Inc.) organizer and founder, Hacker, Infosec professional, and is a passionate privacy advocate. Paul has worked to show the ways a centralized internet has harmed our culture and the future. He believes you should always be N00bin', and that collectively we can restore the promise of the future the internet once offered us.
</p>
</div>
### Contributors
Veilid contributors include coders, admins, writers, legal, and more.
<ul class="col-list">
<li>TC Johnson</li>
<li>Jun34u, cDc</li>
<li>DethVeggie, cDc</li>
<li>Beka Valentine</li>
<li>signal9</li>
<li>Obscure, cDc</li>
<li>Alice 'c0debabe' Rhodes</li>
<li>Abbie 'antijingoist' Gonzalez</li>
<li>snowchyld, NsF</li>
<li>John 'Wrewdison' Whelan</li>
<li>Robert "LambdaCalculus" Menes</li>
<li>Julie Chandler</li>
<li>Glenn Kurtzrock</li>
<li>Daniel Meyerson</li>
<li>CylentKnight</li>
<li>Robert 'Slugnoodle' Notarfrancesco</li>
</ul>
### Special Thanks
A heart-felt thank you to our families and friends for <strike>putting up with</strike> supporting us.

27
pages/about-us/press.md Normal file
View File

@ -0,0 +1,27 @@
---
title: Press
description: Information for the press and media about Veilid
layout: subpage
weight: 4
---
### Press Kit
PDF press summary: <a href="/Veilid-Framework-Press-Kit.pdf">Veilid Framework Press Kit</a>, 20.6 kB
### Press Contact
Press and media inquiries should be sent to <a href="mailto:press@veilid.org">press@veilid.org</a>
### In The News
<ul>
<li>“Americas Original Hacking Supergroup Creates a Free Framework to Improve App Security.” <i>Engadget</i>, <a href="https://www.engadget.com/americas-original-hacking-supergroup-creates-a-free-framework-to-improve-app-security-190043865.html">https://www.engadget.com/americas-original-hacking-supergroup-creates-a-free-framework-to-improve-app-security-190043865.html</a>. Accessed 11 Aug. 2023.</li>
<li><i>Cult of Dead Cow Hacktivists Design Encryption System for Mobile Apps - Play Crazy Game</i>. 2 Aug. 2023, <a href="https://playcrazygame.com/blog/2023/08/02/cult-of-dead-cow-hacktivists-design-encryption-system-for-mobile-apps/">https://playcrazygame.com/blog/2023/08/02/cult-of-dead-cow-hacktivists-design-encryption-system-for-mobile-apps/</a>.</li>
<li>“Cult of the Dead Cow Launches Encryption Protocol to Save Your Privacy.” <i>Gizmodo</i>, 2 Aug. 2023, <a href="https://gizmodo.com/cult-of-the-dead-cow-launches-veilid-encryption-project-1850699803">https://gizmodo.com/cult-of-the-dead-cow-launches-veilid-encryption-project-1850699803</a>.</li>
<li>“Cult of the Dead Cow Wants to Save Internet Privacy with a New Encryption Protocol.” <i>Yahoo News</i>, 2 Aug. 2023, <a href="https://news.yahoo.com/cult-dead-cow-wants-save-203200064.html">https://news.yahoo.com/cult-dead-cow-wants-save-203200064.html</a>.</li>
<li>Hemant, Kumar. “Hacktivist Group CDc to Unveil Veilid Encryption for Privacy-First Apps.” <i>Candid.Technology</i>, 2 Aug. 2023, <a href="https://candid.technology/veilid-encryption-cdc-cult-of-dead-cow/">https://candid.technology/veilid-encryption-cdc-cult-of-dead-cow/</a>.</li>
<li>Johnson, Donovan. “Cult of the Dead Cow Develops Coding Framework for Privacy-Focused Apps.” <i>Fagen Wasanni Technologies</i>, 2 Aug. 2023, <a href="https://fagenwasanni.com/ai/cult-of-the-dead-cow-develops-coding-framework-for-privacy-focused-apps/106537/">https://fagenwasanni.com/ai/cult-of-the-dead-cow-develops-coding-framework-for-privacy-focused-apps/106537/</a>.</li>
<li>Long, Heinrich. “Prominent Hacktivists to Launch Secure Messaging Framework Veilid.” <i>RestorePrivacy</i>, 5 Aug. 2023, <a href="https://restoreprivacy.com/prominent-hacktivists-to-launch-secure-messaging-framework-veilid/">https://restoreprivacy.com/prominent-hacktivists-to-launch-secure-messaging-framework-veilid/</a>.</li>
<li>Menn, Joseph. “Hacking Group Plans System to Encrypt Social Media and Other Apps.” <i>Washington Post</i>, 2 Aug. 2023. <i>www.washingtonpost.com</i>, <a href="https://www.washingtonpost.com/technology/2023/08/02/encryption-dead-cow-cult-apps-def-con/">https://www.washingtonpost.com/technology/2023/08/02/encryption-dead-cow-cult-apps-def-con/</a>.</li>
<li>RHC, Redazione. “Cult of the dead Cow presenta il protocollo Veilid. Una nuova alternativa al capitalismo della sorveglianza.’” <i>Red Hot Cyber</i>, 3 Aug. 2023, <a href="https://www.redhotcyber.com/post/cult-of-the-dead-cow-presenta-il-protocollo-veilid-una-nuova-alternativa-al-capitalismo-della-sorveglianza/">https://www.redhotcyber.com/post/cult-of-the-dead-cow-presenta-il-protocollo-veilid-una-nuova-alternativa-al-capitalismo-della-sorveglianza/</a>.</li>
</ul>

24
pages/chat/index.md Normal file
View File

@ -0,0 +1,24 @@
---
title: VeilidChat
description: VeilidChat is a proof of concept of the Veilid protocol and framework.
menu:
main:
weight: 5
weight: 1
layout: subpage
---
VeilidChat is a demo of the Veilid framework and protocol working.
We built it using the [Flutter](https://flutter.dev/) framework and the Veilid core code.
If you want to try out this proof of concept, please stay tuned for details on how to gain access.
### Source Code
You can get the code for Veilid Chat at https://gitlab.com/veilid/veilidchat
### Support
<p>For app support, please email <a href="mailto:support@veilid.com">support@veilid.com</a></p>

View File

@ -0,0 +1,189 @@
---
title: Privacy Policy
description: The privacy policy for VeilidChat
weight: 2
layout: subpage
---
### VeilidChat Privacy Policy
Last Revised 2023 Aug 3
This privacy notice for the Veilid Foundation ("Veilid," "we," "us," or "our"), describes how and why we might collect, store, use, and/or share ("process") your information when you use our services ("Services"), such as when you:
- Download and use our mobile application (VeilidChat), or any other application of ours that links to this privacy notice in the future.
Reading this privacy notice will help you understand your privacy rights and choices. If you do not agree with our policies and practices, please do not use VeilidChat. If you still have any questions or concerns, please contact us at [support@veilid.com](mailto:support@veilid.com).
<h4 id="summary">Summary of Key Points</h4>
- VeilidChat is a messaging application built on a decentralized, distributed, and end-to-end fully encrypted framework.
- VeilidChat is a proof-of-concept application in beta-testing and you must receive an invitation to activate the application.
- VeilidChat will never ask you for contact information, personal information, or financial information.
- When you register and use VeilidChat, any information entered into the app is either stored locally on your device, or encrypted and distributed in a method that is inaccessible and irretrievable by the Veilid Foundation (the creators of the application).
- We do not collect or process any personal information, nor do we have the capability to collect or process any personal information from VeilidChat.
- We do not collect or process sensitive personal information, nor do we have the capability to collect or process any sensitive information from VeilidChat.
- We do not receive or transmit any information to or from third parties.
- The Veilid Framework processes encrypted and distributed information to provide and administer services for VeilidChat.
- We do not share personal information. Because of the encrypted and distributed nature of information entered into the VeilidChat app, we are unable to access your personal information.
- How do we keep your information safe? We have organizational and technical processes and procedures in place to protect your personal information. However, no electronic transmission over the internet or information storage technology can be guaranteed to be 100% secure, so we cannot promise or guarantee that unauthorized third parties will not be able to defeat our security and improperly collect, access, steal, or modify your information.
- VeilidChat will provide you with a recovery pass-phrase to use in the event that your app is deleted or your device is no longer available/functional for you. If you cannot access this pass-phrase, you will have to create a new account. The Veilid Foundation is unable to restore your account through any means.
- How do you exercise your rights? The easiest way to exercise your rights is to delete VeilidChat. The Veilid Foundation is a non-profit organization that does not collect, process, or use any of your information. You may contact us by visiting https://veilid.com/contact, or by emailing [support@veilid.com](mailto:support@veilid.com). We will consider and act upon any request in accordance with applicable data protection laws.
<h4 id="table-of-contents">Table of Contents</h4>
1. [What Information Do We Collect?](#section-1)
1. [How Do We Process Your Information?](#section-2)
1. [What Legal Bases Do We Rely On To Process Your Personal Information?](#section-3)
1. [When And With Whom Do We Share Your Personal Information?](#section-4)
1. [How Long Do We Keep Your Information?](#section-5)
1. [How Do We Keep Your Information Safe?](#section-6)
1. [Do We Collect Information From Minors?](#section-7)
1. [What Are Your Privacy Rights?](#section-8)
1. [Controls For Do-not-track Features](#section-9)
1. [US State-specific Privacy Rights](#section-10)
1. [Do We Make Updates To This Notice?](#section-11)
1. [How Can You Contact Us About This Notice?](#section-12)
1. [How Can You Review, Update, Or Delete The Data We Collect From You?](#section-13)
1. [Cookie And Data Analytics Disclosures](#section-14)
<h4 id="section-1">1. What information do we collect?</h4>
VeilidChat collects no information from you. VeilidChat is designed to not collect your information and to operate in an encrypted, distributed manner, which means we cannot access your information even if we wanted to (which we dont). Any information you enter into VeilidChat on your device is inaccessible to us.
The Veilid Foundation only collects personal information that you voluntarily provide to us when you request an invitation to the beta version of the application. This will only be the contact information necessary for us to send you an invitation. This process is managed by the Apple App Store and the Veilid Foundation only retains this information long enough to provide it to the Apple App Store to generate an invitation.
<h4 id="section-2">2. How do we process your information?</h4>
We dont. VeilidChat does not collect your information, nor are we able to collect it. Administration of, improvements to, and changes to the VeilidChat application will be made without any processing of personal information. The Veilid Foundation will never ask you for personal, sensitive, or financial information.
If you provide any information to us at [support@veilid.com](mailto:support@veilid.com), though our Discord server, through our website at https://veilid.com/contact, or directly via postal mail to our foundation, we will only process that information to answer your questions or attempt to support your issues, with two major exceptions:
- Legal Obligations. We may process information sent to us via email, our website, or via postal mail where we believe it is necessary for compliance with our legal obligations, such as to cooperate with a law enforcement body or regulatory agency, exercise or defend our legal rights, or disclose your information as evidence in litigation in which we are involved.
- Vital Interests. We may process information sent to us via email, our website, or via postal mail where we believe it is necessary to protect your vital interests or the vital interests of a third party, such as situations involving potential threats to the safety of any person.
<h4 id="section-3">3. What legal bases do we rely on to process uour information?</h4>
VeilidChat does not process any personal information. Because the Veilid Foundation cannot access information entered into VeilidChat in any way, shape, or form, the Veilid Foundation does not process your information.
As for information sent to the Veilid Foundation via email, Discord server, postal mail, or through our website, we only process your personal information when we believe it is necessary and we have a valid legal reason (i.e.,legal obligations) to do so under applicable law, to comply with laws, to protect your rights, or to fulfill our legitimate business interests.
<strong>If you are located in the EU or UK, this section applies to you.</strong>
The General Data Protection Regulation (GDPR) and UK GDPR require us to explain the valid legal bases we rely on in order to process your personal information. VeilidChat does not collect or process personal information. For any information that is sent directly to the Veilid Foundation, we may rely on the following legal bases to process your personal information:
- Consent. The Veilid Foundation may process your information if you have given us specific permission (i.e. consent) to use your personal information for a specific purpose. This is generally limited to contacting us and requesting an invite code to the beta version of the application, however, the Veilid Foundation does not store this information. Apple, through the App Store, will manage the invitation process. Your contact information cannot be linked to your VeilidChat account by the Veilid Foundation. You can withdraw your consent to Apple at any time.
- Legal Obligations. We may process your information where we believe it is necessary for compliance with our legal obligations, such as to cooperate with a law enforcement body or regulatory agency, exercise or defend our legal rights, or disclose your information as evidence in litigation in which we are involved.
- Vital Interests. We may process your information where we believe it is necessary to protect your vital interests or the vital interests of a third party, such as situations involving potential threats to the safety of any person.
<strong>If you are located in Canada, this section applies to you.</strong>
VeilidChat does not collect or process personal information. For any information that is sent directly to the Veilid Foundation, we may rely on the following legal bases to process your personal information:
We may process your information if you have given us specific permission (i.e., express consent) to use your personal information for a specific purpose, or in situations where your permission can be inferred (i.e., implied consent). This is generally limited to contacting us and requesting an invite code to the beta version of the application. Apple, through the App Store, will manage the invitation process. Your contact information cannot be linked to your VeilidChat account by the Veilid Foundation. You can withdraw your consent to Apple at any time.
- In some exceptional cases, we may be legally permitted under applicable law to process your information without your consent, including, for example:
- If collection is clearly in the interests of an individual and consent cannot be obtained in a timely way
- For investigations and fraud detection and prevention
- If it is contained in a witness statement and the collection is necessary to assess, process, or settle an insurance claim
- For identifying injured, ill, or deceased persons and communicating with next of kin
- If we have reasonable grounds to believe an individual has been, is, or may be victim of financial abuse
- If it is reasonable to expect collection and use with consent would compromise the availability or the accuracy of the information and the collection is reasonable for purposes related to investigating a breach of an agreement or a contravention of the laws of Canada or a province
- If disclosure is required to comply with a subpoena, warrant, court order, or rules of the court relating to the production of records
- If it was produced by an individual in the course of their employment, business, or profession and the collection is consistent with the purposes for which the information was produced
- If the collection is solely for journalistic, artistic, or literary purposes
- If the information is publicly available and is specified by the regulations
<h4 id="section-4">4. When and with whom do we share your personal information?</h4>
In no way, shape, or form do we ever share your personal information. We cannot share what we do not retain, or what we cannot access.
- Business Transfers. In the event of any merger, sale, or acquisition of any portion of the Veilid Foundation, the Veilid Foundation will provide updates on our website or through application updates for the VeilidChat application through the App Store. Because the Velid Foundation does not collect any personal information, we have no other methods to provide this information to you.
<h4 id="section-5">5. How long do we keep your information?</h4>
We keep your information for as long as necessary to fulfill the purposes outlined in this privacy notice unless otherwise required by law. However, in most cases, we are incapable of retaining information because we do not collect it.
The Veilid Foundation will only keep your personal information for as long as it is necessary for the purposes set out in this privacy notice, unless a longer retention period is required by law. VeilidChat will retain a local copy of your information (accessible only to your device and the people you directly share information with) for as long as you utilize the application. In future iterations of the application, there will be a “delete messages after a certain period of time” functionality, but for the beta testing proof-of-concept, this functionality has not been introduced.
<h4 id="section-6">6. How do we keep your information safe?</h4>
We have implemented appropriate and reasonable technical and organizational security measures designed to protect the security of any personal information we process. However, despite our safeguards and efforts to secure your information, no electronic transmission over the Internet or information storage technology can be guaranteed to be 100% secure, so we cannot promise or guarantee that any unauthorized third parties will not be able to defeat our security and improperly collect, access, steal, or modify your information.
Although we will do our best to protect your personal information, transmission of personal information to and from Velid Chat is at your own risk. You should only access VeilidChat within a secure environment. If you lose access to your device, the Velid Foundation cannot access or delete information stored there.
<h4 id="section-7">7. Do we collect information from minors?</h4>
We do not collect information from or market to anyone. If you suspect that someone underage is violating the Apple App Store terms of service by downloading VeilidChat, please contact Apple at Support.Apple.com.
<h4 id="section-8">8. What are your privacy rights?</h4>
In some regions (like the EEA, UK, and Canada), you have certain rights under applicable data protection laws. These may include the right (i) to request access and obtain a copy of your personal information, (ii) to request rectification or erasure; (iii) to restrict the processing of your personal information; and (iv) if applicable, to data portability. In certain circumstances, you may also have the right to object to the processing of your personal information.
However, due to the unique nature of VeilidChat, the only information available is stored locally on the users device and is inaccessible by the Veilid Foundation. VeilidChat does not collect or process any personal information. If a user wishes to exercise their data rights, they may copy any data within the VeilidChat application and export it themselves, or delete the application from their device. The Veilid Foundation has no access to any users data.
We will consider and act upon any request in accordance with applicable data protection laws.
If you are located in the EEA or UK and you believe we are unlawfully processing your personal information, you also have the right to complain to your Member State data protection authority or UK data protection authority.
If you are located in Switzerland, you may contact the Federal Data Protection and Information Commissioner.
##### Account Information
If you would at any time like to review or change the information in your account or terminate your account, you can:
- Log in to your account settings and update your user account.
- Delete the application from your device.
Upon your decision to delete the application from your device, it will no longer be able to be accessed by anyone, including the creators of the application. Any data still in existence will be encrypted, distributed, and inaccessible by any party.
However, we may retain some information that is sent directly to the Veilid Foundation via email, our website, our Discord server, or via post mail in our files to prevent fraud, troubleshoot problems, assist with any investigations, enforce our legal terms and/or comply with applicable legal requirements.
If you have questions or comments about your privacy rights, you may email us at [support@veilid.com](mailto:support@veilid.com).
<h4 id="section-9">9. Controls for Do-Not-track Features</h4>
Most web browsers and some mobile operating systems and mobile applications include a Do-Not-Track ("DNT") feature or setting you can activate to signal your privacy preference not to have data about your online browsing activities monitored and collected. VeilidChat is compliant with this technology because we do not monitor, track, collect, or process any information.
<h4 id="section-10">10. US State-Specific Privacy Rights</h4>
- California (knows how to party):
- We do not sell, rent, or share information with anyone, including third parties who engage in direct marketing activities. We do not collect or share your information with anyone, for any reason. No marketing, no third party sharing, nothing.
- VeilidChat has no ability to post public information. If you are under 18 years of age, reside in California, and have a registered account with VeilidChat, you can delete the application on your device and that will serve to exercise your rights to deletion.
- Please note that the Veilid Foundation and the VeilidChat application HAVE NOT collected, rented, shared, or sold any personal information from any individual, and especially not within the past 12 months.
- De-identified Data Disclosure (CA, CO, CT, UT, VA and soon to be more)
- We may use de-identified data in certain circumstances. In those circumstances, not only do we never attempt to re-identify that data, but we are completely unable to re-identify any data because of our encryption and distributed data frameworks.
- Profiling Disclosure (Hi Colorado!)
- We do not engage in profiling of consumers in any way, shape, or form. We especially dont do it in a way that supports automated decisions that might have a legal or significant effect on anyone.
<h4 id="section-11">11. Do we make updates to this notice?</h4>
We will update this notice as necessary to stay compliant with relevant laws and as it relates to new features or products available.
The updated version will be indicated by an updated "Revised" date and the updated version will be effective as soon as it is accessible. If we make material changes to this privacy notice, we may notify you either by prominently posting a notice of such changes on the Veilid Foundations website, or by providing an updated policy through the Apple App Store as part of any version updates. Because we do not collect your information, we are unable to directly contact you. We encourage you to review this privacy notice frequently to be informed of how we are protecting your information.
<h4 id="section-12">12. How can you contact us about this notice?</h4>
If you have questions or comments about this notice, you may email us at [support@veilid.com](mailto:support@veilid.com) or contact us by post at:
<pre>
Veilid Foundation
PO BOX 1593
Madison AL
35758
</pre>
<h4 id="section-13">13. How can you review, update, or delete the data we collect from you?</h4>
The only effective method to review, update, or delete any of your data is locally on the VeilidChat application on your device. The Veilid Foundation is unable to collect or access your information through the VeilidChat application and thus does not have the ability to review, update, or delete information that we do not possess.
<h4 id="section-14">14. Cookie and Data Analytics Disclosure</h4>
We dont use cookies. We dont use data analytics. You can check on our website.

View File

@ -0,0 +1,143 @@
---
title: Code of Conduct
description: Veilid community and developer code of conduct
weight: 2
layout: subpage
---
Our code of conduct on the Contributor Covenant Code of Conduct and will be updated as needed.
Questions, comments, or concerns about the code of conduct may be sent to
<a href="mailto:security@veilid.org">security@veilid.org</a>.
## Our Pledge
We as members, contributors, and leaders pledge to make participation in our
community a harassment-free experience for everyone, regardless of age, body
size, visible or invisible disability, ethnicity, sex characteristics, gender
identity and expression, level of experience, education, socio-economic status,
nationality, personal appearance, race, caste, color, religion, or sexual
identity and orientation.
We pledge to act and interact in ways that contribute to an open, welcoming,
diverse, inclusive, and healthy community.
## Our Standards
Examples of behavior that contributes to a positive environment for our
community include:
* Demonstrating empathy and kindness toward other people
* Being respectful of differing opinions, viewpoints, and experiences
* Giving and gracefully accepting constructive feedback
* Accepting responsibility and apologizing to those affected by our mistakes,
and learning from the experience
* Focusing on what is best not just for us as individuals, but for the overall
community
Examples of unacceptable behavior include:
* The use of sexualized language or imagery, and sexual attention or advances of
any kind
* Trolling, insulting or derogatory comments, and personal or political attacks
* Public or private harassment
* Publishing others' private information, such as a physical or email address,
without their explicit permission
* Other conduct which could reasonably be considered inappropriate in a
professional setting
## Enforcement Responsibilities
Community leaders are responsible for clarifying and enforcing our standards of
acceptable behavior and will take appropriate and fair corrective action in
response to any behavior that they deem inappropriate, threatening, offensive,
or harmful.
Community leaders have the right and responsibility to remove, edit, or reject
comments, commits, code, wiki edits, issues, and other contributions that are
not aligned to this Code of Conduct, and will communicate reasons for moderation
decisions when appropriate.
## Scope
This Code of Conduct applies within all community spaces, and also applies when
an individual is officially representing the community in public spaces.
Examples of representing our community include using an official e-mail address,
posting via an official social media account, or acting as an appointed
representative at an online or offline event.
## Enforcement
Instances of abusive, harassing, or otherwise unacceptable behavior may be
reported to the community leaders responsible for enforcement at
[INSERT CONTACT METHOD].
All complaints will be reviewed and investigated promptly and fairly.
All community leaders are obligated to respect the privacy and security of the
reporter of any incident.
## Enforcement Guidelines
Community leaders will follow these Community Impact Guidelines in determining
the consequences for any action they deem in violation of this Code of Conduct:
### 1. Correction
**Community Impact**: Use of inappropriate language or other behavior deemed
unprofessional or unwelcome in the community.
**Consequence**: A private, written warning from community leaders, providing
clarity around the nature of the violation and an explanation of why the
behavior was inappropriate. A public apology may be requested.
### 2. Warning
**Community Impact**: A violation through a single incident or series of
actions.
**Consequence**: A warning with consequences for continued behavior. No
interaction with the people involved, including unsolicited interaction with
those enforcing the Code of Conduct, for a specified period of time. This
includes avoiding interactions in community spaces as well as external channels
like social media. Violating these terms may lead to a temporary or permanent
ban.
### 3. Temporary Ban
**Community Impact**: A serious violation of community standards, including
sustained inappropriate behavior.
**Consequence**: A temporary ban from any sort of interaction or public
communication with the community for a specified period of time. No public or
private interaction with the people involved, including unsolicited interaction
with those enforcing the Code of Conduct, is allowed during this period.
Violating these terms may lead to a permanent ban.
### 4. Permanent Ban
**Community Impact**: Demonstrating a pattern of violation of community
standards, including sustained inappropriate behavior, harassment of an
individual, or aggression toward or disparagement of classes of individuals.
**Consequence**: A permanent ban from any sort of public interaction within the
community.
## Attribution
This Code of Conduct is adapted from the [Contributor Covenant][homepage],
version 2.1, available at
[https://www.contributor-covenant.org/version/2/1/code_of_conduct.html][v2.1].
Community Impact Guidelines were inspired by
[Mozilla's code of conduct enforcement ladder][Mozilla CoC].
For answers to common questions about this code of conduct, see the FAQ at
[https://www.contributor-covenant.org/faq][FAQ]. Translations are available at
[https://www.contributor-covenant.org/translations][translations].
[homepage]: https://www.contributor-covenant.org
[v2.1]: https://www.contributor-covenant.org/version/2/1/code_of_conduct.html
[Mozilla CoC]: https://github.com/mozilla/diversity
[FAQ]: https://www.contributor-covenant.org/faq
[translations]: https://www.contributor-covenant.org/translations

49
pages/contribute/index.md Normal file
View File

@ -0,0 +1,49 @@
---
title: Contribute
description: Learn about all the ways you can help Veilid
menu:
main:
weight: 6
weight: 1
layout: subpage
---
### How You Can Help
<ul>
<li>
<h4>Coders And Hackers</h4>
We can use more low-level programmers and protocol experts. Platform experts.
We want this system to work well for everyone and be a strong foundation for
general computing and application development.
</li>
<li>
<h4>App Developers</h4>
You can get started writing a Veilid app today! Got a game idea? Want to port
something from a centralized system to a decentralized one? Lets make this happen!
</li>
<li>
<h4>Usability Experts</h4>
We want to make sure that the framework and apps built with it are accessible to everyone.
Everyone should be able to make use of Veilid without even realizing theyre doing it.
</li>
<li>
<h4>Translators</h4>
Veilid technology is for everyone. Help us reach more people by helping us make sure as
many people as possible can read the documentation and use the applications.
</li>
<li>
<h4>Open Source and Governance</h4>
Open source projects deserve to be managed in the open too. Weve got an open RFC process for our design and an MPL-2.0 license that ensures that free and commercial entities can contribute safely and legally.
</li>
<li>
<h4><span title="Donations, but spell with a dollar sign for the letter s">Donation$</span></h4>
Cash works, too. Donations are tax-deductible. <a href="/give">Support Veilid</a>
</li>
</ul>
### Get Started
Please read our <a href="/contribute/code-of-conduct/">Code of Conduct</a> and then join us on our discord.
<a href="/discord" class="btn btn-primary btn-lg">Veilid Discord</a>

27
pages/defcon/index.md Normal file
View File

@ -0,0 +1,27 @@
---
title: DefCon
description: Veilid is launching at DefCon 31 in Las Vegas
layout: subpage
menu:
main:
weight: 2
weight: 1
---
<div class="row g-5">
<div class="col-12 col-md-7">
<p>We're premiering Veilid at Def Con 31 in Las Vegas!</p>
<p>
The <a href="/defcon/talk/">launch talk</a> and
<a href="/defcon/lab/">demo lab</a> targeted more at developers and other technical folks.</p>
<p><a href="/defcon/party/">The party</a> is for anyone attending the conference.</p>
</div>
<div class="col-12 col-md-5">
<div class="defcon">
<a href="https://defcon.org/html/defcon-31/dc-31-index.html"><img src="/img/defcon31-logo-gradient.png" alt="DefCon 31 Logo" class="img-fluid" /></a>
</div>
</div>
</div>

24
pages/defcon/lab.md Normal file
View File

@ -0,0 +1,24 @@
---
title: Demo Lab
description: TC and Veggie demonstrated how to communicate with Veilid
weight: 3
layout: subpage
---
### Veilid
#### A Demo Lab
##### Who
TC Johnson &amp; Deth Veggie
##### Where &amp; When
Saturday August 12, 10:00 11:55, Committee Boardroom, Forum
##### What
Veilid is a new, distributed communication protocol developed by Cult of the Dead Cow's Dildog (of BO2K fame). This p2p, E2EE, distributed protocol is being released at Defcon 31, fully open source, and with an example app called Veilid Chat. These demos will cover setting up an identity, connecting to others, deploying heavy nodes to support the network, and contributing to the project.
[Official Forum Page](https://forum.defcon.org/node/246329)

71
pages/defcon/party.md Normal file
View File

@ -0,0 +1,71 @@
---
title: Veilid Launch Party
description: There ain't no party like a cDc party; join us to celebrate the launch of the Veilid framework.
weight: 4
layout: subpage
---
<pre>(Begin transmission)</pre>
<div class="row justify-content-center">
<div class="col-12 col-md-6">
<img src="/img/break-the-internet.jpg" alt="Veilid Launch Party Flyer, Details Listed Below" class="img-fluid">
</div>
</div>
<div class="card my-4">
<div class="card-header">
<h3 class="card-title m-0 fs-4">
<span class="text-uppercase">Cult of the Dead Cow</span> breaks the internet!!
</h3>
</div>
<div class="card-body">
<p>And you can too!</p>
<ul class="list-inline justify-content-between">
<li class="list-inline-item">Cash Bar</li>
<li class="list-inline-item">Book Signings</li>
<l class="list-inline-item"i>Contests</li>
<li class="list-inline-item">Live Music</li>
<li class="list-inline-item">Shenanigans</li>
<li class="list-inline-item">No Raw Meat!</li>
</ul>
<table class="event-table">
<tr>
<th scope="row">Where</th>
<td>
Forums 105,136
</td>
</tr>
<tr>
<th scope="row">When</th>
<td>Friday, August 11. 8pm to Midnight. </td>
</tr>
<tr>
<th scope="row" class="text-nowrap">Dress Code</th>
<td>
Recommended (but not required) dress code- y2k 31337 Haxxor threads.
Think Zero Cool and Acid Burn meet Max Headroom and Franken Gibe.
There is no contest, but the Bovine Mother is watching, so make her proud.
</td>
</tr>
<tr>
<th scope="row" class="text-nowrap">Schedule</th>
<td>
<ul>
<li><span class="text-nowrap">20:00 - 20:45 &mdash;</span> <span class="text-nowrap">Jackalope</span></li>
<li><span class="text-nowrap">20:45 - 21:30 &mdash;</span> <span class="text-nowrap">DotorNot</span></li>
<li><span class="text-nowrap">21:30 - 21:15 &mdash;</span> <span class="text-nowrap">cDc/Veilid</span></li>
<li><span class="text-nowrap">21:15 - 22:45 &mdash;</span> <span class="text-nowrap">Rocky Rivera &amp; DJ Roza</span></li>
<li><span class="text-nowrap">22:45 - 23:30 &mdash;</span> <span class="text-nowrap">EVA</span></li>
<li><span class="text-nowrap">23:30 - Close &mdash;</span> <span class="text-nowrap">DJ McGrew</span></li>
</ul>
</td>
</tr>
</table>
<p><a href="https://forum.defcon.org/node/245832">DefCon Forum Post</a></p>
</div>
</div>
<h3>The herd hath spoken. ooMen.</h3>
<pre>(End transmission)</pre>

24
pages/defcon/talk.md Normal file
View File

@ -0,0 +1,24 @@
---
title: Launch Talk
description: Dildog and Medus4 go over the how's and why's of Veilid in "The Internals of Veilid"
weight: 2
layout: subpage
---
### The Internals of Veilid
#### A New Decentralized Application Framework
##### Who
Christien 'DilDog' Rioux and Katelyn 'Medus4' Bowden at DefCon 31
[Launch-Slides-Veilid.pdf](/Launch-Slides-Veilid.pdf)
##### Where &amp; When
Friday, August 11 at 09:00; Track 1
##### What
Attend our presentation of Veilid: an open-source, peer-to-peer, mobile-first networked application framework. Talk covers how it works as a protocol, structures, cryptography, and how to write applications.
[Official Forum Page](https://forum.defcon.org/node/246124)

View File

@ -0,0 +1,35 @@
---
title: Code Repositories
description: The code base for the different parts and tools of Veilid
weight: 3
layout: subpage
---
### Veilid Framework
#### Getting Started
Please recursively check out the project using this command
`git clone --recurse-submodules git@gitlab.com:veilid/veilid.git`
Then read the [development](https://gitlab.com/veilid/veilid/-/blob/main/DEVELOPMENT.md) guide to get started.
#### About the Code Repo
The main repository is located at https://gitlab.com/veilid/veilid and includes several components
- `veilid-core` - the main Veilid crate: https://crates.io/crates/veilid-core
- `veilid-tools` - misc functions for veilid and friends: https://crates.io/crates/veilid-tools
- `veilid-wasm` - Veilid bindings for webassembly: https://crates.io/crates/veilid-wasm
- `veilid-flutter` - Veilid bindings for Flutter/Dart. Comes with an example program: https://crates.io/crates/veilid-flutter
- Also `veilid-server` and `veilid-cli` source are also in this repo for building headless nodes
### Packages
If you want to install `veilid-server` and `veilid-cli` from package repositories,
please refer to our [instructions](/docs/package-repositories/).
### VeilidChat
The code for VeilidChat will be available at https://gitlab.com/veilid/veilidchat once we're recovered from DefCon.

19
pages/docs/index.md Normal file
View File

@ -0,0 +1,19 @@
---
title: Documentation
description: Documentation for Veilid framework and protocol
menu:
main:
weight: 4
weight: 1
layout: subpage
---
The documentation is currently a work in progress.
Here's what we've got so far:
- [Rust documentation](https://docs.rs/releases/search?query=veilid)
Are you good at writing? <a href="/about-us/community/">We could use your help</a>.

View File

@ -0,0 +1,47 @@
---
title: Package Repositories
description: Veilid has Rust, Python, Debian, and Fedora packages available.
weight: 4
layout: subpage
---
To run a "headless" Veilid node, you can install `veilid-server` and `veilid-cli` from repositories.
<h3>Debian Based Systems</h3>
<div class="code-snippet">
<input aria-label="Get Keys" type="text" readonly value="wget -O- https://packages.veilid.net/gpg/veilid-packages-key.public | sudo gpg --dearmor -o /usr/share/keyrings/veilid-packages-keyring.gpg">
<button class="btn btn-secondary"><span>Copy</span></button>
</div>
<p>Note: The key's fingerprint is <code>516C76D1E372C5C96EE54E22AE0E059BC64CD052</code></p>
<div class="code-snippet">
<input aria-label="Add Keys" type="text" readonly value='echo "deb [arch=amd64 signed-by=/usr/share/keyrings/veilid-packages-keyring.gpg] https://packages.veilid.net/apt stable main" > /etc/apt/sources.list.d/veilid.list'>
<button class="btn btn-secondary"><span>Copy</span></button>
</div>
<div class="code-snippet">
<input aria-label="Run Updates" type="text" readonly value="apt update">
<button class="btn btn-secondary"><span>Copy</span></button>
</div>
<div class="code-snippet">
<input aria-label="Install the headless and command line utilities" type="text" readonly value="apt install veilid-server veilid-cli">
<button class="btn btn-secondary"><span>Copy</span></button>
</div>
<h3>Fedora Based Systems</h3>
<div class="code-snippet">
<input aria-label="Add repo" type="text" readonly value="yum-config-manager --add-repo https://packages.veilid.net/rpm/veilid-rpm-repo.repo">
<button class="btn btn-secondary"><span>Copy</span></button>
</div>
<div class="code-snippet">
<input aria-label="Install the headless and command line utilities" type="text" readonly value="dnf install veilid-server veilid-cli">
<button class="btn btn-secondary"><span>Copy</span></button>
</div>
<h3>PyPi</h3>
<p><a href="https://pypi.org/project/veilid/">https://pypi.org/project/veilid/</a></p>

45
pages/donate.md Normal file
View File

@ -0,0 +1,45 @@
---
title: Donate
description: Help support Veilid by gifting a tax-deductible donation
menu:
main:
weight: 10
layout: index
---
<div class="row g-5">
<div class="col-12 col-md-7">
<p>
Veilid Foundation was formed to develop, distribute, and maintain a privacy focused
communication platform and protocol for the purposes of defending human and civil rights.
</p>
<p>
Supporting us in this mission helps ensure the Veilid framework gets the support and defense
it needs to protect your privacy.
</p>
<p>
You have a very real chance at private, secure, and accessible communication tools.
</p>
<p>
You can escape the data economy and help others do the same. You don't have to be the product.
</p>
</div>
<div class="col-12 col-md-5">
<div class="focus-text">
<p>
Veilid Foundation Inc is a registered 501c3 non-profit organization; your donations are tax-deductible.
</p>
</div>
<p>You can learn more at <a href="https://veilid.org">Veilid.org</a></p>
</div>
</div>
<div class="d-flex flex-column mt-5">
<p class="small-warning order-2">
Donations are collected via Stripe; clicking this link will open a new window or tab.
</p>
<p class="order-1">
<a target="_blank" href="/give" class="btn btn-lg btn-success text-white w-100">Support Veilid Today</a>
</p>
</div>

View File

@ -0,0 +1,167 @@
---
title: Cryptography
description: An overview of the cryptography used in Veilid
weight: 3
layout: subpage
---
Strong, appropriate, cryptography choices are essential to the functioning of Veilid.
Veilid provides applications guarantees about how data is handled on the wire and at rest.
Cryptosystems were chosen that work well together and provide a balance of speed and cryptographic hardness.
### Current Cryptography Systems
<ul>
<li>
<h4>Authentication is Ed25519</h4>
Elliptic curve25519 was chosen to provide public/private key authentication and signing capabilities
</li>
<li>
<h4>Key Exchange is x25519</h4>
Curve25519 has a DH function that allows nodes to generate a symmetric key to communicate privately.
</li>
<li>
<h4>Encryption is XChaCha20-Poly1305</h4>
ChaCha20 with a 192-bit extended nonce is a fast authenticated stream cipher with associated data (AEAD).
</li>
<li>
<h4>Message Digest is BLAKE3</h4>
BLAKE3 is a extremely fast cryptographic hash that is highly parallelizable and as strong as SHA3-256 and over 17 times faster.
</li>
<li>
<h4>Key Derivation is Argon2</h4>
Password hash generation should be slow and resistant to GPU attacks Argon2 was the winner of the 2015 Password Hashing Competition.
</li>
</ul>
### Upgrading Cryptography Systems
Nothing lasts forever and cryptography is no exception. As computing power improves and cryptographic attacks evolve, weaknesses in cryptosystems are inevitable.
Veilid has ensured that upgrading to newer cryptosystems is streamlined and minimally invasive to app developers, and handled transparently at the node level.
<ul>
<li>
<h4>Multiple Routing Tables</h4>
Because changing cryptosystems changes node ids, there will be different distance measurements between nodes, necessitating a separate routing table per cryptosystem. We support this today.
</li>
<li>
<h4>Typed Keys</h4>
Cryptographic keys, signatures, and hashes are all tagged with their cryptosystem to ensure that we know exactly how they were generated and how they should be used and persisted.
</li>
<li>
<h4>Migration Support</h4>
Reading persisted data will automatically use the correct cryptosystem and will default to always writing it back using the newest/best cryptosystem. This allows for data to be easily migrated just by reading it and writing it back to storage.
</li>
<li>
<h4>Simultaneous Cryptosystems</h4>
While transitioning cryptosystems, nodes can respond to other nodes using either the old system or the new one, or both.
</li>
</ul>
### Secure Storage
- Device-level secret storage APIs are available for all platforms
- Encrypted table store APIs are exposed to applications to make safe data storage easy
- Device data keys can also be password protected
- Apps never need to write anything to disk unencrypted
<div class="row g-3 mx-2 card-set">
<div class="col-12 col-md-6">
<div class="card">
<div class="card-header text-bg-light">
<h4>ProtectedStore</h4>
</div>
<div class="card-body">
<p>Device-level Secret Storage</p>
<ul>
<li>MacOS / iOS Keychain</li>
<li>Android Keystore</li>
<li>Windows Protected Storage</li>
<li>Linux Secret Service</li>
</ul>
New Rust Crate: <code>keyring-manager</code>
</div>
</div>
</div>
<div class="col-12 col-md-6">
<div class="card">
<div class="card-header text-bg-light">
<h4>TableStore</h4>
</div>
<div class="card-body">
<p>Encrypted Key-Value Database</p>
<ul>
<li>SQLITE on Native</li>
<li>IndexedDB in Browser</li>
<li>Device Key can be protected from backup dumping attacks</li>
</ul>
New Rust Crate: <code>keyvaluedb</code>
</div>
</div>
</div>
<div class="col-12 col-md-6">
<div class="card">
<div class="card-header text-bg-light">
<h4>RecordStore</h4>
</div>
<div class="card-body">
<p>Distributed Hash Table Storage</p>
<ul>
<li>Encrypted + Authenticated</li>
<li>Subkey support</li>
<li>LRU distributed cache</li>
<li>Per-key multi-writer schemas</li>
</ul>
</div>
</div>
</div>
<div class="col-12 col-md-6">
<div class="card">
<div class="card-header text-bg-light">
<h4>BlockStore</h4>
</div>
<div class="card-body">
<p>Content-addressable Data Distribution
<ul>
<li>Take What You Give model</li>
<li>Connect and share cloud storage</li>
<li>Bittorrent-like sharding</li>
</ul>
This feature is "coming soon."
</div>
</div>
</div>
</div>
### On The Wire
<div class="focus-text">
<p>Everything is end-to-end encrypted</p>
<p>Data is encrypted at rest and on the wire</p>
<p>Your data is protected even if you lose your device</p>
</div>
<ul>
<li>
<h4>All Protocols Same Encryption</h4>
Each low-level protocol uses the same message and receipt encapsulation. No protocol is special and all protocols offer the same safety guarantees.
</li>
<li>
<h4>Encrypted And Signed</h4>
Messages between nodes are signed by the sender and encrypted for only the receiver. Messages can be relayed without decryption and authentication covers the entire contents including headers.
</li>
<li>
<h4>Everything Is Timestamped</h4>
Envelopes include timestamps and unique nonces and reject old or replayed messages.
</li>
<li>
<h4>Node Information Is Signed</h4>
When a node publishes routing table entries they are signed. No node can lie about another node's dial info, capabilities, availability, or replay old node info when newer info is available.
</li>
</ul>

26
pages/framework/index.md Normal file
View File

@ -0,0 +1,26 @@
---
title: Framework
description: An overview of the Veilid Framework
menu:
main:
weight: 3
weight: 1
layout: subpage
sortby: weight
---
<div class="focus-text">
Veilid is an open-source, peer-to-peer, mobile-first, networked application framework.
</div>
The framework is conceptually similar to <a href="https://ipfs.tech/">IPFS</a> and <a href="https://www.torproject.org/">Tor</a>, but faster and designed from the ground-up to provide all
services over a privately routed network.
The framework enables development of fully-distributed applications without a 'blockchain' or
a 'transactional layer' at their base.
The framework can be included as part of user-facing applications or run as a 'headless node'
for power users who wish to help build the network.

View File

@ -0,0 +1,63 @@
---
title: Networking
description: An overview of the networking used in Veilid
weight: 2
layout: subpage
---
<div class="focus-text">
<p>All devices are welcome and treated fairly.</p>
<p>You can use the public Veilid Network or build your own.</p>
<p>Nodes help each other like mutual aid for connectivity</p>
</div>
All Veilid applications running `veilid-core` are 'nodes', and they are all equal in the eyes of the network. No nodes are 'special'.
Nodes are only limited by the resources they bring and the configuration of the network they are on.
DNS is only used one time during bootstrap'; it is not required though.
SSL is optional and only for HTTPS Websockets for Veilid Webapps.
### Protocols
Veilid uses UDP, TCP, and Websockets.
Low level protocols supported by Veilid are kept simple, to minimize complications. Everything uses framed RPC operations up
to 64KB in size. Protocol support is extensible and may add WebRTC and other specialized protocols in the future.
### Network Topology
<p><img src="/img/Network-Thumbnail.png" alt="A topology graph for Veilid networks" class="img-fluid"></p>
<p>To zoom in on the details, <a href="/img/Network.png">view the full size image directly</a>.</p>
### Bootstrapping
Bootstrap nodes not 'special' nodes. Any node can bootstrap a Veilid network. Networks can be 'keyed' to keep nodes off that don't have the key. You can join the big Veilid network' or make your own isolated network.
<ul>
<li>
<h4>Ask Bootstraps To Find Self'</h4>
A single initial DNS TXT record request returns some bootstrap nodes that are known to exist. Those are asked to return nodes that are close' to your own node.
</li>
<li>
<h4>Public Address Detection</h4>
Nodes are often behind various forms of NAT. Validating one's own public Dial Info' is essential for publishing one's Node Info and answering Find Node requests.
</li>
<li>
<h4>Relay Configuration</h4>
Low-capability network classes may require the use of Inbound or Outbound relays in order to achieve reachability Nodes help each other out to the best of their ability and incur no penalty for not being able to assist other nodes.
</li>
<li>
<h4>Peer Minimum Refresh </h4>
Nodes in your routing table are asked to return nodes that are near you as well. Finding nodes close to your own is always harder than finding nodes far away, so we focus on that with our requests.
</li>
<li>
<h4>Network Class Detection</h4>
Determining NAT type and what mechanisms can be used to achieve connectivity. Direct connection techniques like reverse connections and UDP hole punching may be inappropriate for some network classes.
</li>
<li>
<h4>Ping Validation</h4>
Nodes come and go, change address, and are unreliable. Checking routing table nodes for proof-of-life is done with exponential backoff. Nodes are removed from the routing table on a LIFO basis.
</li>
</ul>

View File

@ -0,0 +1,84 @@
---
title: Private Routing
description: An overview of how private routing works in Veilid
weight: 5
layout: subpage
---
### Private and Safety Routes
<figure>
<img src="/img/private-and-safety-routes.png" alt="a diagram of routes between points a and b" class="img-fluid">
<figcaption>
Veilid Routes are a combination of source and destination private routing.
Because no node can trust any other node to pick the whole route, both source and destination must participate.
</figcaption>
</figure>
### Compiled Routes
<figure>
<img src="/img/compiled-routes.png" alt="a diagram of routes between points a and b, shown with components" class="img-fluid">
<figcaption>
Private Routes are published as a private destination and Safety Routes are allocated locally and combined
together with a Private Route to form a Compiled Route.
</figcaption>
</figure>
### Secure Envelopes
<figure>
<img src="/img/secure-envelopes.png" alt="a diagram how a message is passed from B to A" class="img-fluid">
<figcaption>
<p>
Each node hop only knows about the next one This is similar to onion routing, but assumes that
the source is fully in control of the Safety Route and the destination is fully in control of
the Private Route.
</p>
<p>To zoom in on the details, <a href="/img/secure-envelopes.png">view the image directly</a>.</p>
</figcaption>
</figure>
### Toward The Future
<div class="focus-text">
<p>Private routing is a balance of performance and security</p>
<p>Applications can make use of higher node hop counts if they desire</p>
<p>Future private routing advancements will be transparent to users</p>
</div>
<ul>
<li>
<h4>Per-Hop Payload Keying</h4>
Ensuring that there is nothing common between packets at each hop will reduce the risk of mass data collection
being able to deanonymize routes.
</li>
<li>
<h4>Simplify Directionality</h4>
Routes are currently bidirectional, but are allocated directionally.
We may be able to simplify our allocation mechanism by enforcing bidirectionality.
Bidirectional routes are faster, but directional routes could provide more anonymity.
</li>
<li>
<h4>Elimination of Hop Counting</h4>
Currently the protocol keeps an internal hop count that is not necessary.
Efforts should be made to ensure that individual nodes dont know how far along in a route they are.
</li>
<li>
<h4>Hop Caching</h4>
Route hop NodeInfo could be cached to save on-the-wire size as well as speed things up.
</li>
<li>
<h4>Increasing Hop Count</h4>
<p>Currently the default is one hop chosen by the Safety Route, and one hop chosen by the Private Route, which leads to three hops total once compiled.</p>
<p>It may be important to increase hop count to 2 for users with critical safety needs and to protect from nation-state-level deanonymization where appropriate.</p>
<p>Existing research (on Tor) suggests that our existing hop count should be sufficient and provide comparable anonymity, but this should be revisited.</p>
</li>
</ul>
<div class="focus-text">
<p>IP Privacy means your location is safe too</p>
<p>Users dont have to do anything to use it</p>
<p>No IP address means no tracking, collection, or correlation</p>
</div>

91
pages/framework/rpc.md Normal file
View File

@ -0,0 +1,91 @@
---
title: RPC Protocol
description: An overview of the RPC protocol used in Veilid
weight: 4
layout: subpage
---
Strong, appropriate, cryptography choices are essential to the functioning of Veilid.
Veilid provides applications guarantees about how data is handled on the wire and at rest.
Cryptosystems were chosen that work well together and provide a balance of speed and cryptographic hardness.
### RPC Summary
<ul>
<li>
<h4>Schema Language is Cap'n Proto</h4>
<a href="https://capnproto.org/">Capn Proto</a> is designed for deserialization speed and schema evolution. Flexible and well supported in Rust.
</li>
<li>
<h4>RPC is fully in-schema and documented</h4>
Both Question/Answer and Statement RPC modes are supported. All schema fields are documented.
</li>
<li>
<h4>RPC fully supports Private Routing</h4>
All private routing structures are expressed in the RPC schema itself, no magic encrypted blobs.
</li>
<li>
<h4>Schema Evolution is built-in</h4>
Fields can be added and removed with full backward and forward compatibility. New features wont break older Veilid nodes.
</li>
<li>
<h4>RPC Schema is cryptography-independent</h4>
As cryptosystems change, the language spoken by Veilid nodes remains the same.
</li>
</ul>
### Distributed Hash Table
Distributed Hash Tables are a way of storing data in records that have keys that are close to nodes in the network.
#### DHT Is Just Search
It may look complicated, but all the DHT algorithms out there are just search algorithms. Finding data that is stored on some node somewhere out there.
#### Improving Search
We built a better DHT by making both search and data locality more relevant. Veilid synchronizes popular data when nodes come and go from the network.
<img src="/img/dht-diagram.png" alt="a tree diagram for the search ability" class="img-fluid lightbox">
Locating a node by its ID. Here the node with the prefix 0011 finds the node with the prefix 1110 by
successively learning of and querying closer and closer nodes. The line segment on top represents the
space of 160-bit IDs, and shows how the lookups coverge to the target node. Below we illustrate RPC messages
made by 1110. The first RPC is to node 101, already known to 1110. Subsequent RPCs are to nodes return by the
previous RPC.
#### DHT Schema
Veilid DHT is built using GetValue and SetValue RPC operations. Nodes can opt out of DHT storage if they do not want to participate.
Veilid DHT records have schemas that define subkeys that are individually addressable and can have multiple writers.
DHT record subkeys have sequence numbers and are eventually consistent across multiple writes and background synchronizations.
<div class="row gx-5 gy-3 mb-3">
<div class="col-12 col-lg-6">
<figure class="h-100">
<img src="/img/dht-dflt-framed.png" alt="a diagram showing key-value pairs" class="img-fluid lightbox">
<figcaption>
<p>Veilid Default DHT Schema - DFLT</p>
<p>To zoom in on the details, <a href="/img/dht-dflt-framed.png">view the image directly</a>.</p>
</figcaption>
</figure>
</div>
<div class="col-12 col-lg-6">
<figure class="h-100">
<img src="/img/dht-smpl.png" alt="a diagram showing key-value pairs, but with more fields" class="img-fluid lightbox">
<figcaption>
<p>Veild Simple DHT Schema - SMPL</p>
<p>To zoom in on the details, <a href="/img/dht-smpl.png">view the image directly</a>.</p>
</figcaption>
</figure>
</div>
</div>
<div class="focus-text">
<p>The DHT gives you full control over your data</p>
<p>Our DHT is not based on a blockchain or a coin </p>
<p>Popular data becomes more available automatically </p>
</div>

73
pages/index.md Normal file
View File

@ -0,0 +1,73 @@
---
title: Take Back Control
description: Veilid is an open-source, distributed application framework.
menu:
main:
weight: 1
layout: index
---
<p class="focus-text highlighted">
Veilid is an
<span class="highlighter-1">open-source</span>,
<span class="highlighter-2">peer-to-peer</span>,
<span class="highlighter-3">mobile-first</span>,
<span class="highlighter-4">networked</span>
application framework.
</p>
<p>Veilid (pronounced Vay-Lid, from 'Valid and Veiled Identification')</p>
<p>
Veilid allows anyone to build a distributed, private app. Veilid gives users the privacy to opt out of
data collection and online tracking. Veilid is being built with user experience, privacy, and safety as our top priorities.
It is open source and available to everyone to use and build upon.
</p>
<p>
Veilid goes above and beyond existing privacy technologies and has the potential to completely change the way
people use the Internet. Veilid has no profit motive, which puts us in a unique position to promote ideals
without the compromise of capitalism.
</p>
<p class="focus-text">
We built Veilid because when the Internet was young and new, we viewed it as an endless and open realm of possibility.
</p>
<p>
Instead, the Internet we know now has been heavily commercialized, with users and their data being the most
sought-after commodity. The only ways to opt-out of becoming the product for billionaires to exploit are either
too technical for the average user, or to simply not go online.
</p>
<p>
We don't believe that is fair; we still haven't given up our dream for the entire Internet to be free
and accessible without trading privacy to use it.
</p>
<p class="focus-text">
We believe that everyone should be able to forge relationships, learn, create, and build online &mdash; without being monetized.
</p>
<p>
With Veilid, the user is in control, in a way that is approachable and friendly, regardless of technical
ability. We want to give the world the Internet we should have had all along.
</p>
<div class="row gx-5 gy-3 mt-5">
<div class="col-12 col-md-6 col-lg-3">
<a class="btn btn-info btn-lg w-100" href="/framework">Technical Details</a>
</div>
<div class="col-12 col-md-6 col-lg-3">
<a class="btn bgv-fuschia btn-lg w-100" href="/chat">VeilidChat</a>
</div>
<div class="col-12 col-md-6 col-lg-3">
<a class="btn btn-dark btn-lg w-100" href="/code">Code</a>
</div>
<div class="col-12 col-md-6 col-lg-3">
<a class="btn btn-primary btn-lg w-100" href="/discord">Discord</a>
</div>
</div>
<div class="row gx-5 gy-3 mt-3 justify-content-center">
<div class="col-12 col-md-6">
<a class="btn btn-success btn-lg w-100 text-white" href="/donate">Donate</a>
</div>
</div>

30
pages/translations.md Normal file
View File

@ -0,0 +1,30 @@
---
title: Translations
description: Help translate documentation and more for the Veilid project
layout: index
exclude: true
---
<div class="row g-5">
<div class="col-12 col-md-7">
<p>
We are very early on in this project and currently only have our text in English.
</p>
<p>
We are seeking volunteers to help with this project's translations.
</p>
<p>
Please join us on our server to talk about how we can expand our reach.
</p>
</div>
<div class="col-12 col-md-5">
<h3 class="mt-0 text-center">Help Wanted</h3>
<p>
<a href="/discord" class="btn btn-primary btn-lg w-100">Veilid Discord</a>
</p>
</div>
</div>

71
pages/web-text.md Normal file
View File

@ -0,0 +1,71 @@
---
title: Web Text
description: How to customize your browser text appearance; based on the WAI customize design document.
layout: index
exclude: true
---
## Change Text Size with Zoom
<p>Most web browsers let you increase and decrease the size of text, images, and other web page content with "zoom" features. Some browsers let you choose to zoom only the text size.</p>
<p>To change the zoom in most browsers, press the following two keys at the same time:</p>
<ul>
<li>In Windows, Linux, and Chrome OS:
<ul>
<li>To zoom bigger: "Ctrl" and "+" keys</li>
<li>To zoom smaller: "Ctrl" and "-" keys</li>
</ul>
</li>
<li>Mac OS:
<ul>
<li>To zoom bigger: "⌘" and "+" keys</li>
<li>To zoom smaller: "⌘" and "-" keys</li>
</ul>
</li>
</ul>
Browsers provide specific guidance on different ways to change the page zoom or text-only zoom:
* [Google Chrome - Change text, image, and video sizes (zoom)](https://support.google.com/chrome/answer/96810)
* [Apple Safari - Zoom in on webpages](https://support.apple.com/guide/safari/zoom-in-on-webpages-ibrw1068/mac)
* [Mozilla Firefox - Font size and zoom](https://support.mozilla.org/en-US/kb/font-size-and-zoom-increase-size-of-web-pages)
* [Opera - Zoom](https://help.opera.com/en/latest/browser-window/#zoom)
* [Internet Explorer - Ease of access options](https://support.microsoft.com/en-us/help/17456/windows-internet-explorer-ease-of-access-options)
* [Microsoft Edge - Ease of Access in Microsoft Edge](https://support.microsoft.com/en-gb/help/4000734/windows-10-microsoft-edge-ease-of-access)
* [Vivaldi - Zooming options in Vivaldi](https://help.vivaldi.com/article/zooming-options-in-vivaldi/)
## Other Text and Color Changes
Some browsers provide functionality to set different aspects of font and color in the default view.
* [Mozilla Firefox - Change the fonts and colors websites use](https://support.mozilla.org/en-US/kb/change-fonts-and-colors-websites-use)
* [Opera - Look and feel > Fonts](https://help.opera.com/en/presto/look-and-feel/#fonts)
* [Microsoft Internet Explorer - Ease of Access Options](https://support.microsoft.com/en-us/help/17456/windows-internet-explorer-ease-of-access-options)
Other text and color settings are available in Reader View.
## Reader View
Most browsers offer a "Reader View" or "Reading View" that shows just the main content; it gets rid of navigation, ads, etc. Some browsers let you set the text font, text size, text color, background color, and line spacing in Reader View.
* [Apple Safari - Hide ads when reading articles](https://support.apple.com/en-ca/guide/safari/hide-ads-when-reading-articles-sfri32632/mac)
* [Mozilla Firefox - Reader View for clutter-free web pages](https://support.mozilla.org/en-US/kb/firefox-reader-view-clutter-free-web-pages)
* [Microsoft Edge - Change font style and size for Reading view in Microsoft Edge](https://support.microsoft.com/en-us/help/4028023/microsoft-edge-change-font-style-and-size-for-reading-view)
* [Vivaldi - Reader View](https://help.vivaldi.com/article/reader-view/)
## Advanced Options
There are many browser extensions and add-ons that provide additional control over how the browser displays text and other content.
While most browsers no long support user style sheets, extensions provide similar advanced user control. For example, the Stylus extension is available for several major browsers.
### Note: No Endorsement
We do not endorse specific web browsers or extensions and does not recommend one over another.
While some common browsers are included in this page, mention of a specific browser does not imply
endorsement or recommendation.
### About This Page
This page is based off the [WAI customize design document](https://github.com/w3c/wai-customize-design/blob/master/index.md).

0
static/.keep Normal file
View File

Binary file not shown.

Binary file not shown.

BIN
static/favicon.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 264 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 145 KiB

BIN
static/img/Network.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 214 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 80 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 55 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 66 KiB

BIN
static/img/Veilid-V.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 455 KiB

2
static/img/Veilid-V.svg Normal file
View File

@ -0,0 +1,2 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" style="isolation:isolate" viewBox="0 0 901 901" width="901pt" height="901pt"><defs><clipPath id="_clipPath_LA2coIIEG2Vagf8wP2xv5cSFrDqpTDJQ"><rect width="901" height="901"/></clipPath></defs><g clip-path="url(#_clipPath_LA2coIIEG2Vagf8wP2xv5cSFrDqpTDJQ)"><path d=" M 305.8 69.8 C 311.91 67.94 318.94 70.06 323.02 74.98 C 326.21 78.62 326.85 83.58 328.2 88.05 C 372.11 246.55 416 405.05 459.93 563.54 C 479.59 634.49 499.18 705.45 518.92 776.37 C 520.6 781.38 520.73 787.17 517.8 791.75 C 515.52 795.7 511.46 798.36 507.09 799.44 C 464.94 811.15 422.77 822.8 380.61 834.46 C 376.2 835.62 371.71 837.45 367.07 836.61 C 360.68 835.59 355.3 830.48 353.82 824.2 C 289.98 593.76 226.12 363.33 162.28 132.9 C 161.25 128.98 159.66 125.05 160.17 120.93 C 160.79 114.43 165.65 108.59 171.97 106.91 C 216.59 94.58 261.19 82.18 305.8 69.8 Z " fill="rgb(79,77,157)"/><path d=" M 675.98 123.92 C 683.58 119.46 692.74 115.7 701.6 118.49 C 713.94 122.49 722.95 132.3 732.76 140.25 C 735.47 142.57 738.81 143.89 742.15 145.02 C 742.29 146.65 742.63 148.36 742.07 149.95 C 683.22 311.96 624.24 473.93 565.49 635.97 C 567.14 639.32 568.8 642.67 570.46 646.02 C 555.03 685.68 539.3 725.23 523.79 764.87 C 522.17 768.7 521.03 772.75 518.92 776.37 C 499.18 705.45 479.59 634.49 459.93 563.54 C 471.35 536.95 482.05 510.03 493.19 483.31 C 493.68 482.14 494.32 480.98 495.59 480.52 C 500.59 477.84 505.83 475.61 510.71 472.72 C 513.71 470.37 515.63 466.96 518.13 464.14 C 520.41 461.07 523.38 458.46 525.12 455.03 C 525.09 450.31 523.87 445.68 523.82 440.96 C 525.6 434.76 529.6 429.36 531.47 423.22 C 530.12 416.69 527.87 410.37 526.31 403.89 C 525.45 401.14 527.15 398.56 528.01 396.04 C 529.97 391.7 530.89 386.74 534.2 383.13 C 537.3 379.28 540.81 375.73 543.6 371.64 C 546.34 366.2 548.3 360.4 550.9 354.89 C 551.47 353.17 553.25 352.53 554.67 351.68 C 559.89 348.93 564.99 345.98 570.19 343.21 C 571.18 342.55 572.44 342.11 573.08 341.04 C 576.36 335.28 577.55 328.27 582.5 323.54 C 586.37 318.65 591.86 314.68 593.56 308.42 C 594.6 305.24 596.09 302.2 596.78 298.92 C 594.78 291.13 591.59 283.66 589.32 275.94 C 588.58 273.69 589.81 271.49 590.41 269.38 C 591.41 266.72 591.99 263.88 593.42 261.41 C 597.88 258.1 602.8 255.47 607.42 252.4 C 610.73 250.46 611.5 246.38 613.3 243.26 C 615.47 238.19 619.14 233.56 619.34 227.85 C 619.81 223.25 620.3 218.66 620.82 214.08 C 621.53 207.31 625.85 201.61 627.3 195.06 C 625.94 188.52 623.96 182.13 622.43 175.63 C 621.64 173.28 623.32 171.14 624.15 169.05 C 625.61 166.24 626.53 163.12 628.41 160.55 C 632.99 157.9 638.45 156.89 642.7 153.7 C 652.49 142.47 663.11 131.62 675.98 123.92 Z M 689.4 134.56 C 684.09 135.82 680.07 140.2 678.25 145.22 C 662.71 181.5 647.63 217.98 632.48 254.43 C 584.55 369.65 537 485.02 489.31 600.33 C 487.34 604.68 484.5 610.47 488.32 614.65 C 490.14 616.86 493.14 615.36 494.75 613.71 C 500.05 608.6 503.87 602.21 508.67 596.66 C 516.62 587.64 522.78 577.26 528.93 566.99 C 536.58 553.67 544.33 540.3 549.88 525.93 C 597.15 407.35 643.9 288.57 690.84 169.85 C 694.74 159.59 699.16 149.5 702.77 139.14 C 701.03 133.97 693.95 133.48 689.4 134.56 Z " fill="rgb(11,11,47)"/><path d=" M 689.4 134.56 C 693.95 133.48 701.03 133.97 702.77 139.14 C 699.16 149.5 694.74 159.59 690.84 169.85 C 643.9 288.57 597.15 407.35 549.88 525.93 C 544.33 540.3 536.58 553.67 528.93 566.99 C 522.78 577.26 516.62 587.64 508.67 596.66 C 503.87 602.21 500.05 608.6 494.75 613.71 C 493.14 615.36 490.14 616.86 488.32 614.65 C 484.5 610.47 487.34 604.68 489.31 600.33 C 537 485.02 584.55 369.65 632.48 254.43 C 647.63 217.98 662.71 181.5 678.25 145.22 C 680.07 140.2 684.09 135.82 689.4 134.56 Z " fill="rgb(255,255,255)"/></g></svg>

After

Width:  |  Height:  |  Size: 3.7 KiB

BIN
static/img/Veilid.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 93 KiB

2
static/img/Veilid.svg Normal file

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 9.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 512 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 786 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 66 KiB

BIN
static/img/dht-dflt.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 129 KiB

BIN
static/img/dht-diagram.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 273 KiB

BIN
static/img/dht-smpl.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 154 KiB

3
static/img/fonts.svg Normal file
View File

@ -0,0 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-fonts" viewBox="0 0 16 16">
<path d="M12.258 3h-8.51l-.083 2.46h.479c.26-1.544.758-1.783 2.693-1.845l.424-.013v7.827c0 .663-.144.82-1.3.923v.52h4.082v-.52c-1.162-.103-1.306-.26-1.306-.923V3.602l.431.013c1.934.062 2.434.301 2.693 1.846h.479L12.258 3z"/>
</svg>

After

Width:  |  Height:  |  Size: 357 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 403 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 661 KiB

4
static/img/translate.svg Normal file
View File

@ -0,0 +1,4 @@
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-translate" viewBox="0 0 16 16">
<path d="M4.545 6.714 4.11 8H3l1.862-5h1.284L8 8H6.833l-.435-1.286H4.545zm1.634-.736L5.5 3.956h-.049l-.679 2.022H6.18z"/>
<path d="M0 2a2 2 0 0 1 2-2h7a2 2 0 0 1 2 2v3h3a2 2 0 0 1 2 2v7a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2v-3H2a2 2 0 0 1-2-2V2zm2-1a1 1 0 0 0-1 1v7a1 1 0 0 0 1 1h7a1 1 0 0 0 1-1V2a1 1 0 0 0-1-1H2zm7.138 9.995c.193.301.402.583.63.846-.748.575-1.673 1.001-2.768 1.292.178.217.451.635.555.867 1.125-.359 2.08-.844 2.886-1.494.777.665 1.739 1.165 2.93 1.472.133-.254.414-.673.629-.89-1.125-.253-2.057-.694-2.82-1.284.681-.747 1.222-1.651 1.621-2.757H14V8h-3v1.047h.765c-.318.844-.74 1.546-1.272 2.13a6.066 6.066 0 0 1-.415-.492 1.988 1.988 0 0 1-.94.31z"/>
</svg>

After

Width:  |  Height:  |  Size: 801 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 79 KiB

BIN
static/img/veilid-bg.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 141 KiB

Binary file not shown.

View File

@ -0,0 +1,35 @@
@font-face {
font-family: 'Atkinson Hyperlegible';
src: url('/fonts/AtkinsonHyperlegible-Regular.woff2') format('woff2'),
url('/fonts/AtkinsonHyperlegible-Regular.woff') format('woff');
font-weight: normal;
font-style: normal;
font-display: swap;
}
@font-face {
font-family: 'Atkinson Hyperlegible';
src: url('/fonts/AtkinsonHyperlegible-Bold.woff2') format('woff2'),
url('/fonts/AtkinsonHyperlegible-Bold.woff') format('woff');
font-weight: bold;
font-style: normal;
font-display: swap;
}
@font-face {
font-family: 'Bitter';
src: url('/fonts/Bitter-Medium.woff2') format('woff2'),
url('/fonts/Bitter-Medium.woff') format('woff');
font-weight: normal;
font-style: normal;
font-display: swap;
}
@font-face {
font-family: 'Bitter';
src: url('/fonts/Bitter-Bold.woff2') format('woff2'),
url('/fonts/Bitter-Bold.woff') format('woff');
font-weight: bold;
font-style: normal;
font-display: swap;
}

View File

@ -0,0 +1,81 @@
/* ========================== General Rules ==================================== */
body {
font-family: 'Bitter', serif;
overflow-x: hidden;
}
h1, h2, h3, h4, h5, h6 {
font-family: 'Atkinson Hyperlegible', sans-serif;
margin-top: 1.3em; /* EM on purpose: proportional to font size please */
@extend .mb-1;
color: $primary;
}
code {
font-size: 1em;
}
.list-inline-item:after {
content: ', ';
}
.list-inline-item:last-child:after {
content: '';
}
@include media-breakpoint-down(md) {
.no-comma .list-inline-item:after {
content: '';
}
}
li {
@extend .my-2;
}
p:last-child {
margin-bottom: 0;
}
figure {
@extend .p-3;
border: 1px solid $border-color;
figcaption {
@extend .mt-3;
}
}
.btn {
text-decoration: underline;
}
.highlighter-1, .highlighter-2, .highlighter-3, .highlighter-4 {
display: inline-block;
padding: 0.15em 0.3em;
margin: 0.15em 0;
@extend .rounded;
}
.highlighter-1 {
background-color: #dde97d;
color: black;
}
.highlighter-2 {
background-color: #FFE680;
color: black;
}
.highlighter-3 {
background-color: #99DBFF;
color: black;
}
.highlighter-4 {
background-color: #F080D8;
color: black;
}

View File

@ -0,0 +1,161 @@
#site-logo {
max-height: 4rem;
@extend .my-2;
@extend .me-3;
}
#site-title {
display: block;
position: absolute;
top: -100vh;
}
.navbar-toggler img {
min-height: 2rem;
display: block;
}
/*
// No media query necessary for xs breakpoint as it's effectively `@media (min-width: 0) { ... }`
@include media-breakpoint-up(sm) { ... }
@include media-breakpoint-up(md) { ... }
@include media-breakpoint-up(lg) { ... }
@include media-breakpoint-up(xl) { ... }
@include media-breakpoint-up(xxl) { ... }
*/
@mixin nav-link-theme {
@extend .nav;
@extend .me-3;
.nav-link:visited, .nav-link:link, .nav-link:hover, .nav-link:active, .nav-link.active {
text-align: left !important;
padding: 0.25rem 0.5rem;
background: transparent !important;
}
.nav-link:visited, .nav-link:link {
text-decoration: underline;
color: $veilid_purple_medium;
}
.nav-link:hover, .nav-link:active {
text-decoration: none;
color: $veilid_fuchsia !important;
}
}
.header-nav {
@include nav-link-theme;
display: block;
li {
display: block;
@extend .my-4;
}
}
@include media-breakpoint-up(lg) {
.header-nav {
display: flex;
li {
}
}
}
.subsectionnav {
@include nav-link-theme;
display: block;
}
#site-options {
font-family: 'Atkinson Hyperlegible', sans-serif;
color: $black;
background-color: #E3E4F1;
a:link, a:active, a:visited, a:hover {
color: inherit;
img {
height: 1.5em;
}
}
}
@include media-breakpoint-up(lg) {
#site-options img {
padding-right: 0.25rem;
}
}
#site-nav {
@extend .mt-2;
@extend .mb-4;
}
#site-nav .navbar-brand {
margin-right: 2rem;
}
html, body {
height: 100%;
}
body {
display: flex;
flex-direction: column;
#content {
flex: 2;
margin-top: 0rem;
margin-bottom: 4rem;
}
}
@media (min-width: 992px) {
.subsectionnav li {
display: block;
width: 100%;
}
}
#page-footer {
background-color: $black;
color: $white;
padding: 2rem;
p {
margin: 1rem 0;
}
a:link, a:active, a:hover, a:visited {
color: $white;
}
}
@include media-breakpoint-up(md) {
.col-list { columns: 2; }
}
@include media-breakpoint-up(lg) {
.col-list { columns: 3; }
}
.front-page-hero {
display: flex;
flex-direction: column;
justify-content: end;
height: 25vh;
@extend .mb-4;
.focus-text {
margin-bottom: 0 !important;
}
.take-back-control {
margin: 0 !important;
h2 {
margin: 0 !important;
}
}
}

View File

@ -0,0 +1,54 @@
/* I like how it looks. That's why and that's good enough. */
$line-height-base: 1.62;
$spacer: 1rem;
$spacers: (
0: 0,
1: $spacer * .41,
2: $spacer * .81,
3: $spacer,
4: $spacer * 1.62,
5: $spacer * 3.24,
);
/* Bigger hit box please */
$list-group-item-padding-y: $spacer * .81;
$veilid_purple: #4f4d9d;
$veilid_purple_pastel: #c7c8e2;
$veilid_purple_border: #8B8BC0;
$veilid_purple_medium: #3D3783;
$veilid_purple_darkest: #2b2068;
$veilid_magenta: #e100b0;
$veilid_fuchsia: #8e0097;
$veilid_plum_dark: #441168;
$primary: $veilid_purple;
$primary-bg-subtle: $veilid_purple_pastel;
$primary-border-subtle: #a2a5ce;
$dark: #131c45;
$success: #008219 ;
$warning:#dde97d;
$danger: #cd9c2d;
$info: #001d7f;
$code-color: $veilid_fuchsia;
$secondary: #495057;
$navbar-dark-color: rgba(#fff, .75);
$navbar-dark-hover-color: rgba(#fff, 1);
$table-dark-bg: rgba($dark,0.5);
$link-decoration: underline;
.bgv-purple { background-color: $veilid_purple !important; color: white !important; }
.bgv-fuschia { background-color: $veilid_fuchsia !important; color: white !important; }
.bgv-plum { background-color: $veilid_plum_dark !important; color: white !important; }
$link-color: $veilid_purple_medium;
$link-hover-color: $veilid_fuchsia;

View File

@ -0,0 +1,158 @@
//
// Base styles
//
.accordion {
// scss-docs-start accordion-css-vars
--#{$prefix}accordion-color: #{$accordion-color};
--#{$prefix}accordion-bg: #{$accordion-bg};
--#{$prefix}accordion-transition: #{$accordion-transition};
--#{$prefix}accordion-border-color: #{$accordion-border-color};
--#{$prefix}accordion-border-width: #{$accordion-border-width};
--#{$prefix}accordion-border-radius: #{$accordion-border-radius};
--#{$prefix}accordion-inner-border-radius: #{$accordion-inner-border-radius};
--#{$prefix}accordion-btn-padding-x: #{$accordion-button-padding-x};
--#{$prefix}accordion-btn-padding-y: #{$accordion-button-padding-y};
--#{$prefix}accordion-btn-color: #{$accordion-button-color};
--#{$prefix}accordion-btn-bg: #{$accordion-button-bg};
--#{$prefix}accordion-btn-icon: #{escape-svg($accordion-button-icon)};
--#{$prefix}accordion-btn-icon-width: #{$accordion-icon-width};
--#{$prefix}accordion-btn-icon-transform: #{$accordion-icon-transform};
--#{$prefix}accordion-btn-icon-transition: #{$accordion-icon-transition};
--#{$prefix}accordion-btn-active-icon: #{escape-svg($accordion-button-active-icon)};
--#{$prefix}accordion-btn-focus-border-color: #{$accordion-button-focus-border-color};
--#{$prefix}accordion-btn-focus-box-shadow: #{$accordion-button-focus-box-shadow};
--#{$prefix}accordion-body-padding-x: #{$accordion-body-padding-x};
--#{$prefix}accordion-body-padding-y: #{$accordion-body-padding-y};
--#{$prefix}accordion-active-color: #{$accordion-button-active-color};
--#{$prefix}accordion-active-bg: #{$accordion-button-active-bg};
// scss-docs-end accordion-css-vars
}
.accordion-button {
position: relative;
display: flex;
align-items: center;
width: 100%;
padding: var(--#{$prefix}accordion-btn-padding-y) var(--#{$prefix}accordion-btn-padding-x);
@include font-size($font-size-base);
color: var(--#{$prefix}accordion-btn-color);
text-align: left; // Reset button style
background-color: var(--#{$prefix}accordion-btn-bg);
border: 0;
@include border-radius(0);
overflow-anchor: none;
@include transition(var(--#{$prefix}accordion-transition));
&:not(.collapsed) {
color: var(--#{$prefix}accordion-active-color);
background-color: var(--#{$prefix}accordion-active-bg);
box-shadow: inset 0 calc(-1 * var(--#{$prefix}accordion-border-width)) 0 var(--#{$prefix}accordion-border-color); // stylelint-disable-line function-disallowed-list
&::after {
background-image: var(--#{$prefix}accordion-btn-active-icon);
transform: var(--#{$prefix}accordion-btn-icon-transform);
}
}
// Accordion icon
&::after {
flex-shrink: 0;
width: var(--#{$prefix}accordion-btn-icon-width);
height: var(--#{$prefix}accordion-btn-icon-width);
margin-left: auto;
content: "";
background-image: var(--#{$prefix}accordion-btn-icon);
background-repeat: no-repeat;
background-size: var(--#{$prefix}accordion-btn-icon-width);
@include transition(var(--#{$prefix}accordion-btn-icon-transition));
}
&:hover {
z-index: 2;
}
&:focus {
z-index: 3;
border-color: var(--#{$prefix}accordion-btn-focus-border-color);
outline: 0;
box-shadow: var(--#{$prefix}accordion-btn-focus-box-shadow);
}
}
.accordion-header {
margin-bottom: 0;
}
.accordion-item {
color: var(--#{$prefix}accordion-color);
background-color: var(--#{$prefix}accordion-bg);
border: var(--#{$prefix}accordion-border-width) solid var(--#{$prefix}accordion-border-color);
&:first-of-type {
@include border-top-radius(var(--#{$prefix}accordion-border-radius));
.accordion-button {
@include border-top-radius(var(--#{$prefix}accordion-inner-border-radius));
}
}
&:not(:first-of-type) {
border-top: 0;
}
// Only set a border-radius on the last item if the accordion is collapsed
&:last-of-type {
@include border-bottom-radius(var(--#{$prefix}accordion-border-radius));
.accordion-button {
&.collapsed {
@include border-bottom-radius(var(--#{$prefix}accordion-inner-border-radius));
}
}
.accordion-collapse {
@include border-bottom-radius(var(--#{$prefix}accordion-border-radius));
}
}
}
.accordion-body {
padding: var(--#{$prefix}accordion-body-padding-y) var(--#{$prefix}accordion-body-padding-x);
}
// Flush accordion items
//
// Remove borders and border-radius to keep accordion items edge-to-edge.
.accordion-flush {
.accordion-collapse {
border-width: 0;
}
.accordion-item {
border-right: 0;
border-left: 0;
@include border-radius(0);
&:first-child { border-top: 0; }
&:last-child { border-bottom: 0; }
.accordion-button {
&,
&.collapsed {
@include border-radius(0);
}
}
}
}
@if $enable-dark-mode {
@include color-mode(dark) {
.accordion-button::after {
--#{$prefix}accordion-btn-icon: #{escape-svg($accordion-button-icon-dark)};
--#{$prefix}accordion-btn-active-icon: #{escape-svg($accordion-button-active-icon-dark)};
}
}
}

View File

@ -0,0 +1,68 @@
//
// Base styles
//
.alert {
// scss-docs-start alert-css-vars
--#{$prefix}alert-bg: transparent;
--#{$prefix}alert-padding-x: #{$alert-padding-x};
--#{$prefix}alert-padding-y: #{$alert-padding-y};
--#{$prefix}alert-margin-bottom: #{$alert-margin-bottom};
--#{$prefix}alert-color: inherit;
--#{$prefix}alert-border-color: transparent;
--#{$prefix}alert-border: #{$alert-border-width} solid var(--#{$prefix}alert-border-color);
--#{$prefix}alert-border-radius: #{$alert-border-radius};
--#{$prefix}alert-link-color: inherit;
// scss-docs-end alert-css-vars
position: relative;
padding: var(--#{$prefix}alert-padding-y) var(--#{$prefix}alert-padding-x);
margin-bottom: var(--#{$prefix}alert-margin-bottom);
color: var(--#{$prefix}alert-color);
background-color: var(--#{$prefix}alert-bg);
border: var(--#{$prefix}alert-border);
@include border-radius(var(--#{$prefix}alert-border-radius));
}
// Headings for larger alerts
.alert-heading {
// Specified to prevent conflicts of changing $headings-color
color: inherit;
}
// Provide class for links that match alerts
.alert-link {
font-weight: $alert-link-font-weight;
color: var(--#{$prefix}alert-link-color);
}
// Dismissible alerts
//
// Expand the right padding and account for the close button's positioning.
.alert-dismissible {
padding-right: $alert-dismissible-padding-r;
// Adjust close link position
.btn-close {
position: absolute;
top: 0;
right: 0;
z-index: $stretched-link-z-index + 1;
padding: $alert-padding-y * 1.25 $alert-padding-x;
}
}
// scss-docs-start alert-modifiers
// Generate contextual modifier classes for colorizing the alert
@each $state in map-keys($theme-colors) {
.alert-#{$state} {
--#{$prefix}alert-color: var(--#{$prefix}#{$state}-text-emphasis);
--#{$prefix}alert-bg: var(--#{$prefix}#{$state}-bg-subtle);
--#{$prefix}alert-border-color: var(--#{$prefix}#{$state}-border-subtle);
--#{$prefix}alert-link-color: var(--#{$prefix}#{$state}-text-emphasis);
}
}
// scss-docs-end alert-modifiers

View File

@ -0,0 +1,38 @@
// Base class
//
// Requires one of the contextual, color modifier classes for `color` and
// `background-color`.
.badge {
// scss-docs-start badge-css-vars
--#{$prefix}badge-padding-x: #{$badge-padding-x};
--#{$prefix}badge-padding-y: #{$badge-padding-y};
@include rfs($badge-font-size, --#{$prefix}badge-font-size);
--#{$prefix}badge-font-weight: #{$badge-font-weight};
--#{$prefix}badge-color: #{$badge-color};
--#{$prefix}badge-border-radius: #{$badge-border-radius};
// scss-docs-end badge-css-vars
display: inline-block;
padding: var(--#{$prefix}badge-padding-y) var(--#{$prefix}badge-padding-x);
@include font-size(var(--#{$prefix}badge-font-size));
font-weight: var(--#{$prefix}badge-font-weight);
line-height: 1;
color: var(--#{$prefix}badge-color);
text-align: center;
white-space: nowrap;
vertical-align: baseline;
@include border-radius(var(--#{$prefix}badge-border-radius));
@include gradient-bg();
// Empty badges collapse automatically
&:empty {
display: none;
}
}
// Quick fix for badges in buttons
.btn .badge {
position: relative;
top: -1px;
}

View File

@ -0,0 +1,40 @@
.breadcrumb {
// scss-docs-start breadcrumb-css-vars
--#{$prefix}breadcrumb-padding-x: #{$breadcrumb-padding-x};
--#{$prefix}breadcrumb-padding-y: #{$breadcrumb-padding-y};
--#{$prefix}breadcrumb-margin-bottom: #{$breadcrumb-margin-bottom};
@include rfs($breadcrumb-font-size, --#{$prefix}breadcrumb-font-size);
--#{$prefix}breadcrumb-bg: #{$breadcrumb-bg};
--#{$prefix}breadcrumb-border-radius: #{$breadcrumb-border-radius};
--#{$prefix}breadcrumb-divider-color: #{$breadcrumb-divider-color};
--#{$prefix}breadcrumb-item-padding-x: #{$breadcrumb-item-padding-x};
--#{$prefix}breadcrumb-item-active-color: #{$breadcrumb-active-color};
// scss-docs-end breadcrumb-css-vars
display: flex;
flex-wrap: wrap;
padding: var(--#{$prefix}breadcrumb-padding-y) var(--#{$prefix}breadcrumb-padding-x);
margin-bottom: var(--#{$prefix}breadcrumb-margin-bottom);
@include font-size(var(--#{$prefix}breadcrumb-font-size));
list-style: none;
background-color: var(--#{$prefix}breadcrumb-bg);
@include border-radius(var(--#{$prefix}breadcrumb-border-radius));
}
.breadcrumb-item {
// The separator between breadcrumbs (by default, a forward-slash: "/")
+ .breadcrumb-item {
padding-left: var(--#{$prefix}breadcrumb-item-padding-x);
&::before {
float: left; // Suppress inline spacings and underlining of the separator
padding-right: var(--#{$prefix}breadcrumb-item-padding-x);
color: var(--#{$prefix}breadcrumb-divider-color);
content: var(--#{$prefix}breadcrumb-divider, escape-svg($breadcrumb-divider)) #{"/* rtl:"} var(--#{$prefix}breadcrumb-divider, escape-svg($breadcrumb-divider-flipped)) #{"*/"};
}
}
&.active {
color: var(--#{$prefix}breadcrumb-item-active-color);
}
}

View File

@ -0,0 +1,142 @@
// Make the div behave like a button
.btn-group,
.btn-group-vertical {
position: relative;
display: inline-flex;
vertical-align: middle; // match .btn alignment given font-size hack above
> .btn {
position: relative;
flex: 1 1 auto;
}
// Bring the hover, focused, and "active" buttons to the front to overlay
// the borders properly
> .btn-check:checked + .btn,
> .btn-check:focus + .btn,
> .btn:hover,
> .btn:focus,
> .btn:active,
> .btn.active {
z-index: 1;
}
}
// Optional: Group multiple button groups together for a toolbar
.btn-toolbar {
display: flex;
flex-wrap: wrap;
justify-content: flex-start;
.input-group {
width: auto;
}
}
.btn-group {
@include border-radius($btn-border-radius);
// Prevent double borders when buttons are next to each other
> :not(.btn-check:first-child) + .btn,
> .btn-group:not(:first-child) {
margin-left: calc(#{$btn-border-width} * -1); // stylelint-disable-line function-disallowed-list
}
// Reset rounded corners
> .btn:not(:last-child):not(.dropdown-toggle),
> .btn.dropdown-toggle-split:first-child,
> .btn-group:not(:last-child) > .btn {
@include border-end-radius(0);
}
// The left radius should be 0 if the button is:
// - the "third or more" child
// - the second child and the previous element isn't `.btn-check` (making it the first child visually)
// - part of a btn-group which isn't the first child
> .btn:nth-child(n + 3),
> :not(.btn-check) + .btn,
> .btn-group:not(:first-child) > .btn {
@include border-start-radius(0);
}
}
// Sizing
//
// Remix the default button sizing classes into new ones for easier manipulation.
.btn-group-sm > .btn { @extend .btn-sm; }
.btn-group-lg > .btn { @extend .btn-lg; }
//
// Split button dropdowns
//
.dropdown-toggle-split {
padding-right: $btn-padding-x * .75;
padding-left: $btn-padding-x * .75;
&::after,
.dropup &::after,
.dropend &::after {
margin-left: 0;
}
.dropstart &::before {
margin-right: 0;
}
}
.btn-sm + .dropdown-toggle-split {
padding-right: $btn-padding-x-sm * .75;
padding-left: $btn-padding-x-sm * .75;
}
.btn-lg + .dropdown-toggle-split {
padding-right: $btn-padding-x-lg * .75;
padding-left: $btn-padding-x-lg * .75;
}
// The clickable button for toggling the menu
// Set the same inset shadow as the :active state
.btn-group.show .dropdown-toggle {
@include box-shadow($btn-active-box-shadow);
// Show no shadow for `.btn-link` since it has no other button styles.
&.btn-link {
@include box-shadow(none);
}
}
//
// Vertical button groups
//
.btn-group-vertical {
flex-direction: column;
align-items: flex-start;
justify-content: center;
> .btn,
> .btn-group {
width: 100%;
}
> .btn:not(:first-child),
> .btn-group:not(:first-child) {
margin-top: calc(#{$btn-border-width} * -1); // stylelint-disable-line function-disallowed-list
}
// Reset rounded corners
> .btn:not(:last-child):not(.dropdown-toggle),
> .btn-group:not(:last-child) > .btn {
@include border-bottom-radius(0);
}
> .btn ~ .btn,
> .btn-group:not(:first-child) > .btn {
@include border-top-radius(0);
}
}

View File

@ -0,0 +1,207 @@
//
// Base styles
//
.btn {
// scss-docs-start btn-css-vars
--#{$prefix}btn-padding-x: #{$btn-padding-x};
--#{$prefix}btn-padding-y: #{$btn-padding-y};
--#{$prefix}btn-font-family: #{$btn-font-family};
@include rfs($btn-font-size, --#{$prefix}btn-font-size);
--#{$prefix}btn-font-weight: #{$btn-font-weight};
--#{$prefix}btn-line-height: #{$btn-line-height};
--#{$prefix}btn-color: #{$btn-color};
--#{$prefix}btn-bg: transparent;
--#{$prefix}btn-border-width: #{$btn-border-width};
--#{$prefix}btn-border-color: transparent;
--#{$prefix}btn-border-radius: #{$btn-border-radius};
--#{$prefix}btn-hover-border-color: transparent;
--#{$prefix}btn-box-shadow: #{$btn-box-shadow};
--#{$prefix}btn-disabled-opacity: #{$btn-disabled-opacity};
--#{$prefix}btn-focus-box-shadow: 0 0 0 #{$btn-focus-width} rgba(var(--#{$prefix}btn-focus-shadow-rgb), .5);
// scss-docs-end btn-css-vars
display: inline-block;
padding: var(--#{$prefix}btn-padding-y) var(--#{$prefix}btn-padding-x);
font-family: var(--#{$prefix}btn-font-family);
@include font-size(var(--#{$prefix}btn-font-size));
font-weight: var(--#{$prefix}btn-font-weight);
line-height: var(--#{$prefix}btn-line-height);
color: var(--#{$prefix}btn-color);
text-align: center;
text-decoration: if($link-decoration == none, null, none);
white-space: $btn-white-space;
vertical-align: middle;
cursor: if($enable-button-pointers, pointer, null);
user-select: none;
border: var(--#{$prefix}btn-border-width) solid var(--#{$prefix}btn-border-color);
@include border-radius(var(--#{$prefix}btn-border-radius));
@include gradient-bg(var(--#{$prefix}btn-bg));
@include box-shadow(var(--#{$prefix}btn-box-shadow));
@include transition($btn-transition);
&:hover {
color: var(--#{$prefix}btn-hover-color);
text-decoration: if($link-hover-decoration == underline, none, null);
background-color: var(--#{$prefix}btn-hover-bg);
border-color: var(--#{$prefix}btn-hover-border-color);
}
.btn-check + &:hover {
// override for the checkbox/radio buttons
color: var(--#{$prefix}btn-color);
background-color: var(--#{$prefix}btn-bg);
border-color: var(--#{$prefix}btn-border-color);
}
&:focus-visible {
color: var(--#{$prefix}btn-hover-color);
@include gradient-bg(var(--#{$prefix}btn-hover-bg));
border-color: var(--#{$prefix}btn-hover-border-color);
outline: 0;
// Avoid using mixin so we can pass custom focus shadow properly
@if $enable-shadows {
box-shadow: var(--#{$prefix}btn-box-shadow), var(--#{$prefix}btn-focus-box-shadow);
} @else {
box-shadow: var(--#{$prefix}btn-focus-box-shadow);
}
}
.btn-check:focus-visible + & {
border-color: var(--#{$prefix}btn-hover-border-color);
outline: 0;
// Avoid using mixin so we can pass custom focus shadow properly
@if $enable-shadows {
box-shadow: var(--#{$prefix}btn-box-shadow), var(--#{$prefix}btn-focus-box-shadow);
} @else {
box-shadow: var(--#{$prefix}btn-focus-box-shadow);
}
}
.btn-check:checked + &,
:not(.btn-check) + &:active,
&:first-child:active,
&.active,
&.show {
color: var(--#{$prefix}btn-active-color);
background-color: var(--#{$prefix}btn-active-bg);
// Remove CSS gradients if they're enabled
background-image: if($enable-gradients, none, null);
border-color: var(--#{$prefix}btn-active-border-color);
@include box-shadow(var(--#{$prefix}btn-active-shadow));
&:focus-visible {
// Avoid using mixin so we can pass custom focus shadow properly
@if $enable-shadows {
box-shadow: var(--#{$prefix}btn-active-shadow), var(--#{$prefix}btn-focus-box-shadow);
} @else {
box-shadow: var(--#{$prefix}btn-focus-box-shadow);
}
}
}
&:disabled,
&.disabled,
fieldset:disabled & {
color: var(--#{$prefix}btn-disabled-color);
pointer-events: none;
background-color: var(--#{$prefix}btn-disabled-bg);
background-image: if($enable-gradients, none, null);
border-color: var(--#{$prefix}btn-disabled-border-color);
opacity: var(--#{$prefix}btn-disabled-opacity);
@include box-shadow(none);
}
}
//
// Alternate buttons
//
// scss-docs-start btn-variant-loops
@each $color, $value in $theme-colors {
.btn-#{$color} {
@if $color == "light" {
@include button-variant(
$value,
$value,
$hover-background: shade-color($value, $btn-hover-bg-shade-amount),
$hover-border: shade-color($value, $btn-hover-border-shade-amount),
$active-background: shade-color($value, $btn-active-bg-shade-amount),
$active-border: shade-color($value, $btn-active-border-shade-amount)
);
} @else if $color == "dark" {
@include button-variant(
$value,
$value,
$hover-background: tint-color($value, $btn-hover-bg-tint-amount),
$hover-border: tint-color($value, $btn-hover-border-tint-amount),
$active-background: tint-color($value, $btn-active-bg-tint-amount),
$active-border: tint-color($value, $btn-active-border-tint-amount)
);
} @else {
@include button-variant($value, $value);
}
}
}
@each $color, $value in $theme-colors {
.btn-outline-#{$color} {
@include button-outline-variant($value);
}
}
// scss-docs-end btn-variant-loops
//
// Link buttons
//
// Make a button look and behave like a link
.btn-link {
--#{$prefix}btn-font-weight: #{$font-weight-normal};
--#{$prefix}btn-color: #{$btn-link-color};
--#{$prefix}btn-bg: transparent;
--#{$prefix}btn-border-color: transparent;
--#{$prefix}btn-hover-color: #{$btn-link-hover-color};
--#{$prefix}btn-hover-border-color: transparent;
--#{$prefix}btn-active-color: #{$btn-link-hover-color};
--#{$prefix}btn-active-border-color: transparent;
--#{$prefix}btn-disabled-color: #{$btn-link-disabled-color};
--#{$prefix}btn-disabled-border-color: transparent;
--#{$prefix}btn-box-shadow: 0 0 0 #000; // Can't use `none` as keyword negates all values when used with multiple shadows
--#{$prefix}btn-focus-shadow-rgb: #{to-rgb(mix(color-contrast($link-color), $link-color, 15%))};
text-decoration: $link-decoration;
@if $enable-gradients {
background-image: none;
}
&:hover,
&:focus-visible {
text-decoration: $link-hover-decoration;
}
&:focus-visible {
color: var(--#{$prefix}btn-color);
}
&:hover {
color: var(--#{$prefix}btn-hover-color);
}
// No need for an active state here
}
//
// Button Sizes
//
.btn-lg {
@include button-size($btn-padding-y-lg, $btn-padding-x-lg, $btn-font-size-lg, $btn-border-radius-lg);
}
.btn-sm {
@include button-size($btn-padding-y-sm, $btn-padding-x-sm, $btn-font-size-sm, $btn-border-radius-sm);
}

View File

@ -0,0 +1,239 @@
//
// Base styles
//
.card {
// scss-docs-start card-css-vars
--#{$prefix}card-spacer-y: #{$card-spacer-y};
--#{$prefix}card-spacer-x: #{$card-spacer-x};
--#{$prefix}card-title-spacer-y: #{$card-title-spacer-y};
--#{$prefix}card-title-color: #{$card-title-color};
--#{$prefix}card-subtitle-color: #{$card-subtitle-color};
--#{$prefix}card-border-width: #{$card-border-width};
--#{$prefix}card-border-color: #{$card-border-color};
--#{$prefix}card-border-radius: #{$card-border-radius};
--#{$prefix}card-box-shadow: #{$card-box-shadow};
--#{$prefix}card-inner-border-radius: #{$card-inner-border-radius};
--#{$prefix}card-cap-padding-y: #{$card-cap-padding-y};
--#{$prefix}card-cap-padding-x: #{$card-cap-padding-x};
--#{$prefix}card-cap-bg: #{$card-cap-bg};
--#{$prefix}card-cap-color: #{$card-cap-color};
--#{$prefix}card-height: #{$card-height};
--#{$prefix}card-color: #{$card-color};
--#{$prefix}card-bg: #{$card-bg};
--#{$prefix}card-img-overlay-padding: #{$card-img-overlay-padding};
--#{$prefix}card-group-margin: #{$card-group-margin};
// scss-docs-end card-css-vars
position: relative;
display: flex;
flex-direction: column;
min-width: 0; // See https://github.com/twbs/bootstrap/pull/22740#issuecomment-305868106
height: var(--#{$prefix}card-height);
color: var(--#{$prefix}body-color);
word-wrap: break-word;
background-color: var(--#{$prefix}card-bg);
background-clip: border-box;
border: var(--#{$prefix}card-border-width) solid var(--#{$prefix}card-border-color);
@include border-radius(var(--#{$prefix}card-border-radius));
@include box-shadow(var(--#{$prefix}card-box-shadow));
> hr {
margin-right: 0;
margin-left: 0;
}
> .list-group {
border-top: inherit;
border-bottom: inherit;
&:first-child {
border-top-width: 0;
@include border-top-radius(var(--#{$prefix}card-inner-border-radius));
}
&:last-child {
border-bottom-width: 0;
@include border-bottom-radius(var(--#{$prefix}card-inner-border-radius));
}
}
// Due to specificity of the above selector (`.card > .list-group`), we must
// use a child selector here to prevent double borders.
> .card-header + .list-group,
> .list-group + .card-footer {
border-top: 0;
}
}
.card-body {
// Enable `flex-grow: 1` for decks and groups so that card blocks take up
// as much space as possible, ensuring footers are aligned to the bottom.
flex: 1 1 auto;
padding: var(--#{$prefix}card-spacer-y) var(--#{$prefix}card-spacer-x);
color: var(--#{$prefix}card-color);
}
.card-title {
margin-bottom: var(--#{$prefix}card-title-spacer-y);
color: var(--#{$prefix}card-title-color);
}
.card-subtitle {
margin-top: calc(-.5 * var(--#{$prefix}card-title-spacer-y)); // stylelint-disable-line function-disallowed-list
margin-bottom: 0;
color: var(--#{$prefix}card-subtitle-color);
}
.card-text:last-child {
margin-bottom: 0;
}
.card-link {
&:hover {
text-decoration: if($link-hover-decoration == underline, none, null);
}
+ .card-link {
margin-left: var(--#{$prefix}card-spacer-x);
}
}
//
// Optional textual caps
//
.card-header {
padding: var(--#{$prefix}card-cap-padding-y) var(--#{$prefix}card-cap-padding-x);
margin-bottom: 0; // Removes the default margin-bottom of <hN>
color: var(--#{$prefix}card-cap-color);
background-color: var(--#{$prefix}card-cap-bg);
border-bottom: var(--#{$prefix}card-border-width) solid var(--#{$prefix}card-border-color);
&:first-child {
@include border-radius(var(--#{$prefix}card-inner-border-radius) var(--#{$prefix}card-inner-border-radius) 0 0);
}
}
.card-footer {
padding: var(--#{$prefix}card-cap-padding-y) var(--#{$prefix}card-cap-padding-x);
color: var(--#{$prefix}card-cap-color);
background-color: var(--#{$prefix}card-cap-bg);
border-top: var(--#{$prefix}card-border-width) solid var(--#{$prefix}card-border-color);
&:last-child {
@include border-radius(0 0 var(--#{$prefix}card-inner-border-radius) var(--#{$prefix}card-inner-border-radius));
}
}
//
// Header navs
//
.card-header-tabs {
margin-right: calc(-.5 * var(--#{$prefix}card-cap-padding-x)); // stylelint-disable-line function-disallowed-list
margin-bottom: calc(-1 * var(--#{$prefix}card-cap-padding-y)); // stylelint-disable-line function-disallowed-list
margin-left: calc(-.5 * var(--#{$prefix}card-cap-padding-x)); // stylelint-disable-line function-disallowed-list
border-bottom: 0;
.nav-link.active {
background-color: var(--#{$prefix}card-bg);
border-bottom-color: var(--#{$prefix}card-bg);
}
}
.card-header-pills {
margin-right: calc(-.5 * var(--#{$prefix}card-cap-padding-x)); // stylelint-disable-line function-disallowed-list
margin-left: calc(-.5 * var(--#{$prefix}card-cap-padding-x)); // stylelint-disable-line function-disallowed-list
}
// Card image
.card-img-overlay {
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
padding: var(--#{$prefix}card-img-overlay-padding);
@include border-radius(var(--#{$prefix}card-inner-border-radius));
}
.card-img,
.card-img-top,
.card-img-bottom {
width: 100%; // Required because we use flexbox and this inherently applies align-self: stretch
}
.card-img,
.card-img-top {
@include border-top-radius(var(--#{$prefix}card-inner-border-radius));
}
.card-img,
.card-img-bottom {
@include border-bottom-radius(var(--#{$prefix}card-inner-border-radius));
}
//
// Card groups
//
.card-group {
// The child selector allows nested `.card` within `.card-group`
// to display properly.
> .card {
margin-bottom: var(--#{$prefix}card-group-margin);
}
@include media-breakpoint-up(sm) {
display: flex;
flex-flow: row wrap;
// The child selector allows nested `.card` within `.card-group`
// to display properly.
> .card {
// Flexbugs #4: https://github.com/philipwalton/flexbugs#flexbug-4
flex: 1 0 0%;
margin-bottom: 0;
+ .card {
margin-left: 0;
border-left: 0;
}
// Handle rounded corners
@if $enable-rounded {
&:not(:last-child) {
@include border-end-radius(0);
.card-img-top,
.card-header {
// stylelint-disable-next-line property-disallowed-list
border-top-right-radius: 0;
}
.card-img-bottom,
.card-footer {
// stylelint-disable-next-line property-disallowed-list
border-bottom-right-radius: 0;
}
}
&:not(:first-child) {
@include border-start-radius(0);
.card-img-top,
.card-header {
// stylelint-disable-next-line property-disallowed-list
border-top-left-radius: 0;
}
.card-img-bottom,
.card-footer {
// stylelint-disable-next-line property-disallowed-list
border-bottom-left-radius: 0;
}
}
}
}
}
}

View File

@ -0,0 +1,244 @@
// Notes on the classes:
//
// 1. .carousel.pointer-event should ideally be pan-y (to allow for users to scroll vertically)
// even when their scroll action started on a carousel, but for compatibility (with Firefox)
// we're preventing all actions instead
// 2. The .carousel-item-start and .carousel-item-end is used to indicate where
// the active slide is heading.
// 3. .active.carousel-item is the current slide.
// 4. .active.carousel-item-start and .active.carousel-item-end is the current
// slide in its in-transition state. Only one of these occurs at a time.
// 5. .carousel-item-next.carousel-item-start and .carousel-item-prev.carousel-item-end
// is the upcoming slide in transition.
.carousel {
position: relative;
}
.carousel.pointer-event {
touch-action: pan-y;
}
.carousel-inner {
position: relative;
width: 100%;
overflow: hidden;
@include clearfix();
}
.carousel-item {
position: relative;
display: none;
float: left;
width: 100%;
margin-right: -100%;
backface-visibility: hidden;
@include transition($carousel-transition);
}
.carousel-item.active,
.carousel-item-next,
.carousel-item-prev {
display: block;
}
.carousel-item-next:not(.carousel-item-start),
.active.carousel-item-end {
transform: translateX(100%);
}
.carousel-item-prev:not(.carousel-item-end),
.active.carousel-item-start {
transform: translateX(-100%);
}
//
// Alternate transitions
//
.carousel-fade {
.carousel-item {
opacity: 0;
transition-property: opacity;
transform: none;
}
.carousel-item.active,
.carousel-item-next.carousel-item-start,
.carousel-item-prev.carousel-item-end {
z-index: 1;
opacity: 1;
}
.active.carousel-item-start,
.active.carousel-item-end {
z-index: 0;
opacity: 0;
@include transition(opacity 0s $carousel-transition-duration);
}
}
//
// Left/right controls for nav
//
.carousel-control-prev,
.carousel-control-next {
position: absolute;
top: 0;
bottom: 0;
z-index: 1;
// Use flex for alignment (1-3)
display: flex; // 1. allow flex styles
align-items: center; // 2. vertically center contents
justify-content: center; // 3. horizontally center contents
width: $carousel-control-width;
padding: 0;
color: $carousel-control-color;
text-align: center;
background: none;
border: 0;
opacity: $carousel-control-opacity;
@include transition($carousel-control-transition);
// Hover/focus state
&:hover,
&:focus {
color: $carousel-control-color;
text-decoration: none;
outline: 0;
opacity: $carousel-control-hover-opacity;
}
}
.carousel-control-prev {
left: 0;
background-image: if($enable-gradients, linear-gradient(90deg, rgba($black, .25), rgba($black, .001)), null);
}
.carousel-control-next {
right: 0;
background-image: if($enable-gradients, linear-gradient(270deg, rgba($black, .25), rgba($black, .001)), null);
}
// Icons for within
.carousel-control-prev-icon,
.carousel-control-next-icon {
display: inline-block;
width: $carousel-control-icon-width;
height: $carousel-control-icon-width;
background-repeat: no-repeat;
background-position: 50%;
background-size: 100% 100%;
}
/* rtl:options: {
"autoRename": true,
"stringMap":[ {
"name" : "prev-next",
"search" : "prev",
"replace" : "next"
} ]
} */
.carousel-control-prev-icon {
background-image: escape-svg($carousel-control-prev-icon-bg);
}
.carousel-control-next-icon {
background-image: escape-svg($carousel-control-next-icon-bg);
}
// Optional indicator pips/controls
//
// Add a container (such as a list) with the following class and add an item (ideally a focusable control,
// like a button) with data-bs-target for each slide your carousel holds.
.carousel-indicators {
position: absolute;
right: 0;
bottom: 0;
left: 0;
z-index: 2;
display: flex;
justify-content: center;
padding: 0;
// Use the .carousel-control's width as margin so we don't overlay those
margin-right: $carousel-control-width;
margin-bottom: 1rem;
margin-left: $carousel-control-width;
[data-bs-target] {
box-sizing: content-box;
flex: 0 1 auto;
width: $carousel-indicator-width;
height: $carousel-indicator-height;
padding: 0;
margin-right: $carousel-indicator-spacer;
margin-left: $carousel-indicator-spacer;
text-indent: -999px;
cursor: pointer;
background-color: $carousel-indicator-active-bg;
background-clip: padding-box;
border: 0;
// Use transparent borders to increase the hit area by 10px on top and bottom.
border-top: $carousel-indicator-hit-area-height solid transparent;
border-bottom: $carousel-indicator-hit-area-height solid transparent;
opacity: $carousel-indicator-opacity;
@include transition($carousel-indicator-transition);
}
.active {
opacity: $carousel-indicator-active-opacity;
}
}
// Optional captions
//
//
.carousel-caption {
position: absolute;
right: (100% - $carousel-caption-width) * .5;
bottom: $carousel-caption-spacer;
left: (100% - $carousel-caption-width) * .5;
padding-top: $carousel-caption-padding-y;
padding-bottom: $carousel-caption-padding-y;
color: $carousel-caption-color;
text-align: center;
}
// Dark mode carousel
@mixin carousel-dark() {
.carousel-control-prev-icon,
.carousel-control-next-icon {
filter: $carousel-dark-control-icon-filter;
}
.carousel-indicators [data-bs-target] {
background-color: $carousel-dark-indicator-active-bg;
}
.carousel-caption {
color: $carousel-dark-caption-color;
}
}
.carousel-dark {
@include carousel-dark();
}
@if $enable-dark-mode {
@include color-mode(dark) {
@if $color-mode-type == "media-query" {
.carousel {
@include carousel-dark();
}
} @else {
.carousel,
&.carousel {
@include carousel-dark();
}
}
}
}

View File

@ -0,0 +1,63 @@
// Transparent background and border properties included for button version.
// iOS requires the button element instead of an anchor tag.
// If you want the anchor version, it requires `href="#"`.
// See https://developer.mozilla.org/en-US/docs/Web/Events/click#Safari_Mobile
.btn-close {
// scss-docs-start close-css-vars
--#{$prefix}btn-close-color: #{$btn-close-color};
--#{$prefix}btn-close-bg: #{ escape-svg($btn-close-bg) };
--#{$prefix}btn-close-opacity: #{$btn-close-opacity};
--#{$prefix}btn-close-hover-opacity: #{$btn-close-hover-opacity};
--#{$prefix}btn-close-focus-shadow: #{$btn-close-focus-shadow};
--#{$prefix}btn-close-focus-opacity: #{$btn-close-focus-opacity};
--#{$prefix}btn-close-disabled-opacity: #{$btn-close-disabled-opacity};
--#{$prefix}btn-close-white-filter: #{$btn-close-white-filter};
// scss-docs-end close-css-vars
box-sizing: content-box;
width: $btn-close-width;
height: $btn-close-height;
padding: $btn-close-padding-y $btn-close-padding-x;
color: var(--#{$prefix}btn-close-color);
background: transparent var(--#{$prefix}btn-close-bg) center / $btn-close-width auto no-repeat; // include transparent for button elements
border: 0; // for button elements
@include border-radius();
opacity: var(--#{$prefix}btn-close-opacity);
// Override <a>'s hover style
&:hover {
color: var(--#{$prefix}btn-close-color);
text-decoration: none;
opacity: var(--#{$prefix}btn-close-hover-opacity);
}
&:focus {
outline: 0;
box-shadow: var(--#{$prefix}btn-close-focus-shadow);
opacity: var(--#{$prefix}btn-close-focus-opacity);
}
&:disabled,
&.disabled {
pointer-events: none;
user-select: none;
opacity: var(--#{$prefix}btn-close-disabled-opacity);
}
}
@mixin btn-close-white() {
filter: var(--#{$prefix}btn-close-white-filter);
}
.btn-close-white {
@include btn-close-white();
}
@if $enable-dark-mode {
@include color-mode(dark) {
.btn-close {
@include btn-close-white();
}
}
}

View File

@ -0,0 +1,41 @@
// Container widths
//
// Set the container width, and override it for fixed navbars in media queries.
@if $enable-container-classes {
// Single container class with breakpoint max-widths
.container,
// 100% wide container at all breakpoints
.container-fluid {
@include make-container();
}
// Responsive containers that are 100% wide until a breakpoint
@each $breakpoint, $container-max-width in $container-max-widths {
.container-#{$breakpoint} {
@extend .container-fluid;
}
@include media-breakpoint-up($breakpoint, $grid-breakpoints) {
%responsive-container-#{$breakpoint} {
max-width: $container-max-width;
}
// Extend each breakpoint which is smaller or equal to the current breakpoint
$extend-breakpoint: true;
@each $name, $width in $grid-breakpoints {
@if ($extend-breakpoint) {
.container#{breakpoint-infix($name, $grid-breakpoints)} {
@extend %responsive-container-#{$breakpoint};
}
// Once the current breakpoint is reached, stop extending
@if ($breakpoint == $name) {
$extend-breakpoint: false;
}
}
}
}
}
}

View File

@ -0,0 +1,250 @@
// The dropdown wrapper (`<div>`)
.dropup,
.dropend,
.dropdown,
.dropstart,
.dropup-center,
.dropdown-center {
position: relative;
}
.dropdown-toggle {
white-space: nowrap;
// Generate the caret automatically
@include caret();
}
// The dropdown menu
.dropdown-menu {
// scss-docs-start dropdown-css-vars
--#{$prefix}dropdown-zindex: #{$zindex-dropdown};
--#{$prefix}dropdown-min-width: #{$dropdown-min-width};
--#{$prefix}dropdown-padding-x: #{$dropdown-padding-x};
--#{$prefix}dropdown-padding-y: #{$dropdown-padding-y};
--#{$prefix}dropdown-spacer: #{$dropdown-spacer};
@include rfs($dropdown-font-size, --#{$prefix}dropdown-font-size);
--#{$prefix}dropdown-color: #{$dropdown-color};
--#{$prefix}dropdown-bg: #{$dropdown-bg};
--#{$prefix}dropdown-border-color: #{$dropdown-border-color};
--#{$prefix}dropdown-border-radius: #{$dropdown-border-radius};
--#{$prefix}dropdown-border-width: #{$dropdown-border-width};
--#{$prefix}dropdown-inner-border-radius: #{$dropdown-inner-border-radius};
--#{$prefix}dropdown-divider-bg: #{$dropdown-divider-bg};
--#{$prefix}dropdown-divider-margin-y: #{$dropdown-divider-margin-y};
--#{$prefix}dropdown-box-shadow: #{$dropdown-box-shadow};
--#{$prefix}dropdown-link-color: #{$dropdown-link-color};
--#{$prefix}dropdown-link-hover-color: #{$dropdown-link-hover-color};
--#{$prefix}dropdown-link-hover-bg: #{$dropdown-link-hover-bg};
--#{$prefix}dropdown-link-active-color: #{$dropdown-link-active-color};
--#{$prefix}dropdown-link-active-bg: #{$dropdown-link-active-bg};
--#{$prefix}dropdown-link-disabled-color: #{$dropdown-link-disabled-color};
--#{$prefix}dropdown-item-padding-x: #{$dropdown-item-padding-x};
--#{$prefix}dropdown-item-padding-y: #{$dropdown-item-padding-y};
--#{$prefix}dropdown-header-color: #{$dropdown-header-color};
--#{$prefix}dropdown-header-padding-x: #{$dropdown-header-padding-x};
--#{$prefix}dropdown-header-padding-y: #{$dropdown-header-padding-y};
// scss-docs-end dropdown-css-vars
position: absolute;
z-index: var(--#{$prefix}dropdown-zindex);
display: none; // none by default, but block on "open" of the menu
min-width: var(--#{$prefix}dropdown-min-width);
padding: var(--#{$prefix}dropdown-padding-y) var(--#{$prefix}dropdown-padding-x);
margin: 0; // Override default margin of ul
@include font-size(var(--#{$prefix}dropdown-font-size));
color: var(--#{$prefix}dropdown-color);
text-align: left; // Ensures proper alignment if parent has it changed (e.g., modal footer)
list-style: none;
background-color: var(--#{$prefix}dropdown-bg);
background-clip: padding-box;
border: var(--#{$prefix}dropdown-border-width) solid var(--#{$prefix}dropdown-border-color);
@include border-radius(var(--#{$prefix}dropdown-border-radius));
@include box-shadow(var(--#{$prefix}dropdown-box-shadow));
&[data-bs-popper] {
top: 100%;
left: 0;
margin-top: var(--#{$prefix}dropdown-spacer);
}
@if $dropdown-padding-y == 0 {
> .dropdown-item:first-child,
> li:first-child .dropdown-item {
@include border-top-radius(var(--#{$prefix}dropdown-inner-border-radius));
}
> .dropdown-item:last-child,
> li:last-child .dropdown-item {
@include border-bottom-radius(var(--#{$prefix}dropdown-inner-border-radius));
}
}
}
// scss-docs-start responsive-breakpoints
// We deliberately hardcode the `bs-` prefix because we check
// this custom property in JS to determine Popper's positioning
@each $breakpoint in map-keys($grid-breakpoints) {
@include media-breakpoint-up($breakpoint) {
$infix: breakpoint-infix($breakpoint, $grid-breakpoints);
.dropdown-menu#{$infix}-start {
--bs-position: start;
&[data-bs-popper] {
right: auto;
left: 0;
}
}
.dropdown-menu#{$infix}-end {
--bs-position: end;
&[data-bs-popper] {
right: 0;
left: auto;
}
}
}
}
// scss-docs-end responsive-breakpoints
// Allow for dropdowns to go bottom up (aka, dropup-menu)
// Just add .dropup after the standard .dropdown class and you're set.
.dropup {
.dropdown-menu[data-bs-popper] {
top: auto;
bottom: 100%;
margin-top: 0;
margin-bottom: var(--#{$prefix}dropdown-spacer);
}
.dropdown-toggle {
@include caret(up);
}
}
.dropend {
.dropdown-menu[data-bs-popper] {
top: 0;
right: auto;
left: 100%;
margin-top: 0;
margin-left: var(--#{$prefix}dropdown-spacer);
}
.dropdown-toggle {
@include caret(end);
&::after {
vertical-align: 0;
}
}
}
.dropstart {
.dropdown-menu[data-bs-popper] {
top: 0;
right: 100%;
left: auto;
margin-top: 0;
margin-right: var(--#{$prefix}dropdown-spacer);
}
.dropdown-toggle {
@include caret(start);
&::before {
vertical-align: 0;
}
}
}
// Dividers (basically an `<hr>`) within the dropdown
.dropdown-divider {
height: 0;
margin: var(--#{$prefix}dropdown-divider-margin-y) 0;
overflow: hidden;
border-top: 1px solid var(--#{$prefix}dropdown-divider-bg);
opacity: 1; // Revisit in v6 to de-dupe styles that conflict with <hr> element
}
// Links, buttons, and more within the dropdown menu
//
// `<button>`-specific styles are denoted with `// For <button>s`
.dropdown-item {
display: block;
width: 100%; // For `<button>`s
padding: var(--#{$prefix}dropdown-item-padding-y) var(--#{$prefix}dropdown-item-padding-x);
clear: both;
font-weight: $font-weight-normal;
color: var(--#{$prefix}dropdown-link-color);
text-align: inherit; // For `<button>`s
text-decoration: if($link-decoration == none, null, none);
white-space: nowrap; // prevent links from randomly breaking onto new lines
background-color: transparent; // For `<button>`s
border: 0; // For `<button>`s
@include border-radius(var(--#{$prefix}dropdown-item-border-radius, 0));
&:hover,
&:focus {
color: var(--#{$prefix}dropdown-link-hover-color);
text-decoration: if($link-hover-decoration == underline, none, null);
@include gradient-bg(var(--#{$prefix}dropdown-link-hover-bg));
}
&.active,
&:active {
color: var(--#{$prefix}dropdown-link-active-color);
text-decoration: none;
@include gradient-bg(var(--#{$prefix}dropdown-link-active-bg));
}
&.disabled,
&:disabled {
color: var(--#{$prefix}dropdown-link-disabled-color);
pointer-events: none;
background-color: transparent;
// Remove CSS gradients if they're enabled
background-image: if($enable-gradients, none, null);
}
}
.dropdown-menu.show {
display: block;
}
// Dropdown section headers
.dropdown-header {
display: block;
padding: var(--#{$prefix}dropdown-header-padding-y) var(--#{$prefix}dropdown-header-padding-x);
margin-bottom: 0; // for use with heading elements
@include font-size($font-size-sm);
color: var(--#{$prefix}dropdown-header-color);
white-space: nowrap; // as with > li > a
}
// Dropdown text
.dropdown-item-text {
display: block;
padding: var(--#{$prefix}dropdown-item-padding-y) var(--#{$prefix}dropdown-item-padding-x);
color: var(--#{$prefix}dropdown-link-color);
}
// Dark dropdowns
.dropdown-menu-dark {
// scss-docs-start dropdown-dark-css-vars
--#{$prefix}dropdown-color: #{$dropdown-dark-color};
--#{$prefix}dropdown-bg: #{$dropdown-dark-bg};
--#{$prefix}dropdown-border-color: #{$dropdown-dark-border-color};
--#{$prefix}dropdown-box-shadow: #{$dropdown-dark-box-shadow};
--#{$prefix}dropdown-link-color: #{$dropdown-dark-link-color};
--#{$prefix}dropdown-link-hover-color: #{$dropdown-dark-link-hover-color};
--#{$prefix}dropdown-divider-bg: #{$dropdown-dark-divider-bg};
--#{$prefix}dropdown-link-hover-bg: #{$dropdown-dark-link-hover-bg};
--#{$prefix}dropdown-link-active-color: #{$dropdown-dark-link-active-color};
--#{$prefix}dropdown-link-active-bg: #{$dropdown-dark-link-active-bg};
--#{$prefix}dropdown-link-disabled-color: #{$dropdown-dark-link-disabled-color};
--#{$prefix}dropdown-header-color: #{$dropdown-dark-header-color};
// scss-docs-end dropdown-dark-css-vars
}

View File

@ -0,0 +1,19 @@
@font-face {
font-family: 'Atkinson Hyperlegible';
src: url('/fonts/AtkinsonHyperlegible-Regular.woff2') format('woff2'),
url('/fonts/AtkinsonHyperlegible-Regular.woff') format('woff');
font-weight: normal;
font-style: normal;
font-display: swap;
}
@font-face {
font-family: 'Bitter';
src: url('/fonts/Bitter-Medium.woff2') format('woff2'),
url('/fonts/Bitter-Medium.woff') format('woff');
font-weight: normal;
font-style: normal;
font-display: swap;
}

View File

@ -0,0 +1,9 @@
@import "forms/labels";
@import "forms/form-text";
@import "forms/form-control";
@import "forms/form-select";
@import "forms/form-check";
@import "forms/form-range";
@import "forms/floating-labels";
@import "forms/input-group";
@import "forms/validation";

View File

@ -0,0 +1,302 @@
// Bootstrap functions
//
// Utility mixins and functions for evaluating source code across our variables, maps, and mixins.
// Ascending
// Used to evaluate Sass maps like our grid breakpoints.
@mixin _assert-ascending($map, $map-name) {
$prev-key: null;
$prev-num: null;
@each $key, $num in $map {
@if $prev-num == null or unit($num) == "%" or unit($prev-num) == "%" {
// Do nothing
} @else if not comparable($prev-num, $num) {
@warn "Potentially invalid value for #{$map-name}: This map must be in ascending order, but key '#{$key}' has value #{$num} whose unit makes it incomparable to #{$prev-num}, the value of the previous key '#{$prev-key}' !";
} @else if $prev-num >= $num {
@warn "Invalid value for #{$map-name}: This map must be in ascending order, but key '#{$key}' has value #{$num} which isn't greater than #{$prev-num}, the value of the previous key '#{$prev-key}' !";
}
$prev-key: $key;
$prev-num: $num;
}
}
// Starts at zero
// Used to ensure the min-width of the lowest breakpoint starts at 0.
@mixin _assert-starts-at-zero($map, $map-name: "$grid-breakpoints") {
@if length($map) > 0 {
$values: map-values($map);
$first-value: nth($values, 1);
@if $first-value != 0 {
@warn "First breakpoint in #{$map-name} must start at 0, but starts at #{$first-value}.";
}
}
}
// Colors
@function to-rgb($value) {
@return red($value), green($value), blue($value);
}
// stylelint-disable scss/dollar-variable-pattern
@function rgba-css-var($identifier, $target) {
@if $identifier == "body" and $target == "bg" {
@return rgba(var(--#{$prefix}#{$identifier}-bg-rgb), var(--#{$prefix}#{$target}-opacity));
} @if $identifier == "body" and $target == "text" {
@return rgba(var(--#{$prefix}#{$identifier}-color-rgb), var(--#{$prefix}#{$target}-opacity));
} @else {
@return rgba(var(--#{$prefix}#{$identifier}-rgb), var(--#{$prefix}#{$target}-opacity));
}
}
@function map-loop($map, $func, $args...) {
$_map: ();
@each $key, $value in $map {
// allow to pass the $key and $value of the map as an function argument
$_args: ();
@each $arg in $args {
$_args: append($_args, if($arg == "$key", $key, if($arg == "$value", $value, $arg)));
}
$_map: map-merge($_map, ($key: call(get-function($func), $_args...)));
}
@return $_map;
}
// stylelint-enable scss/dollar-variable-pattern
@function varify($list) {
$result: null;
@each $entry in $list {
$result: append($result, var(--#{$prefix}#{$entry}), space);
}
@return $result;
}
// Internal Bootstrap function to turn maps into its negative variant.
// It prefixes the keys with `n` and makes the value negative.
@function negativify-map($map) {
$result: ();
@each $key, $value in $map {
@if $key != 0 {
$result: map-merge($result, ("n" + $key: (-$value)));
}
}
@return $result;
}
// Get multiple keys from a sass map
@function map-get-multiple($map, $values) {
$result: ();
@each $key, $value in $map {
@if (index($values, $key) != null) {
$result: map-merge($result, ($key: $value));
}
}
@return $result;
}
// Merge multiple maps
@function map-merge-multiple($maps...) {
$merged-maps: ();
@each $map in $maps {
$merged-maps: map-merge($merged-maps, $map);
}
@return $merged-maps;
}
// Replace `$search` with `$replace` in `$string`
// Used on our SVG icon backgrounds for custom forms.
//
// @author Kitty Giraudel
// @param {String} $string - Initial string
// @param {String} $search - Substring to replace
// @param {String} $replace ('') - New value
// @return {String} - Updated string
@function str-replace($string, $search, $replace: "") {
$index: str-index($string, $search);
@if $index {
@return str-slice($string, 1, $index - 1) + $replace + str-replace(str-slice($string, $index + str-length($search)), $search, $replace);
}
@return $string;
}
// See https://codepen.io/kevinweber/pen/dXWoRw
//
// Requires the use of quotes around data URIs.
@function escape-svg($string) {
@if str-index($string, "data:image/svg+xml") {
@each $char, $encoded in $escaped-characters {
// Do not escape the url brackets
@if str-index($string, "url(") == 1 {
$string: url("#{str-replace(str-slice($string, 6, -3), $char, $encoded)}");
} @else {
$string: str-replace($string, $char, $encoded);
}
}
}
@return $string;
}
// Color contrast
// See https://github.com/twbs/bootstrap/pull/30168
// A list of pre-calculated numbers of pow(divide((divide($value, 255) + .055), 1.055), 2.4). (from 0 to 255)
// stylelint-disable-next-line scss/dollar-variable-default, scss/dollar-variable-pattern
$_luminance-list: .0008 .001 .0011 .0013 .0015 .0017 .002 .0022 .0025 .0027 .003 .0033 .0037 .004 .0044 .0048 .0052 .0056 .006 .0065 .007 .0075 .008 .0086 .0091 .0097 .0103 .011 .0116 .0123 .013 .0137 .0144 .0152 .016 .0168 .0176 .0185 .0194 .0203 .0212 .0222 .0232 .0242 .0252 .0262 .0273 .0284 .0296 .0307 .0319 .0331 .0343 .0356 .0369 .0382 .0395 .0409 .0423 .0437 .0452 .0467 .0482 .0497 .0513 .0529 .0545 .0561 .0578 .0595 .0612 .063 .0648 .0666 .0685 .0704 .0723 .0742 .0762 .0782 .0802 .0823 .0844 .0865 .0887 .0908 .0931 .0953 .0976 .0999 .1022 .1046 .107 .1095 .1119 .1144 .117 .1195 .1221 .1248 .1274 .1301 .1329 .1356 .1384 .1413 .1441 .147 .15 .1529 .1559 .159 .162 .1651 .1683 .1714 .1746 .1779 .1812 .1845 .1878 .1912 .1946 .1981 .2016 .2051 .2086 .2122 .2159 .2195 .2232 .227 .2307 .2346 .2384 .2423 .2462 .2502 .2542 .2582 .2623 .2664 .2705 .2747 .2789 .2831 .2874 .2918 .2961 .3005 .305 .3095 .314 .3185 .3231 .3278 .3325 .3372 .3419 .3467 .3515 .3564 .3613 .3663 .3712 .3763 .3813 .3864 .3916 .3968 .402 .4072 .4125 .4179 .4233 .4287 .4342 .4397 .4452 .4508 .4564 .4621 .4678 .4735 .4793 .4851 .491 .4969 .5029 .5089 .5149 .521 .5271 .5333 .5395 .5457 .552 .5583 .5647 .5711 .5776 .5841 .5906 .5972 .6038 .6105 .6172 .624 .6308 .6376 .6445 .6514 .6584 .6654 .6724 .6795 .6867 .6939 .7011 .7084 .7157 .7231 .7305 .7379 .7454 .7529 .7605 .7682 .7758 .7835 .7913 .7991 .807 .8148 .8228 .8308 .8388 .8469 .855 .8632 .8714 .8796 .8879 .8963 .9047 .9131 .9216 .9301 .9387 .9473 .956 .9647 .9734 .9823 .9911 1;
@function color-contrast($background, $color-contrast-dark: $color-contrast-dark, $color-contrast-light: $color-contrast-light, $min-contrast-ratio: $min-contrast-ratio) {
$foregrounds: $color-contrast-light, $color-contrast-dark, $white, $black;
$max-ratio: 0;
$max-ratio-color: null;
@each $color in $foregrounds {
$contrast-ratio: contrast-ratio($background, $color);
@if $contrast-ratio > $min-contrast-ratio {
@return $color;
} @else if $contrast-ratio > $max-ratio {
$max-ratio: $contrast-ratio;
$max-ratio-color: $color;
}
}
@warn "Found no color leading to #{$min-contrast-ratio}:1 contrast ratio against #{$background}...";
@return $max-ratio-color;
}
@function contrast-ratio($background, $foreground: $color-contrast-light) {
$l1: luminance($background);
$l2: luminance(opaque($background, $foreground));
@return if($l1 > $l2, divide($l1 + .05, $l2 + .05), divide($l2 + .05, $l1 + .05));
}
// Return WCAG2.1 relative luminance
// See https://www.w3.org/TR/WCAG/#dfn-relative-luminance
// See https://www.w3.org/TR/WCAG/#dfn-contrast-ratio
@function luminance($color) {
$rgb: (
"r": red($color),
"g": green($color),
"b": blue($color)
);
@each $name, $value in $rgb {
$value: if(divide($value, 255) < .04045, divide(divide($value, 255), 12.92), nth($_luminance-list, $value + 1));
$rgb: map-merge($rgb, ($name: $value));
}
@return (map-get($rgb, "r") * .2126) + (map-get($rgb, "g") * .7152) + (map-get($rgb, "b") * .0722);
}
// Return opaque color
// opaque(#fff, rgba(0, 0, 0, .5)) => #808080
@function opaque($background, $foreground) {
@return mix(rgba($foreground, 1), $background, opacity($foreground) * 100%);
}
// scss-docs-start color-functions
// Tint a color: mix a color with white
@function tint-color($color, $weight) {
@return mix(white, $color, $weight);
}
// Shade a color: mix a color with black
@function shade-color($color, $weight) {
@return mix(black, $color, $weight);
}
// Shade the color if the weight is positive, else tint it
@function shift-color($color, $weight) {
@return if($weight > 0, shade-color($color, $weight), tint-color($color, -$weight));
}
// scss-docs-end color-functions
// Return valid calc
@function add($value1, $value2, $return-calc: true) {
@if $value1 == null {
@return $value2;
}
@if $value2 == null {
@return $value1;
}
@if type-of($value1) == number and type-of($value2) == number and comparable($value1, $value2) {
@return $value1 + $value2;
}
@return if($return-calc == true, calc(#{$value1} + #{$value2}), $value1 + unquote(" + ") + $value2);
}
@function subtract($value1, $value2, $return-calc: true) {
@if $value1 == null and $value2 == null {
@return null;
}
@if $value1 == null {
@return -$value2;
}
@if $value2 == null {
@return $value1;
}
@if type-of($value1) == number and type-of($value2) == number and comparable($value1, $value2) {
@return $value1 - $value2;
}
@if type-of($value2) != number {
$value2: unquote("(") + $value2 + unquote(")");
}
@return if($return-calc == true, calc(#{$value1} - #{$value2}), $value1 + unquote(" - ") + $value2);
}
@function divide($dividend, $divisor, $precision: 10) {
$sign: if($dividend > 0 and $divisor > 0 or $dividend < 0 and $divisor < 0, 1, -1);
$dividend: abs($dividend);
$divisor: abs($divisor);
@if $dividend == 0 {
@return 0;
}
@if $divisor == 0 {
@error "Cannot divide by 0";
}
$remainder: $dividend;
$result: 0;
$factor: 10;
@while ($remainder > 0 and $precision >= 0) {
$quotient: 0;
@while ($remainder >= $divisor) {
$remainder: $remainder - $divisor;
$quotient: $quotient + 1;
}
$result: $result * 10 + $quotient;
$factor: $factor * .1;
$remainder: $remainder * 10;
$precision: $precision - 1;
@if ($precision < 0 and $remainder >= $divisor * 5) {
$result: $result + 1;
}
}
$result: $result * $factor * $sign;
$dividend-unit: unit($dividend);
$divisor-unit: unit($divisor);
$unit-map: (
"px": 1px,
"rem": 1rem,
"em": 1em,
"%": 1%
);
@if ($dividend-unit != $divisor-unit and map-has-key($unit-map, $dividend-unit)) {
$result: $result * map-get($unit-map, $dividend-unit);
}
@return $result;
}

View File

@ -0,0 +1,24 @@
/*
div.gallery
figure
img
figcaption
*/
div.gallery {
@extend .row;
@extend .row-cols-2;
.gallery-item {
padding: 1px;
}
figure {
margin: 1rem;
@extend .card;
img {
@extend .card-img-top;
}
figcaption {
@extend .card-body;
}
}
}

View File

@ -0,0 +1,39 @@
// Row
//
// Rows contain your columns.
:root {
@each $name, $value in $grid-breakpoints {
--#{$prefix}breakpoint-#{$name}: #{$value};
}
}
@if $enable-grid-classes {
.row {
@include make-row();
> * {
@include make-col-ready();
}
}
}
@if $enable-cssgrid {
.grid {
display: grid;
grid-template-rows: repeat(var(--#{$prefix}rows, 1), 1fr);
grid-template-columns: repeat(var(--#{$prefix}columns, #{$grid-columns}), 1fr);
gap: var(--#{$prefix}gap, #{$grid-gutter-width});
@include make-cssgrid();
}
}
// Columns
//
// Common styles for small and large grid columns
@if $enable-grid-classes {
@include make-grid-columns();
}

View File

@ -0,0 +1,12 @@
@import "helpers/clearfix";
@import "helpers/color-bg";
@import "helpers/colored-links";
@import "helpers/focus-ring";
@import "helpers/icon-link";
@import "helpers/ratio";
@import "helpers/position";
@import "helpers/stacks";
@import "helpers/visually-hidden";
@import "helpers/stretched-link";
@import "helpers/text-truncation";
@import "helpers/vr";

View File

@ -0,0 +1,42 @@
// Responsive images (ensure images don't scale beyond their parents)
//
// This is purposefully opt-in via an explicit class rather than being the default for all `<img>`s.
// We previously tried the "images are responsive by default" approach in Bootstrap v2,
// and abandoned it in Bootstrap v3 because it breaks lots of third-party widgets (including Google Maps)
// which weren't expecting the images within themselves to be involuntarily resized.
// See also https://github.com/twbs/bootstrap/issues/18178
.img-fluid {
@include img-fluid();
}
// Image thumbnails
.img-thumbnail {
padding: $thumbnail-padding;
background-color: $thumbnail-bg;
border: $thumbnail-border-width solid $thumbnail-border-color;
@include border-radius($thumbnail-border-radius);
@include box-shadow($thumbnail-box-shadow);
// Keep them at most 100% wide
@include img-fluid();
}
//
// Figures
//
.figure {
// Ensures the caption's text aligns with the image.
display: inline-block;
}
.figure-img {
margin-bottom: $spacer * .5;
line-height: 1;
}
.figure-caption {
@include font-size($figure-caption-font-size);
color: $figure-caption-color;
}

View File

@ -0,0 +1,197 @@
// Base class
//
// Easily usable on <ul>, <ol>, or <div>.
.list-group {
// scss-docs-start list-group-css-vars
--#{$prefix}list-group-color: #{$list-group-color};
--#{$prefix}list-group-bg: #{$list-group-bg};
--#{$prefix}list-group-border-color: #{$list-group-border-color};
--#{$prefix}list-group-border-width: #{$list-group-border-width};
--#{$prefix}list-group-border-radius: #{$list-group-border-radius};
--#{$prefix}list-group-item-padding-x: #{$list-group-item-padding-x};
--#{$prefix}list-group-item-padding-y: #{$list-group-item-padding-y};
--#{$prefix}list-group-action-color: #{$list-group-action-color};
--#{$prefix}list-group-action-hover-color: #{$list-group-action-hover-color};
--#{$prefix}list-group-action-hover-bg: #{$list-group-hover-bg};
--#{$prefix}list-group-action-active-color: #{$list-group-action-active-color};
--#{$prefix}list-group-action-active-bg: #{$list-group-action-active-bg};
--#{$prefix}list-group-disabled-color: #{$list-group-disabled-color};
--#{$prefix}list-group-disabled-bg: #{$list-group-disabled-bg};
--#{$prefix}list-group-active-color: #{$list-group-active-color};
--#{$prefix}list-group-active-bg: #{$list-group-active-bg};
--#{$prefix}list-group-active-border-color: #{$list-group-active-border-color};
// scss-docs-end list-group-css-vars
display: flex;
flex-direction: column;
// No need to set list-style: none; since .list-group-item is block level
padding-left: 0; // reset padding because ul and ol
margin-bottom: 0;
@include border-radius(var(--#{$prefix}list-group-border-radius));
}
.list-group-numbered {
list-style-type: none;
counter-reset: section;
> .list-group-item::before {
// Increments only this instance of the section counter
content: counters(section, ".") ". ";
counter-increment: section;
}
}
// Interactive list items
//
// Use anchor or button elements instead of `li`s or `div`s to create interactive
// list items. Includes an extra `.active` modifier class for selected items.
.list-group-item-action {
width: 100%; // For `<button>`s (anchors become 100% by default though)
color: var(--#{$prefix}list-group-action-color);
text-align: inherit; // For `<button>`s (anchors inherit)
// Hover state
&:hover,
&:focus {
z-index: 1; // Place hover/focus items above their siblings for proper border styling
color: var(--#{$prefix}list-group-action-hover-color);
text-decoration: none;
background-color: var(--#{$prefix}list-group-action-hover-bg);
}
&:active {
color: var(--#{$prefix}list-group-action-active-color);
background-color: var(--#{$prefix}list-group-action-active-bg);
}
}
// Individual list items
//
// Use on `li`s or `div`s within the `.list-group` parent.
.list-group-item {
position: relative;
display: block;
padding: var(--#{$prefix}list-group-item-padding-y) var(--#{$prefix}list-group-item-padding-x);
color: var(--#{$prefix}list-group-color);
text-decoration: if($link-decoration == none, null, none);
background-color: var(--#{$prefix}list-group-bg);
border: var(--#{$prefix}list-group-border-width) solid var(--#{$prefix}list-group-border-color);
&:first-child {
@include border-top-radius(inherit);
}
&:last-child {
@include border-bottom-radius(inherit);
}
&.disabled,
&:disabled {
color: var(--#{$prefix}list-group-disabled-color);
pointer-events: none;
background-color: var(--#{$prefix}list-group-disabled-bg);
}
// Include both here for `<a>`s and `<button>`s
&.active {
z-index: 2; // Place active items above their siblings for proper border styling
color: var(--#{$prefix}list-group-active-color);
background-color: var(--#{$prefix}list-group-active-bg);
border-color: var(--#{$prefix}list-group-active-border-color);
}
// stylelint-disable-next-line scss/selector-no-redundant-nesting-selector
& + .list-group-item {
border-top-width: 0;
&.active {
margin-top: calc(-1 * var(--#{$prefix}list-group-border-width)); // stylelint-disable-line function-disallowed-list
border-top-width: var(--#{$prefix}list-group-border-width);
}
}
}
// Horizontal
//
// Change the layout of list group items from vertical (default) to horizontal.
@each $breakpoint in map-keys($grid-breakpoints) {
@include media-breakpoint-up($breakpoint) {
$infix: breakpoint-infix($breakpoint, $grid-breakpoints);
.list-group-horizontal#{$infix} {
flex-direction: row;
> .list-group-item {
&:first-child:not(:last-child) {
@include border-bottom-start-radius(var(--#{$prefix}list-group-border-radius));
@include border-top-end-radius(0);
}
&:last-child:not(:first-child) {
@include border-top-end-radius(var(--#{$prefix}list-group-border-radius));
@include border-bottom-start-radius(0);
}
&.active {
margin-top: 0;
}
+ .list-group-item {
border-top-width: var(--#{$prefix}list-group-border-width);
border-left-width: 0;
&.active {
margin-left: calc(-1 * var(--#{$prefix}list-group-border-width)); // stylelint-disable-line function-disallowed-list
border-left-width: var(--#{$prefix}list-group-border-width);
}
}
}
}
}
}
// Flush list items
//
// Remove borders and border-radius to keep list group items edge-to-edge. Most
// useful within other components (e.g., cards).
.list-group-flush {
@include border-radius(0);
> .list-group-item {
border-width: 0 0 var(--#{$prefix}list-group-border-width);
&:last-child {
border-bottom-width: 0;
}
}
}
// scss-docs-start list-group-modifiers
// List group contextual variants
//
// Add modifier classes to change text and background color on individual items.
// Organizationally, this must come after the `:hover` states.
@each $state in map-keys($theme-colors) {
.list-group-item-#{$state} {
--#{$prefix}list-group-color: var(--#{$prefix}#{$state}-text-emphasis);
--#{$prefix}list-group-bg: var(--#{$prefix}#{$state}-bg-subtle);
--#{$prefix}list-group-border-color: var(--#{$prefix}#{$state}-border-subtle);
--#{$prefix}list-group-action-hover-color: var(--#{$prefix}emphasis-color);
--#{$prefix}list-group-action-hover-bg: var(--#{$prefix}#{$state}-border-subtle);
--#{$prefix}list-group-action-active-color: var(--#{$prefix}emphasis-color);
--#{$prefix}list-group-action-active-bg: var(--#{$prefix}#{$state}-border-subtle);
--#{$prefix}list-group-active-color: var(--#{$prefix}#{$state}-bg-subtle);
--#{$prefix}list-group-active-bg: var(--#{$prefix}#{$state}-text-emphasis);
--#{$prefix}list-group-active-border-color: var(--#{$prefix}#{$state}-text-emphasis);
}
}
// scss-docs-end list-group-modifiers

View File

@ -0,0 +1,174 @@
// Re-assigned maps
//
// Placed here so that others can override the default Sass maps and see automatic updates to utilities and more.
// scss-docs-start theme-colors-rgb
$theme-colors-rgb: map-loop($theme-colors, to-rgb, "$value") !default;
// scss-docs-end theme-colors-rgb
// scss-docs-start theme-text-map
$theme-colors-text: (
"primary": $primary-text-emphasis,
"secondary": $secondary-text-emphasis,
"success": $success-text-emphasis,
"info": $info-text-emphasis,
"warning": $warning-text-emphasis,
"danger": $danger-text-emphasis,
"light": $light-text-emphasis,
"dark": $dark-text-emphasis,
) !default;
// scss-docs-end theme-text-map
// scss-docs-start theme-bg-subtle-map
$theme-colors-bg-subtle: (
"primary": $primary-bg-subtle,
"secondary": $secondary-bg-subtle,
"success": $success-bg-subtle,
"info": $info-bg-subtle,
"warning": $warning-bg-subtle,
"danger": $danger-bg-subtle,
"light": $light-bg-subtle,
"dark": $dark-bg-subtle,
) !default;
// scss-docs-end theme-bg-subtle-map
// scss-docs-start theme-border-subtle-map
$theme-colors-border-subtle: (
"primary": $primary-border-subtle,
"secondary": $secondary-border-subtle,
"success": $success-border-subtle,
"info": $info-border-subtle,
"warning": $warning-border-subtle,
"danger": $danger-border-subtle,
"light": $light-border-subtle,
"dark": $dark-border-subtle,
) !default;
// scss-docs-end theme-border-subtle-map
$theme-colors-text-dark: null !default;
$theme-colors-bg-subtle-dark: null !default;
$theme-colors-border-subtle-dark: null !default;
@if $enable-dark-mode {
// scss-docs-start theme-text-dark-map
$theme-colors-text-dark: (
"primary": $primary-text-emphasis-dark,
"secondary": $secondary-text-emphasis-dark,
"success": $success-text-emphasis-dark,
"info": $info-text-emphasis-dark,
"warning": $warning-text-emphasis-dark,
"danger": $danger-text-emphasis-dark,
"light": $light-text-emphasis-dark,
"dark": $dark-text-emphasis-dark,
) !default;
// scss-docs-end theme-text-dark-map
// scss-docs-start theme-bg-subtle-dark-map
$theme-colors-bg-subtle-dark: (
"primary": $primary-bg-subtle-dark,
"secondary": $secondary-bg-subtle-dark,
"success": $success-bg-subtle-dark,
"info": $info-bg-subtle-dark,
"warning": $warning-bg-subtle-dark,
"danger": $danger-bg-subtle-dark,
"light": $light-bg-subtle-dark,
"dark": $dark-bg-subtle-dark,
) !default;
// scss-docs-end theme-bg-subtle-dark-map
// scss-docs-start theme-border-subtle-dark-map
$theme-colors-border-subtle-dark: (
"primary": $primary-border-subtle-dark,
"secondary": $secondary-border-subtle-dark,
"success": $success-border-subtle-dark,
"info": $info-border-subtle-dark,
"warning": $warning-border-subtle-dark,
"danger": $danger-border-subtle-dark,
"light": $light-border-subtle-dark,
"dark": $dark-border-subtle-dark,
) !default;
// scss-docs-end theme-border-subtle-dark-map
}
// Utilities maps
//
// Extends the default `$theme-colors` maps to help create our utilities.
// Come v6, we'll de-dupe these variables. Until then, for backward compatibility, we keep them to reassign.
// scss-docs-start utilities-colors
$utilities-colors: $theme-colors-rgb !default;
// scss-docs-end utilities-colors
// scss-docs-start utilities-text-colors
$utilities-text: map-merge(
$utilities-colors,
(
"black": to-rgb($black),
"white": to-rgb($white),
"body": to-rgb($body-color)
)
) !default;
$utilities-text-colors: map-loop($utilities-text, rgba-css-var, "$key", "text") !default;
$utilities-text-emphasis-colors: (
"primary-emphasis": var(--#{$prefix}primary-text-emphasis),
"secondary-emphasis": var(--#{$prefix}secondary-text-emphasis),
"success-emphasis": var(--#{$prefix}success-text-emphasis),
"info-emphasis": var(--#{$prefix}info-text-emphasis),
"warning-emphasis": var(--#{$prefix}warning-text-emphasis),
"danger-emphasis": var(--#{$prefix}danger-text-emphasis),
"light-emphasis": var(--#{$prefix}light-text-emphasis),
"dark-emphasis": var(--#{$prefix}dark-text-emphasis)
) !default;
// scss-docs-end utilities-text-colors
// scss-docs-start utilities-bg-colors
$utilities-bg: map-merge(
$utilities-colors,
(
"black": to-rgb($black),
"white": to-rgb($white),
"body": to-rgb($body-bg)
)
) !default;
$utilities-bg-colors: map-loop($utilities-bg, rgba-css-var, "$key", "bg") !default;
$utilities-bg-subtle: (
"primary-subtle": var(--#{$prefix}primary-bg-subtle),
"secondary-subtle": var(--#{$prefix}secondary-bg-subtle),
"success-subtle": var(--#{$prefix}success-bg-subtle),
"info-subtle": var(--#{$prefix}info-bg-subtle),
"warning-subtle": var(--#{$prefix}warning-bg-subtle),
"danger-subtle": var(--#{$prefix}danger-bg-subtle),
"light-subtle": var(--#{$prefix}light-bg-subtle),
"dark-subtle": var(--#{$prefix}dark-bg-subtle)
) !default;
// scss-docs-end utilities-bg-colors
// scss-docs-start utilities-border-colors
$utilities-border: map-merge(
$utilities-colors,
(
"black": to-rgb($black),
"white": to-rgb($white)
)
) !default;
$utilities-border-colors: map-loop($utilities-border, rgba-css-var, "$key", "border") !default;
$utilities-border-subtle: (
"primary-subtle": var(--#{$prefix}primary-border-subtle),
"secondary-subtle": var(--#{$prefix}secondary-border-subtle),
"success-subtle": var(--#{$prefix}success-border-subtle),
"info-subtle": var(--#{$prefix}info-border-subtle),
"warning-subtle": var(--#{$prefix}warning-border-subtle),
"danger-subtle": var(--#{$prefix}danger-border-subtle),
"light-subtle": var(--#{$prefix}light-border-subtle),
"dark-subtle": var(--#{$prefix}dark-border-subtle)
) !default;
// scss-docs-end utilities-border-colors
$utilities-links-underline: map-loop($utilities-colors, rgba-css-var, "$key", "link-underline") !default;
$negative-spacers: if($enable-negative-margins, negativify-map($spacers), null) !default;
$gutters: $spacers !default;

View File

@ -0,0 +1,42 @@
// Toggles
//
// Used in conjunction with global variables to enable certain theme features.
// Vendor
@import "vendor/rfs";
// Deprecate
@import "mixins/deprecate";
// Helpers
@import "mixins/breakpoints";
@import "mixins/color-mode";
@import "mixins/color-scheme";
@import "mixins/image";
@import "mixins/resize";
@import "mixins/visually-hidden";
@import "mixins/reset-text";
@import "mixins/text-truncate";
// Utilities
@import "mixins/utilities";
// Components
@import "mixins/backdrop";
@import "mixins/buttons";
@import "mixins/caret";
@import "mixins/pagination";
@import "mixins/lists";
@import "mixins/forms";
@import "mixins/table-variants";
// Skins
@import "mixins/border-radius";
@import "mixins/box-shadow";
@import "mixins/gradients";
@import "mixins/transition";
// Layout
@import "mixins/clearfix";
@import "mixins/container";
@import "mixins/grid";

View File

@ -0,0 +1,237 @@
// stylelint-disable function-disallowed-list
// .modal-open - body class for killing the scroll
// .modal - container to scroll within
// .modal-dialog - positioning shell for the actual modal
// .modal-content - actual modal w/ bg and corners and stuff
// Container that the modal scrolls within
.modal {
// scss-docs-start modal-css-vars
--#{$prefix}modal-zindex: #{$zindex-modal};
--#{$prefix}modal-width: #{$modal-md};
--#{$prefix}modal-padding: #{$modal-inner-padding};
--#{$prefix}modal-margin: #{$modal-dialog-margin};
--#{$prefix}modal-color: #{$modal-content-color};
--#{$prefix}modal-bg: #{$modal-content-bg};
--#{$prefix}modal-border-color: #{$modal-content-border-color};
--#{$prefix}modal-border-width: #{$modal-content-border-width};
--#{$prefix}modal-border-radius: #{$modal-content-border-radius};
--#{$prefix}modal-box-shadow: #{$modal-content-box-shadow-xs};
--#{$prefix}modal-inner-border-radius: #{$modal-content-inner-border-radius};
--#{$prefix}modal-header-padding-x: #{$modal-header-padding-x};
--#{$prefix}modal-header-padding-y: #{$modal-header-padding-y};
--#{$prefix}modal-header-padding: #{$modal-header-padding}; // Todo in v6: Split this padding into x and y
--#{$prefix}modal-header-border-color: #{$modal-header-border-color};
--#{$prefix}modal-header-border-width: #{$modal-header-border-width};
--#{$prefix}modal-title-line-height: #{$modal-title-line-height};
--#{$prefix}modal-footer-gap: #{$modal-footer-margin-between};
--#{$prefix}modal-footer-bg: #{$modal-footer-bg};
--#{$prefix}modal-footer-border-color: #{$modal-footer-border-color};
--#{$prefix}modal-footer-border-width: #{$modal-footer-border-width};
// scss-docs-end modal-css-vars
position: fixed;
top: 0;
left: 0;
z-index: var(--#{$prefix}modal-zindex);
display: none;
width: 100%;
height: 100%;
overflow-x: hidden;
overflow-y: auto;
// Prevent Chrome on Windows from adding a focus outline. For details, see
// https://github.com/twbs/bootstrap/pull/10951.
outline: 0;
// We deliberately don't use `-webkit-overflow-scrolling: touch;` due to a
// gnarly iOS Safari bug: https://bugs.webkit.org/show_bug.cgi?id=158342
// See also https://github.com/twbs/bootstrap/issues/17695
}
// Shell div to position the modal with bottom padding
.modal-dialog {
position: relative;
width: auto;
margin: var(--#{$prefix}modal-margin);
// allow clicks to pass through for custom click handling to close modal
pointer-events: none;
// When fading in the modal, animate it to slide down
.modal.fade & {
@include transition($modal-transition);
transform: $modal-fade-transform;
}
.modal.show & {
transform: $modal-show-transform;
}
// When trying to close, animate focus to scale
.modal.modal-static & {
transform: $modal-scale-transform;
}
}
.modal-dialog-scrollable {
height: calc(100% - var(--#{$prefix}modal-margin) * 2);
.modal-content {
max-height: 100%;
overflow: hidden;
}
.modal-body {
overflow-y: auto;
}
}
.modal-dialog-centered {
display: flex;
align-items: center;
min-height: calc(100% - var(--#{$prefix}modal-margin) * 2);
}
// Actual modal
.modal-content {
position: relative;
display: flex;
flex-direction: column;
width: 100%; // Ensure `.modal-content` extends the full width of the parent `.modal-dialog`
// counteract the pointer-events: none; in the .modal-dialog
color: var(--#{$prefix}modal-color);
pointer-events: auto;
background-color: var(--#{$prefix}modal-bg);
background-clip: padding-box;
border: var(--#{$prefix}modal-border-width) solid var(--#{$prefix}modal-border-color);
@include border-radius(var(--#{$prefix}modal-border-radius));
@include box-shadow(var(--#{$prefix}modal-box-shadow));
// Remove focus outline from opened modal
outline: 0;
}
// Modal background
.modal-backdrop {
// scss-docs-start modal-backdrop-css-vars
--#{$prefix}backdrop-zindex: #{$zindex-modal-backdrop};
--#{$prefix}backdrop-bg: #{$modal-backdrop-bg};
--#{$prefix}backdrop-opacity: #{$modal-backdrop-opacity};
// scss-docs-end modal-backdrop-css-vars
@include overlay-backdrop(var(--#{$prefix}backdrop-zindex), var(--#{$prefix}backdrop-bg), var(--#{$prefix}backdrop-opacity));
}
// Modal header
// Top section of the modal w/ title and dismiss
.modal-header {
display: flex;
flex-shrink: 0;
align-items: center;
justify-content: space-between; // Put modal header elements (title and dismiss) on opposite ends
padding: var(--#{$prefix}modal-header-padding);
border-bottom: var(--#{$prefix}modal-header-border-width) solid var(--#{$prefix}modal-header-border-color);
@include border-top-radius(var(--#{$prefix}modal-inner-border-radius));
.btn-close {
padding: calc(var(--#{$prefix}modal-header-padding-y) * .5) calc(var(--#{$prefix}modal-header-padding-x) * .5);
margin: calc(-.5 * var(--#{$prefix}modal-header-padding-y)) calc(-.5 * var(--#{$prefix}modal-header-padding-x)) calc(-.5 * var(--#{$prefix}modal-header-padding-y)) auto;
}
}
// Title text within header
.modal-title {
margin-bottom: 0;
line-height: var(--#{$prefix}modal-title-line-height);
}
// Modal body
// Where all modal content resides (sibling of .modal-header and .modal-footer)
.modal-body {
position: relative;
// Enable `flex-grow: 1` so that the body take up as much space as possible
// when there should be a fixed height on `.modal-dialog`.
flex: 1 1 auto;
padding: var(--#{$prefix}modal-padding);
}
// Footer (for actions)
.modal-footer {
display: flex;
flex-shrink: 0;
flex-wrap: wrap;
align-items: center; // vertically center
justify-content: flex-end; // Right align buttons with flex property because text-align doesn't work on flex items
padding: calc(var(--#{$prefix}modal-padding) - var(--#{$prefix}modal-footer-gap) * .5);
background-color: var(--#{$prefix}modal-footer-bg);
border-top: var(--#{$prefix}modal-footer-border-width) solid var(--#{$prefix}modal-footer-border-color);
@include border-bottom-radius(var(--#{$prefix}modal-inner-border-radius));
// Place margin between footer elements
// This solution is far from ideal because of the universal selector usage,
// but is needed to fix https://github.com/twbs/bootstrap/issues/24800
> * {
margin: calc(var(--#{$prefix}modal-footer-gap) * .5); // Todo in v6: replace with gap on parent class
}
}
// Scale up the modal
@include media-breakpoint-up(sm) {
.modal {
--#{$prefix}modal-margin: #{$modal-dialog-margin-y-sm-up};
--#{$prefix}modal-box-shadow: #{$modal-content-box-shadow-sm-up};
}
// Automatically set modal's width for larger viewports
.modal-dialog {
max-width: var(--#{$prefix}modal-width);
margin-right: auto;
margin-left: auto;
}
.modal-sm {
--#{$prefix}modal-width: #{$modal-sm};
}
}
@include media-breakpoint-up(lg) {
.modal-lg,
.modal-xl {
--#{$prefix}modal-width: #{$modal-lg};
}
}
@include media-breakpoint-up(xl) {
.modal-xl {
--#{$prefix}modal-width: #{$modal-xl};
}
}
// scss-docs-start modal-fullscreen-loop
@each $breakpoint in map-keys($grid-breakpoints) {
$infix: breakpoint-infix($breakpoint, $grid-breakpoints);
$postfix: if($infix != "", $infix + "-down", "");
@include media-breakpoint-down($breakpoint) {
.modal-fullscreen#{$postfix} {
width: 100vw;
max-width: none;
height: 100%;
margin: 0;
.modal-content {
height: 100%;
border: 0;
@include border-radius(0);
}
.modal-header,
.modal-footer {
@include border-radius(0);
}
.modal-body {
overflow-y: auto;
}
}
}
}
// scss-docs-end modal-fullscreen-loop

View File

@ -0,0 +1,197 @@
// Base class
//
// Kickstart any navigation component with a set of style resets. Works with
// `<nav>`s, `<ul>`s or `<ol>`s.
.nav {
// scss-docs-start nav-css-vars
--#{$prefix}nav-link-padding-x: #{$nav-link-padding-x};
--#{$prefix}nav-link-padding-y: #{$nav-link-padding-y};
@include rfs($nav-link-font-size, --#{$prefix}nav-link-font-size);
--#{$prefix}nav-link-font-weight: #{$nav-link-font-weight};
--#{$prefix}nav-link-color: #{$nav-link-color};
--#{$prefix}nav-link-hover-color: #{$nav-link-hover-color};
--#{$prefix}nav-link-disabled-color: #{$nav-link-disabled-color};
// scss-docs-end nav-css-vars
display: flex;
flex-wrap: wrap;
padding-left: 0;
margin-bottom: 0;
list-style: none;
}
.nav-link {
display: block;
padding: var(--#{$prefix}nav-link-padding-y) var(--#{$prefix}nav-link-padding-x);
@include font-size(var(--#{$prefix}nav-link-font-size));
font-weight: var(--#{$prefix}nav-link-font-weight);
color: var(--#{$prefix}nav-link-color);
text-decoration: if($link-decoration == none, null, none);
background: none;
border: 0;
@include transition($nav-link-transition);
&:hover,
&:focus {
color: var(--#{$prefix}nav-link-hover-color);
text-decoration: if($link-hover-decoration == underline, none, null);
}
&:focus-visible {
outline: 0;
box-shadow: $nav-link-focus-box-shadow;
}
// Disabled state lightens text
&.disabled,
&:disabled {
color: var(--#{$prefix}nav-link-disabled-color);
pointer-events: none;
cursor: default;
}
}
//
// Tabs
//
.nav-tabs {
// scss-docs-start nav-tabs-css-vars
--#{$prefix}nav-tabs-border-width: #{$nav-tabs-border-width};
--#{$prefix}nav-tabs-border-color: #{$nav-tabs-border-color};
--#{$prefix}nav-tabs-border-radius: #{$nav-tabs-border-radius};
--#{$prefix}nav-tabs-link-hover-border-color: #{$nav-tabs-link-hover-border-color};
--#{$prefix}nav-tabs-link-active-color: #{$nav-tabs-link-active-color};
--#{$prefix}nav-tabs-link-active-bg: #{$nav-tabs-link-active-bg};
--#{$prefix}nav-tabs-link-active-border-color: #{$nav-tabs-link-active-border-color};
// scss-docs-end nav-tabs-css-vars
border-bottom: var(--#{$prefix}nav-tabs-border-width) solid var(--#{$prefix}nav-tabs-border-color);
.nav-link {
margin-bottom: calc(-1 * var(--#{$prefix}nav-tabs-border-width)); // stylelint-disable-line function-disallowed-list
border: var(--#{$prefix}nav-tabs-border-width) solid transparent;
@include border-top-radius(var(--#{$prefix}nav-tabs-border-radius));
&:hover,
&:focus {
// Prevents active .nav-link tab overlapping focus outline of previous/next .nav-link
isolation: isolate;
border-color: var(--#{$prefix}nav-tabs-link-hover-border-color);
}
}
.nav-link.active,
.nav-item.show .nav-link {
color: var(--#{$prefix}nav-tabs-link-active-color);
background-color: var(--#{$prefix}nav-tabs-link-active-bg);
border-color: var(--#{$prefix}nav-tabs-link-active-border-color);
}
.dropdown-menu {
// Make dropdown border overlap tab border
margin-top: calc(-1 * var(--#{$prefix}nav-tabs-border-width)); // stylelint-disable-line function-disallowed-list
// Remove the top rounded corners here since there is a hard edge above the menu
@include border-top-radius(0);
}
}
//
// Pills
//
.nav-pills {
// scss-docs-start nav-pills-css-vars
--#{$prefix}nav-pills-border-radius: #{$nav-pills-border-radius};
--#{$prefix}nav-pills-link-active-color: #{$nav-pills-link-active-color};
--#{$prefix}nav-pills-link-active-bg: #{$nav-pills-link-active-bg};
// scss-docs-end nav-pills-css-vars
.nav-link {
@include border-radius(var(--#{$prefix}nav-pills-border-radius));
}
.nav-link.active,
.show > .nav-link {
color: var(--#{$prefix}nav-pills-link-active-color);
@include gradient-bg(var(--#{$prefix}nav-pills-link-active-bg));
}
}
//
// Underline
//
.nav-underline {
// scss-docs-start nav-underline-css-vars
--#{$prefix}nav-underline-gap: #{$nav-underline-gap};
--#{$prefix}nav-underline-border-width: #{$nav-underline-border-width};
--#{$prefix}nav-underline-link-active-color: #{$nav-underline-link-active-color};
// scss-docs-end nav-underline-css-vars
gap: var(--#{$prefix}nav-underline-gap);
.nav-link {
padding-right: 0;
padding-left: 0;
border-bottom: var(--#{$prefix}nav-underline-border-width) solid transparent;
&:hover,
&:focus {
border-bottom-color: currentcolor;
}
}
.nav-link.active,
.show > .nav-link {
font-weight: $font-weight-bold;
color: var(--#{$prefix}nav-underline-link-active-color);
border-bottom-color: currentcolor;
}
}
//
// Justified variants
//
.nav-fill {
> .nav-link,
.nav-item {
flex: 1 1 auto;
text-align: center;
}
}
.nav-justified {
> .nav-link,
.nav-item {
flex-basis: 0;
flex-grow: 1;
text-align: center;
}
}
.nav-fill,
.nav-justified {
.nav-item .nav-link {
width: 100%; // Make sure button will grow
}
}
// Tabbable tabs
//
// Hide tabbable panes to start, show them when `.active`
.tab-content {
> .tab-pane {
display: none;
}
> .active {
display: block;
}
}

View File

@ -0,0 +1,289 @@
// Navbar
//
// Provide a static navbar from which we expand to create full-width, fixed, and
// other navbar variations.
.navbar {
// scss-docs-start navbar-css-vars
--#{$prefix}navbar-padding-x: #{if($navbar-padding-x == null, 0, $navbar-padding-x)};
--#{$prefix}navbar-padding-y: #{$navbar-padding-y};
--#{$prefix}navbar-color: #{$navbar-light-color};
--#{$prefix}navbar-hover-color: #{$navbar-light-hover-color};
--#{$prefix}navbar-disabled-color: #{$navbar-light-disabled-color};
--#{$prefix}navbar-active-color: #{$navbar-light-active-color};
--#{$prefix}navbar-brand-padding-y: #{$navbar-brand-padding-y};
--#{$prefix}navbar-brand-margin-end: #{$navbar-brand-margin-end};
--#{$prefix}navbar-brand-font-size: #{$navbar-brand-font-size};
--#{$prefix}navbar-brand-color: #{$navbar-light-brand-color};
--#{$prefix}navbar-brand-hover-color: #{$navbar-light-brand-hover-color};
--#{$prefix}navbar-nav-link-padding-x: #{$navbar-nav-link-padding-x};
--#{$prefix}navbar-toggler-padding-y: #{$navbar-toggler-padding-y};
--#{$prefix}navbar-toggler-padding-x: #{$navbar-toggler-padding-x};
--#{$prefix}navbar-toggler-font-size: #{$navbar-toggler-font-size};
--#{$prefix}navbar-toggler-icon-bg: #{escape-svg($navbar-light-toggler-icon-bg)};
--#{$prefix}navbar-toggler-border-color: #{$navbar-light-toggler-border-color};
--#{$prefix}navbar-toggler-border-radius: #{$navbar-toggler-border-radius};
--#{$prefix}navbar-toggler-focus-width: #{$navbar-toggler-focus-width};
--#{$prefix}navbar-toggler-transition: #{$navbar-toggler-transition};
// scss-docs-end navbar-css-vars
position: relative;
display: flex;
flex-wrap: wrap; // allow us to do the line break for collapsing content
align-items: center;
justify-content: space-between; // space out brand from logo
padding: var(--#{$prefix}navbar-padding-y) var(--#{$prefix}navbar-padding-x);
@include gradient-bg();
// Because flex properties aren't inherited, we need to redeclare these first
// few properties so that content nested within behave properly.
// The `flex-wrap` property is inherited to simplify the expanded navbars
%container-flex-properties {
display: flex;
flex-wrap: inherit;
align-items: center;
justify-content: space-between;
}
> .container,
> .container-fluid {
@extend %container-flex-properties;
}
@each $breakpoint, $container-max-width in $container-max-widths {
> .container#{breakpoint-infix($breakpoint, $container-max-widths)} {
@extend %container-flex-properties;
}
}
}
// Navbar brand
//
// Used for brand, project, or site names.
.navbar-brand {
padding-top: var(--#{$prefix}navbar-brand-padding-y);
padding-bottom: var(--#{$prefix}navbar-brand-padding-y);
margin-right: var(--#{$prefix}navbar-brand-margin-end);
@include font-size(var(--#{$prefix}navbar-brand-font-size));
color: var(--#{$prefix}navbar-brand-color);
text-decoration: if($link-decoration == none, null, none);
white-space: nowrap;
&:hover,
&:focus {
color: var(--#{$prefix}navbar-brand-hover-color);
text-decoration: if($link-hover-decoration == underline, none, null);
}
}
// Navbar nav
//
// Custom navbar navigation (doesn't require `.nav`, but does make use of `.nav-link`).
.navbar-nav {
// scss-docs-start navbar-nav-css-vars
--#{$prefix}nav-link-padding-x: 0;
--#{$prefix}nav-link-padding-y: #{$nav-link-padding-y};
@include rfs($nav-link-font-size, --#{$prefix}nav-link-font-size);
--#{$prefix}nav-link-font-weight: #{$nav-link-font-weight};
--#{$prefix}nav-link-color: var(--#{$prefix}navbar-color);
--#{$prefix}nav-link-hover-color: var(--#{$prefix}navbar-hover-color);
--#{$prefix}nav-link-disabled-color: var(--#{$prefix}navbar-disabled-color);
// scss-docs-end navbar-nav-css-vars
display: flex;
flex-direction: column; // cannot use `inherit` to get the `.navbar`s value
padding-left: 0;
margin-bottom: 0;
list-style: none;
.nav-link {
&.active,
&.show {
color: var(--#{$prefix}navbar-active-color);
}
}
.dropdown-menu {
position: static;
}
}
// Navbar text
//
//
.navbar-text {
padding-top: $nav-link-padding-y;
padding-bottom: $nav-link-padding-y;
color: var(--#{$prefix}navbar-color);
a,
a:hover,
a:focus {
color: var(--#{$prefix}navbar-active-color);
}
}
// Responsive navbar
//
// Custom styles for responsive collapsing and toggling of navbar contents.
// Powered by the collapse Bootstrap JavaScript plugin.
// When collapsed, prevent the toggleable navbar contents from appearing in
// the default flexbox row orientation. Requires the use of `flex-wrap: wrap`
// on the `.navbar` parent.
.navbar-collapse {
flex-basis: 100%;
flex-grow: 1;
// For always expanded or extra full navbars, ensure content aligns itself
// properly vertically. Can be easily overridden with flex utilities.
align-items: center;
}
// Button for toggling the navbar when in its collapsed state
.navbar-toggler {
padding: var(--#{$prefix}navbar-toggler-padding-y) var(--#{$prefix}navbar-toggler-padding-x);
@include font-size(var(--#{$prefix}navbar-toggler-font-size));
line-height: 1;
color: var(--#{$prefix}navbar-color);
background-color: transparent; // remove default button style
border: var(--#{$prefix}border-width) solid var(--#{$prefix}navbar-toggler-border-color); // remove default button style
@include border-radius(var(--#{$prefix}navbar-toggler-border-radius));
@include transition(var(--#{$prefix}navbar-toggler-transition));
&:hover {
text-decoration: none;
}
&:focus {
text-decoration: none;
outline: 0;
box-shadow: 0 0 0 var(--#{$prefix}navbar-toggler-focus-width);
}
}
// Keep as a separate element so folks can easily override it with another icon
// or image file as needed.
.navbar-toggler-icon {
display: inline-block;
width: 1.5em;
height: 1.5em;
vertical-align: middle;
background-image: var(--#{$prefix}navbar-toggler-icon-bg);
background-repeat: no-repeat;
background-position: center;
background-size: 100%;
}
.navbar-nav-scroll {
max-height: var(--#{$prefix}scroll-height, 75vh);
overflow-y: auto;
}
// scss-docs-start navbar-expand-loop
// Generate series of `.navbar-expand-*` responsive classes for configuring
// where your navbar collapses.
.navbar-expand {
@each $breakpoint in map-keys($grid-breakpoints) {
$next: breakpoint-next($breakpoint, $grid-breakpoints);
$infix: breakpoint-infix($next, $grid-breakpoints);
// stylelint-disable-next-line scss/selector-no-union-class-name
&#{$infix} {
@include media-breakpoint-up($next) {
flex-wrap: nowrap;
justify-content: flex-start;
.navbar-nav {
flex-direction: row;
.dropdown-menu {
position: absolute;
}
.nav-link {
padding-right: var(--#{$prefix}navbar-nav-link-padding-x);
padding-left: var(--#{$prefix}navbar-nav-link-padding-x);
}
}
.navbar-nav-scroll {
overflow: visible;
}
.navbar-collapse {
display: flex !important; // stylelint-disable-line declaration-no-important
flex-basis: auto;
}
.navbar-toggler {
display: none;
}
.offcanvas {
// stylelint-disable declaration-no-important
position: static;
z-index: auto;
flex-grow: 1;
width: auto !important;
height: auto !important;
visibility: visible !important;
background-color: transparent !important;
border: 0 !important;
transform: none !important;
@include box-shadow(none);
@include transition(none);
// stylelint-enable declaration-no-important
.offcanvas-header {
display: none;
}
.offcanvas-body {
display: flex;
flex-grow: 0;
padding: 0;
overflow-y: visible;
}
}
}
}
}
}
// scss-docs-end navbar-expand-loop
// Navbar themes
//
// Styles for switching between navbars with light or dark background.
.navbar-light {
@include deprecate("`.navbar-light`", "v5.2.0", "v6.0.0", true);
}
.navbar-dark,
.navbar[data-bs-theme="dark"] {
// scss-docs-start navbar-dark-css-vars
--#{$prefix}navbar-color: #{$navbar-dark-color};
--#{$prefix}navbar-hover-color: #{$navbar-dark-hover-color};
--#{$prefix}navbar-disabled-color: #{$navbar-dark-disabled-color};
--#{$prefix}navbar-active-color: #{$navbar-dark-active-color};
--#{$prefix}navbar-brand-color: #{$navbar-dark-brand-color};
--#{$prefix}navbar-brand-hover-color: #{$navbar-dark-brand-hover-color};
--#{$prefix}navbar-toggler-border-color: #{$navbar-dark-toggler-border-color};
--#{$prefix}navbar-toggler-icon-bg: #{escape-svg($navbar-dark-toggler-icon-bg)};
// scss-docs-end navbar-dark-css-vars
}
@if $enable-dark-mode {
@include color-mode(dark) {
.navbar-toggler-icon {
--#{$prefix}navbar-toggler-icon-bg: #{escape-svg($navbar-dark-toggler-icon-bg)};
}
}
}

View File

@ -0,0 +1,146 @@
// stylelint-disable function-disallowed-list
%offcanvas-css-vars {
// scss-docs-start offcanvas-css-vars
--#{$prefix}offcanvas-zindex: #{$zindex-offcanvas};
--#{$prefix}offcanvas-width: #{$offcanvas-horizontal-width};
--#{$prefix}offcanvas-height: #{$offcanvas-vertical-height};
--#{$prefix}offcanvas-padding-x: #{$offcanvas-padding-x};
--#{$prefix}offcanvas-padding-y: #{$offcanvas-padding-y};
--#{$prefix}offcanvas-color: #{$offcanvas-color};
--#{$prefix}offcanvas-bg: #{$offcanvas-bg-color};
--#{$prefix}offcanvas-border-width: #{$offcanvas-border-width};
--#{$prefix}offcanvas-border-color: #{$offcanvas-border-color};
--#{$prefix}offcanvas-box-shadow: #{$offcanvas-box-shadow};
--#{$prefix}offcanvas-transition: #{transform $offcanvas-transition-duration ease-in-out};
--#{$prefix}offcanvas-title-line-height: #{$offcanvas-title-line-height};
// scss-docs-end offcanvas-css-vars
}
@each $breakpoint in map-keys($grid-breakpoints) {
$next: breakpoint-next($breakpoint, $grid-breakpoints);
$infix: breakpoint-infix($next, $grid-breakpoints);
.offcanvas#{$infix} {
@extend %offcanvas-css-vars;
}
}
@each $breakpoint in map-keys($grid-breakpoints) {
$next: breakpoint-next($breakpoint, $grid-breakpoints);
$infix: breakpoint-infix($next, $grid-breakpoints);
.offcanvas#{$infix} {
@include media-breakpoint-down($next) {
position: fixed;
bottom: 0;
z-index: var(--#{$prefix}offcanvas-zindex);
display: flex;
flex-direction: column;
max-width: 100%;
color: var(--#{$prefix}offcanvas-color);
visibility: hidden;
background-color: var(--#{$prefix}offcanvas-bg);
background-clip: padding-box;
outline: 0;
@include box-shadow(var(--#{$prefix}offcanvas-box-shadow));
@include transition(var(--#{$prefix}offcanvas-transition));
&.offcanvas-start {
top: 0;
left: 0;
width: var(--#{$prefix}offcanvas-width);
border-right: var(--#{$prefix}offcanvas-border-width) solid var(--#{$prefix}offcanvas-border-color);
transform: translateX(-100%);
}
&.offcanvas-end {
top: 0;
right: 0;
width: var(--#{$prefix}offcanvas-width);
border-left: var(--#{$prefix}offcanvas-border-width) solid var(--#{$prefix}offcanvas-border-color);
transform: translateX(100%);
}
&.offcanvas-top {
top: 0;
right: 0;
left: 0;
height: var(--#{$prefix}offcanvas-height);
max-height: 100%;
border-bottom: var(--#{$prefix}offcanvas-border-width) solid var(--#{$prefix}offcanvas-border-color);
transform: translateY(-100%);
}
&.offcanvas-bottom {
right: 0;
left: 0;
height: var(--#{$prefix}offcanvas-height);
max-height: 100%;
border-top: var(--#{$prefix}offcanvas-border-width) solid var(--#{$prefix}offcanvas-border-color);
transform: translateY(100%);
}
&.showing,
&.show:not(.hiding) {
transform: none;
}
&.showing,
&.hiding,
&.show {
visibility: visible;
}
}
@if not ($infix == "") {
@include media-breakpoint-up($next) {
--#{$prefix}offcanvas-height: auto;
--#{$prefix}offcanvas-border-width: 0;
background-color: transparent !important; // stylelint-disable-line declaration-no-important
.offcanvas-header {
display: none;
}
.offcanvas-body {
display: flex;
flex-grow: 0;
padding: 0;
overflow-y: visible;
// Reset `background-color` in case `.bg-*` classes are used in offcanvas
background-color: transparent !important; // stylelint-disable-line declaration-no-important
}
}
}
}
}
.offcanvas-backdrop {
@include overlay-backdrop($zindex-offcanvas-backdrop, $offcanvas-backdrop-bg, $offcanvas-backdrop-opacity);
}
.offcanvas-header {
display: flex;
align-items: center;
justify-content: space-between;
padding: var(--#{$prefix}offcanvas-padding-y) var(--#{$prefix}offcanvas-padding-x);
.btn-close {
padding: calc(var(--#{$prefix}offcanvas-padding-y) * .5) calc(var(--#{$prefix}offcanvas-padding-x) * .5);
margin-top: calc(-.5 * var(--#{$prefix}offcanvas-padding-y));
margin-right: calc(-.5 * var(--#{$prefix}offcanvas-padding-x));
margin-bottom: calc(-.5 * var(--#{$prefix}offcanvas-padding-y));
}
}
.offcanvas-title {
margin-bottom: 0;
line-height: var(--#{$prefix}offcanvas-title-line-height);
}
.offcanvas-body {
flex-grow: 1;
padding: var(--#{$prefix}offcanvas-padding-y) var(--#{$prefix}offcanvas-padding-x);
overflow-y: auto;
}

View File

@ -0,0 +1,109 @@
.pagination {
// scss-docs-start pagination-css-vars
--#{$prefix}pagination-padding-x: #{$pagination-padding-x};
--#{$prefix}pagination-padding-y: #{$pagination-padding-y};
@include rfs($pagination-font-size, --#{$prefix}pagination-font-size);
--#{$prefix}pagination-color: #{$pagination-color};
--#{$prefix}pagination-bg: #{$pagination-bg};
--#{$prefix}pagination-border-width: #{$pagination-border-width};
--#{$prefix}pagination-border-color: #{$pagination-border-color};
--#{$prefix}pagination-border-radius: #{$pagination-border-radius};
--#{$prefix}pagination-hover-color: #{$pagination-hover-color};
--#{$prefix}pagination-hover-bg: #{$pagination-hover-bg};
--#{$prefix}pagination-hover-border-color: #{$pagination-hover-border-color};
--#{$prefix}pagination-focus-color: #{$pagination-focus-color};
--#{$prefix}pagination-focus-bg: #{$pagination-focus-bg};
--#{$prefix}pagination-focus-box-shadow: #{$pagination-focus-box-shadow};
--#{$prefix}pagination-active-color: #{$pagination-active-color};
--#{$prefix}pagination-active-bg: #{$pagination-active-bg};
--#{$prefix}pagination-active-border-color: #{$pagination-active-border-color};
--#{$prefix}pagination-disabled-color: #{$pagination-disabled-color};
--#{$prefix}pagination-disabled-bg: #{$pagination-disabled-bg};
--#{$prefix}pagination-disabled-border-color: #{$pagination-disabled-border-color};
// scss-docs-end pagination-css-vars
display: flex;
@include list-unstyled();
}
.page-link {
position: relative;
display: block;
padding: var(--#{$prefix}pagination-padding-y) var(--#{$prefix}pagination-padding-x);
@include font-size(var(--#{$prefix}pagination-font-size));
color: var(--#{$prefix}pagination-color);
text-decoration: if($link-decoration == none, null, none);
background-color: var(--#{$prefix}pagination-bg);
border: var(--#{$prefix}pagination-border-width) solid var(--#{$prefix}pagination-border-color);
@include transition($pagination-transition);
&:hover {
z-index: 2;
color: var(--#{$prefix}pagination-hover-color);
text-decoration: if($link-hover-decoration == underline, none, null);
background-color: var(--#{$prefix}pagination-hover-bg);
border-color: var(--#{$prefix}pagination-hover-border-color);
}
&:focus {
z-index: 3;
color: var(--#{$prefix}pagination-focus-color);
background-color: var(--#{$prefix}pagination-focus-bg);
outline: $pagination-focus-outline;
box-shadow: var(--#{$prefix}pagination-focus-box-shadow);
}
&.active,
.active > & {
z-index: 3;
color: var(--#{$prefix}pagination-active-color);
@include gradient-bg(var(--#{$prefix}pagination-active-bg));
border-color: var(--#{$prefix}pagination-active-border-color);
}
&.disabled,
.disabled > & {
color: var(--#{$prefix}pagination-disabled-color);
pointer-events: none;
background-color: var(--#{$prefix}pagination-disabled-bg);
border-color: var(--#{$prefix}pagination-disabled-border-color);
}
}
.page-item {
&:not(:first-child) .page-link {
margin-left: $pagination-margin-start;
}
@if $pagination-margin-start == calc(#{$pagination-border-width} * -1) {
&:first-child {
.page-link {
@include border-start-radius(var(--#{$prefix}pagination-border-radius));
}
}
&:last-child {
.page-link {
@include border-end-radius(var(--#{$prefix}pagination-border-radius));
}
}
} @else {
// Add border-radius to all pageLinks in case they have left margin
.page-link {
@include border-radius(var(--#{$prefix}pagination-border-radius));
}
}
}
//
// Sizing
//
.pagination-lg {
@include pagination-size($pagination-padding-y-lg, $pagination-padding-x-lg, $font-size-lg, $pagination-border-radius-lg);
}
.pagination-sm {
@include pagination-size($pagination-padding-y-sm, $pagination-padding-x-sm, $font-size-sm, $pagination-border-radius-sm);
}

View File

@ -0,0 +1,51 @@
.placeholder {
display: inline-block;
min-height: 1em;
vertical-align: middle;
cursor: wait;
background-color: currentcolor;
opacity: $placeholder-opacity-max;
&.btn::before {
display: inline-block;
content: "";
}
}
// Sizing
.placeholder-xs {
min-height: .6em;
}
.placeholder-sm {
min-height: .8em;
}
.placeholder-lg {
min-height: 1.2em;
}
// Animation
.placeholder-glow {
.placeholder {
animation: placeholder-glow 2s ease-in-out infinite;
}
}
@keyframes placeholder-glow {
50% {
opacity: $placeholder-opacity-min;
}
}
.placeholder-wave {
mask-image: linear-gradient(130deg, $black 55%, rgba(0, 0, 0, (1 - $placeholder-opacity-min)) 75%, $black 95%);
mask-size: 200% 100%;
animation: placeholder-wave 2s linear infinite;
}
@keyframes placeholder-wave {
100% {
mask-position: -200% 0%;
}
}

View File

@ -0,0 +1,196 @@
.popover {
// scss-docs-start popover-css-vars
--#{$prefix}popover-zindex: #{$zindex-popover};
--#{$prefix}popover-max-width: #{$popover-max-width};
@include rfs($popover-font-size, --#{$prefix}popover-font-size);
--#{$prefix}popover-bg: #{$popover-bg};
--#{$prefix}popover-border-width: #{$popover-border-width};
--#{$prefix}popover-border-color: #{$popover-border-color};
--#{$prefix}popover-border-radius: #{$popover-border-radius};
--#{$prefix}popover-inner-border-radius: #{$popover-inner-border-radius};
--#{$prefix}popover-box-shadow: #{$popover-box-shadow};
--#{$prefix}popover-header-padding-x: #{$popover-header-padding-x};
--#{$prefix}popover-header-padding-y: #{$popover-header-padding-y};
@include rfs($popover-header-font-size, --#{$prefix}popover-header-font-size);
--#{$prefix}popover-header-color: #{$popover-header-color};
--#{$prefix}popover-header-bg: #{$popover-header-bg};
--#{$prefix}popover-body-padding-x: #{$popover-body-padding-x};
--#{$prefix}popover-body-padding-y: #{$popover-body-padding-y};
--#{$prefix}popover-body-color: #{$popover-body-color};
--#{$prefix}popover-arrow-width: #{$popover-arrow-width};
--#{$prefix}popover-arrow-height: #{$popover-arrow-height};
--#{$prefix}popover-arrow-border: var(--#{$prefix}popover-border-color);
// scss-docs-end popover-css-vars
z-index: var(--#{$prefix}popover-zindex);
display: block;
max-width: var(--#{$prefix}popover-max-width);
// Our parent element can be arbitrary since tooltips are by default inserted as a sibling of their target element.
// So reset our font and text properties to avoid inheriting weird values.
@include reset-text();
@include font-size(var(--#{$prefix}popover-font-size));
// Allow breaking very long words so they don't overflow the popover's bounds
word-wrap: break-word;
background-color: var(--#{$prefix}popover-bg);
background-clip: padding-box;
border: var(--#{$prefix}popover-border-width) solid var(--#{$prefix}popover-border-color);
@include border-radius(var(--#{$prefix}popover-border-radius));
@include box-shadow(var(--#{$prefix}popover-box-shadow));
.popover-arrow {
display: block;
width: var(--#{$prefix}popover-arrow-width);
height: var(--#{$prefix}popover-arrow-height);
&::before,
&::after {
position: absolute;
display: block;
content: "";
border-color: transparent;
border-style: solid;
border-width: 0;
}
}
}
.bs-popover-top {
> .popover-arrow {
bottom: calc(-1 * (var(--#{$prefix}popover-arrow-height)) - var(--#{$prefix}popover-border-width)); // stylelint-disable-line function-disallowed-list
&::before,
&::after {
border-width: var(--#{$prefix}popover-arrow-height) calc(var(--#{$prefix}popover-arrow-width) * .5) 0; // stylelint-disable-line function-disallowed-list
}
&::before {
bottom: 0;
border-top-color: var(--#{$prefix}popover-arrow-border);
}
&::after {
bottom: var(--#{$prefix}popover-border-width);
border-top-color: var(--#{$prefix}popover-bg);
}
}
}
/* rtl:begin:ignore */
.bs-popover-end {
> .popover-arrow {
left: calc(-1 * (var(--#{$prefix}popover-arrow-height)) - var(--#{$prefix}popover-border-width)); // stylelint-disable-line function-disallowed-list
width: var(--#{$prefix}popover-arrow-height);
height: var(--#{$prefix}popover-arrow-width);
&::before,
&::after {
border-width: calc(var(--#{$prefix}popover-arrow-width) * .5) var(--#{$prefix}popover-arrow-height) calc(var(--#{$prefix}popover-arrow-width) * .5) 0; // stylelint-disable-line function-disallowed-list
}
&::before {
left: 0;
border-right-color: var(--#{$prefix}popover-arrow-border);
}
&::after {
left: var(--#{$prefix}popover-border-width);
border-right-color: var(--#{$prefix}popover-bg);
}
}
}
/* rtl:end:ignore */
.bs-popover-bottom {
> .popover-arrow {
top: calc(-1 * (var(--#{$prefix}popover-arrow-height)) - var(--#{$prefix}popover-border-width)); // stylelint-disable-line function-disallowed-list
&::before,
&::after {
border-width: 0 calc(var(--#{$prefix}popover-arrow-width) * .5) var(--#{$prefix}popover-arrow-height); // stylelint-disable-line function-disallowed-list
}
&::before {
top: 0;
border-bottom-color: var(--#{$prefix}popover-arrow-border);
}
&::after {
top: var(--#{$prefix}popover-border-width);
border-bottom-color: var(--#{$prefix}popover-bg);
}
}
// This will remove the popover-header's border just below the arrow
.popover-header::before {
position: absolute;
top: 0;
left: 50%;
display: block;
width: var(--#{$prefix}popover-arrow-width);
margin-left: calc(-.5 * var(--#{$prefix}popover-arrow-width)); // stylelint-disable-line function-disallowed-list
content: "";
border-bottom: var(--#{$prefix}popover-border-width) solid var(--#{$prefix}popover-header-bg);
}
}
/* rtl:begin:ignore */
.bs-popover-start {
> .popover-arrow {
right: calc(-1 * (var(--#{$prefix}popover-arrow-height)) - var(--#{$prefix}popover-border-width)); // stylelint-disable-line function-disallowed-list
width: var(--#{$prefix}popover-arrow-height);
height: var(--#{$prefix}popover-arrow-width);
&::before,
&::after {
border-width: calc(var(--#{$prefix}popover-arrow-width) * .5) 0 calc(var(--#{$prefix}popover-arrow-width) * .5) var(--#{$prefix}popover-arrow-height); // stylelint-disable-line function-disallowed-list
}
&::before {
right: 0;
border-left-color: var(--#{$prefix}popover-arrow-border);
}
&::after {
right: var(--#{$prefix}popover-border-width);
border-left-color: var(--#{$prefix}popover-bg);
}
}
}
/* rtl:end:ignore */
.bs-popover-auto {
&[data-popper-placement^="top"] {
@extend .bs-popover-top;
}
&[data-popper-placement^="right"] {
@extend .bs-popover-end;
}
&[data-popper-placement^="bottom"] {
@extend .bs-popover-bottom;
}
&[data-popper-placement^="left"] {
@extend .bs-popover-start;
}
}
// Offset the popover to account for the popover arrow
.popover-header {
padding: var(--#{$prefix}popover-header-padding-y) var(--#{$prefix}popover-header-padding-x);
margin-bottom: 0; // Reset the default from Reboot
@include font-size(var(--#{$prefix}popover-header-font-size));
color: var(--#{$prefix}popover-header-color);
background-color: var(--#{$prefix}popover-header-bg);
border-bottom: var(--#{$prefix}popover-border-width) solid var(--#{$prefix}popover-border-color);
@include border-top-radius(var(--#{$prefix}popover-inner-border-radius));
&:empty {
display: none;
}
}
.popover-body {
padding: var(--#{$prefix}popover-body-padding-y) var(--#{$prefix}popover-body-padding-x);
color: var(--#{$prefix}popover-body-color);
}

View File

@ -0,0 +1,68 @@
// Disable animation if transitions are disabled
// scss-docs-start progress-keyframes
@if $enable-transitions {
@keyframes progress-bar-stripes {
0% { background-position-x: $progress-height; }
}
}
// scss-docs-end progress-keyframes
.progress,
.progress-stacked {
// scss-docs-start progress-css-vars
--#{$prefix}progress-height: #{$progress-height};
@include rfs($progress-font-size, --#{$prefix}progress-font-size);
--#{$prefix}progress-bg: #{$progress-bg};
--#{$prefix}progress-border-radius: #{$progress-border-radius};
--#{$prefix}progress-box-shadow: #{$progress-box-shadow};
--#{$prefix}progress-bar-color: #{$progress-bar-color};
--#{$prefix}progress-bar-bg: #{$progress-bar-bg};
--#{$prefix}progress-bar-transition: #{$progress-bar-transition};
// scss-docs-end progress-css-vars
display: flex;
height: var(--#{$prefix}progress-height);
overflow: hidden; // force rounded corners by cropping it
@include font-size(var(--#{$prefix}progress-font-size));
background-color: var(--#{$prefix}progress-bg);
@include border-radius(var(--#{$prefix}progress-border-radius));
@include box-shadow(var(--#{$prefix}progress-box-shadow));
}
.progress-bar {
display: flex;
flex-direction: column;
justify-content: center;
overflow: hidden;
color: var(--#{$prefix}progress-bar-color);
text-align: center;
white-space: nowrap;
background-color: var(--#{$prefix}progress-bar-bg);
@include transition(var(--#{$prefix}progress-bar-transition));
}
.progress-bar-striped {
@include gradient-striped();
background-size: var(--#{$prefix}progress-height) var(--#{$prefix}progress-height);
}
.progress-stacked > .progress {
overflow: visible;
}
.progress-stacked > .progress > .progress-bar {
width: 100%;
}
@if $enable-transitions {
.progress-bar-animated {
animation: $progress-bar-animation-timing progress-bar-stripes;
@if $enable-reduced-motion {
@media (prefers-reduced-motion: reduce) {
animation: none;
}
}
}
}

View File

@ -0,0 +1,610 @@
// stylelint-disable declaration-no-important, selector-no-qualifying-type, property-no-vendor-prefix
// Reboot
//
// Normalization of HTML elements, manually forked from Normalize.css to remove
// styles targeting irrelevant browsers while applying new styles.
//
// Normalize is licensed MIT. https://github.com/necolas/normalize.css
// Document
//
// Change from `box-sizing: content-box` so that `width` is not affected by `padding` or `border`.
*,
*::before,
*::after {
box-sizing: border-box;
}
// Root
//
// Ability to the value of the root font sizes, affecting the value of `rem`.
// null by default, thus nothing is generated.
:root {
@if $font-size-root != null {
@include font-size(var(--#{$prefix}root-font-size));
}
@if $enable-smooth-scroll {
@media (prefers-reduced-motion: no-preference) {
scroll-behavior: smooth;
}
}
}
// Body
//
// 1. Remove the margin in all browsers.
// 2. As a best practice, apply a default `background-color`.
// 3. Prevent adjustments of font size after orientation changes in iOS.
// 4. Change the default tap highlight to be completely transparent in iOS.
// scss-docs-start reboot-body-rules
body {
margin: 0; // 1
font-family: var(--#{$prefix}body-font-family);
@include font-size(var(--#{$prefix}body-font-size));
font-weight: var(--#{$prefix}body-font-weight);
line-height: var(--#{$prefix}body-line-height);
color: var(--#{$prefix}body-color);
text-align: var(--#{$prefix}body-text-align);
background-color: var(--#{$prefix}body-bg); // 2
-webkit-text-size-adjust: 100%; // 3
-webkit-tap-highlight-color: rgba($black, 0); // 4
}
// scss-docs-end reboot-body-rules
// Content grouping
//
// 1. Reset Firefox's gray color
hr {
margin: $hr-margin-y 0;
color: $hr-color; // 1
border: 0;
border-top: $hr-border-width solid $hr-border-color;
opacity: $hr-opacity;
}
// Typography
//
// 1. Remove top margins from headings
// By default, `<h1>`-`<h6>` all receive top and bottom margins. We nuke the top
// margin for easier control within type scales as it avoids margin collapsing.
%heading {
margin-top: 0; // 1
margin-bottom: $headings-margin-bottom;
font-family: $headings-font-family;
font-style: $headings-font-style;
font-weight: $headings-font-weight;
line-height: $headings-line-height;
color: var(--#{$prefix}heading-color);
}
h1 {
@extend %heading;
@include font-size($h1-font-size);
}
h2 {
@extend %heading;
@include font-size($h2-font-size);
}
h3 {
@extend %heading;
@include font-size($h3-font-size);
}
h4 {
@extend %heading;
@include font-size($h4-font-size);
}
h5 {
@extend %heading;
@include font-size($h5-font-size);
}
h6 {
@extend %heading;
@include font-size($h6-font-size);
}
// Reset margins on paragraphs
//
// Similarly, the top margin on `<p>`s get reset. However, we also reset the
// bottom margin to use `rem` units instead of `em`.
p {
margin-top: 0;
margin-bottom: $paragraph-margin-bottom;
}
// Abbreviations
//
// 1. Add the correct text decoration in Chrome, Edge, Opera, and Safari.
// 2. Add explicit cursor to indicate changed behavior.
// 3. Prevent the text-decoration to be skipped.
abbr[title] {
text-decoration: underline dotted; // 1
cursor: help; // 2
text-decoration-skip-ink: none; // 3
}
// Address
address {
margin-bottom: 1rem;
font-style: normal;
line-height: inherit;
}
// Lists
ol,
ul {
padding-left: 2rem;
}
ol,
ul,
dl {
margin-top: 0;
margin-bottom: 1rem;
}
ol ol,
ul ul,
ol ul,
ul ol {
margin-bottom: 0;
}
dt {
font-weight: $dt-font-weight;
}
// 1. Undo browser default
dd {
margin-bottom: .5rem;
margin-left: 0; // 1
}
// Blockquote
blockquote {
margin: 0 0 1rem;
}
// Strong
//
// Add the correct font weight in Chrome, Edge, and Safari
b,
strong {
font-weight: $font-weight-bolder;
}
// Small
//
// Add the correct font size in all browsers
small {
@include font-size($small-font-size);
}
// Mark
mark {
padding: $mark-padding;
background-color: var(--#{$prefix}highlight-bg);
}
// Sub and Sup
//
// Prevent `sub` and `sup` elements from affecting the line height in
// all browsers.
sub,
sup {
position: relative;
@include font-size($sub-sup-font-size);
line-height: 0;
vertical-align: baseline;
}
sub { bottom: -.25em; }
sup { top: -.5em; }
// Links
a {
color: rgba(var(--#{$prefix}link-color-rgb), var(--#{$prefix}link-opacity, 1));
text-decoration: $link-decoration;
&:hover {
--#{$prefix}link-color-rgb: var(--#{$prefix}link-hover-color-rgb);
text-decoration: $link-hover-decoration;
}
}
// And undo these styles for placeholder links/named anchors (without href).
// It would be more straightforward to just use a[href] in previous block, but that
// causes specificity issues in many other styles that are too complex to fix.
// See https://github.com/twbs/bootstrap/issues/19402
a:not([href]):not([class]) {
&,
&:hover {
color: inherit;
text-decoration: none;
}
}
// Code
pre,
code,
kbd,
samp {
font-family: $font-family-code;
@include font-size(1em); // Correct the odd `em` font sizing in all browsers.
}
// 1. Remove browser default top margin
// 2. Reset browser default of `1em` to use `rem`s
// 3. Don't allow content to break outside
pre {
display: block;
margin-top: 0; // 1
margin-bottom: 1rem; // 2
overflow: auto; // 3
@include font-size($code-font-size);
color: $pre-color;
// Account for some code outputs that place code tags in pre tags
code {
@include font-size(inherit);
color: inherit;
word-break: normal;
}
}
code {
@include font-size($code-font-size);
color: var(--#{$prefix}code-color);
word-wrap: break-word;
// Streamline the style when inside anchors to avoid broken underline and more
a > & {
color: inherit;
}
}
kbd {
padding: $kbd-padding-y $kbd-padding-x;
@include font-size($kbd-font-size);
color: $kbd-color;
background-color: $kbd-bg;
@include border-radius($border-radius-sm);
kbd {
padding: 0;
@include font-size(1em);
font-weight: $nested-kbd-font-weight;
}
}
// Figures
//
// Apply a consistent margin strategy (matches our type styles).
figure {
margin: 0 0 1rem;
}
// Images and content
img,
svg {
vertical-align: middle;
}
// Tables
//
// Prevent double borders
table {
caption-side: bottom;
border-collapse: collapse;
}
caption {
padding-top: $table-cell-padding-y;
padding-bottom: $table-cell-padding-y;
color: $table-caption-color;
text-align: left;
}
// 1. Removes font-weight bold by inheriting
// 2. Matches default `<td>` alignment by inheriting `text-align`.
// 3. Fix alignment for Safari
th {
font-weight: $table-th-font-weight; // 1
text-align: inherit; // 2
text-align: -webkit-match-parent; // 3
}
thead,
tbody,
tfoot,
tr,
td,
th {
border-color: inherit;
border-style: solid;
border-width: 0;
}
// Forms
//
// 1. Allow labels to use `margin` for spacing.
label {
display: inline-block; // 1
}
// Remove the default `border-radius` that macOS Chrome adds.
// See https://github.com/twbs/bootstrap/issues/24093
button {
// stylelint-disable-next-line property-disallowed-list
border-radius: 0;
}
// Explicitly remove focus outline in Chromium when it shouldn't be
// visible (e.g. as result of mouse click or touch tap). It already
// should be doing this automatically, but seems to currently be
// confused and applies its very visible two-tone outline anyway.
button:focus:not(:focus-visible) {
outline: 0;
}
// 1. Remove the margin in Firefox and Safari
input,
button,
select,
optgroup,
textarea {
margin: 0; // 1
font-family: inherit;
@include font-size(inherit);
line-height: inherit;
}
// Remove the inheritance of text transform in Firefox
button,
select {
text-transform: none;
}
// Set the cursor for non-`<button>` buttons
//
// Details at https://github.com/twbs/bootstrap/pull/30562
[role="button"] {
cursor: pointer;
}
select {
// Remove the inheritance of word-wrap in Safari.
// See https://github.com/twbs/bootstrap/issues/24990
word-wrap: normal;
// Undo the opacity change from Chrome
&:disabled {
opacity: 1;
}
}
// Remove the dropdown arrow only from text type inputs built with datalists in Chrome.
// See https://stackoverflow.com/a/54997118
[list]:not([type="date"]):not([type="datetime-local"]):not([type="month"]):not([type="week"]):not([type="time"])::-webkit-calendar-picker-indicator {
display: none !important;
}
// 1. Prevent a WebKit bug where (2) destroys native `audio` and `video`
// controls in Android 4.
// 2. Correct the inability to style clickable types in iOS and Safari.
// 3. Opinionated: add "hand" cursor to non-disabled button elements.
button,
[type="button"], // 1
[type="reset"],
[type="submit"] {
-webkit-appearance: button; // 2
@if $enable-button-pointers {
&:not(:disabled) {
cursor: pointer; // 3
}
}
}
// Remove inner border and padding from Firefox, but don't restore the outline like Normalize.
::-moz-focus-inner {
padding: 0;
border-style: none;
}
// 1. Textareas should really only resize vertically so they don't break their (horizontal) containers.
textarea {
resize: vertical; // 1
}
// 1. Browsers set a default `min-width: min-content;` on fieldsets,
// unlike e.g. `<div>`s, which have `min-width: 0;` by default.
// So we reset that to ensure fieldsets behave more like a standard block element.
// See https://github.com/twbs/bootstrap/issues/12359
// and https://html.spec.whatwg.org/multipage/#the-fieldset-and-legend-elements
// 2. Reset the default outline behavior of fieldsets so they don't affect page layout.
fieldset {
min-width: 0; // 1
padding: 0; // 2
margin: 0; // 2
border: 0; // 2
}
// 1. By using `float: left`, the legend will behave like a block element.
// This way the border of a fieldset wraps around the legend if present.
// 2. Fix wrapping bug.
// See https://github.com/twbs/bootstrap/issues/29712
legend {
float: left; // 1
width: 100%;
padding: 0;
margin-bottom: $legend-margin-bottom;
@include font-size($legend-font-size);
font-weight: $legend-font-weight;
line-height: inherit;
+ * {
clear: left; // 2
}
}
// Fix height of inputs with a type of datetime-local, date, month, week, or time
// See https://github.com/twbs/bootstrap/issues/18842
::-webkit-datetime-edit-fields-wrapper,
::-webkit-datetime-edit-text,
::-webkit-datetime-edit-minute,
::-webkit-datetime-edit-hour-field,
::-webkit-datetime-edit-day-field,
::-webkit-datetime-edit-month-field,
::-webkit-datetime-edit-year-field {
padding: 0;
}
::-webkit-inner-spin-button {
height: auto;
}
// 1. This overrides the extra rounded corners on search inputs in iOS so that our
// `.form-control` class can properly style them. Note that this cannot simply
// be added to `.form-control` as it's not specific enough. For details, see
// https://github.com/twbs/bootstrap/issues/11586.
// 2. Correct the outline style in Safari.
[type="search"] {
-webkit-appearance: textfield; // 1
outline-offset: -2px; // 2
}
// 1. A few input types should stay LTR
// See https://rtlstyling.com/posts/rtl-styling#form-inputs
// 2. RTL only output
// See https://rtlcss.com/learn/usage-guide/control-directives/#raw
/* rtl:raw:
[type="tel"],
[type="url"],
[type="email"],
[type="number"] {
direction: ltr;
}
*/
// Remove the inner padding in Chrome and Safari on macOS.
::-webkit-search-decoration {
-webkit-appearance: none;
}
// Remove padding around color pickers in webkit browsers
::-webkit-color-swatch-wrapper {
padding: 0;
}
// 1. Inherit font family and line height for file input buttons
// 2. Correct the inability to style clickable types in iOS and Safari.
::file-selector-button {
font: inherit; // 1
-webkit-appearance: button; // 2
}
// Correct element displays
output {
display: inline-block;
}
// Remove border from iframe
iframe {
border: 0;
}
// Summary
//
// 1. Add the correct display in all browsers
summary {
display: list-item; // 1
cursor: pointer;
}
// Progress
//
// Add the correct vertical alignment in Chrome, Firefox, and Opera.
progress {
vertical-align: baseline;
}
// Hidden attribute
//
// Always hide an element with the `hidden` HTML attribute.
[hidden] {
display: none !important;
}

View File

@ -0,0 +1,184 @@
:root,
[data-bs-theme="light"] {
// Note: Custom variable values only support SassScript inside `#{}`.
// Colors
//
// Generate palettes for full colors, grays, and theme colors.
@each $color, $value in $colors {
--#{$prefix}#{$color}: #{$value};
}
@each $color, $value in $grays {
--#{$prefix}gray-#{$color}: #{$value};
}
@each $color, $value in $theme-colors {
--#{$prefix}#{$color}: #{$value};
}
@each $color, $value in $theme-colors-rgb {
--#{$prefix}#{$color}-rgb: #{$value};
}
@each $color, $value in $theme-colors-text {
--#{$prefix}#{$color}-text-emphasis: #{$value};
}
@each $color, $value in $theme-colors-bg-subtle {
--#{$prefix}#{$color}-bg-subtle: #{$value};
}
@each $color, $value in $theme-colors-border-subtle {
--#{$prefix}#{$color}-border-subtle: #{$value};
}
--#{$prefix}white-rgb: #{to-rgb($white)};
--#{$prefix}black-rgb: #{to-rgb($black)};
// Fonts
// Note: Use `inspect` for lists so that quoted items keep the quotes.
// See https://github.com/sass/sass/issues/2383#issuecomment-336349172
--#{$prefix}font-sans-serif: #{inspect($font-family-sans-serif)};
--#{$prefix}font-monospace: #{inspect($font-family-monospace)};
--#{$prefix}gradient: #{$gradient};
// Root and body
// scss-docs-start root-body-variables
@if $font-size-root != null {
--#{$prefix}root-font-size: #{$font-size-root};
}
--#{$prefix}body-font-family: #{inspect($font-family-base)};
@include rfs($font-size-base, --#{$prefix}body-font-size);
--#{$prefix}body-font-weight: #{$font-weight-base};
--#{$prefix}body-line-height: #{$line-height-base};
@if $body-text-align != null {
--#{$prefix}body-text-align: #{$body-text-align};
}
--#{$prefix}body-color: #{$body-color};
--#{$prefix}body-color-rgb: #{to-rgb($body-color)};
--#{$prefix}body-bg: #{$body-bg};
--#{$prefix}body-bg-rgb: #{to-rgb($body-bg)};
--#{$prefix}emphasis-color: #{$body-emphasis-color};
--#{$prefix}emphasis-color-rgb: #{to-rgb($body-emphasis-color)};
--#{$prefix}secondary-color: #{$body-secondary-color};
--#{$prefix}secondary-color-rgb: #{to-rgb($body-secondary-color)};
--#{$prefix}secondary-bg: #{$body-secondary-bg};
--#{$prefix}secondary-bg-rgb: #{to-rgb($body-secondary-bg)};
--#{$prefix}tertiary-color: #{$body-tertiary-color};
--#{$prefix}tertiary-color-rgb: #{to-rgb($body-tertiary-color)};
--#{$prefix}tertiary-bg: #{$body-tertiary-bg};
--#{$prefix}tertiary-bg-rgb: #{to-rgb($body-tertiary-bg)};
// scss-docs-end root-body-variables
--#{$prefix}heading-color: #{$headings-color};
--#{$prefix}link-color: #{$link-color};
--#{$prefix}link-color-rgb: #{to-rgb($link-color)};
--#{$prefix}link-decoration: #{$link-decoration};
--#{$prefix}link-hover-color: #{$link-hover-color};
--#{$prefix}link-hover-color-rgb: #{to-rgb($link-hover-color)};
@if $link-hover-decoration != null {
--#{$prefix}link-hover-decoration: #{$link-hover-decoration};
}
--#{$prefix}code-color: #{$code-color};
--#{$prefix}highlight-bg: #{$mark-bg};
// scss-docs-start root-border-var
--#{$prefix}border-width: #{$border-width};
--#{$prefix}border-style: #{$border-style};
--#{$prefix}border-color: #{$border-color};
--#{$prefix}border-color-translucent: #{$border-color-translucent};
--#{$prefix}border-radius: #{$border-radius};
--#{$prefix}border-radius-sm: #{$border-radius-sm};
--#{$prefix}border-radius-lg: #{$border-radius-lg};
--#{$prefix}border-radius-xl: #{$border-radius-xl};
--#{$prefix}border-radius-xxl: #{$border-radius-xxl};
--#{$prefix}border-radius-2xl: var(--#{$prefix}border-radius-xxl); // Deprecated in v5.3.0 for consistency
--#{$prefix}border-radius-pill: #{$border-radius-pill};
// scss-docs-end root-border-var
--#{$prefix}box-shadow: #{$box-shadow};
--#{$prefix}box-shadow-sm: #{$box-shadow-sm};
--#{$prefix}box-shadow-lg: #{$box-shadow-lg};
--#{$prefix}box-shadow-inset: #{$box-shadow-inset};
// Focus styles
// scss-docs-start root-focus-variables
--#{$prefix}focus-ring-width: #{$focus-ring-width};
--#{$prefix}focus-ring-opacity: #{$focus-ring-opacity};
--#{$prefix}focus-ring-color: #{$focus-ring-color};
// scss-docs-end root-focus-variables
// scss-docs-start root-form-validation-variables
--#{$prefix}form-valid-color: #{$form-valid-color};
--#{$prefix}form-valid-border-color: #{$form-valid-border-color};
--#{$prefix}form-invalid-color: #{$form-invalid-color};
--#{$prefix}form-invalid-border-color: #{$form-invalid-border-color};
// scss-docs-end root-form-validation-variables
}
@if $enable-dark-mode {
@include color-mode(dark, true) {
color-scheme: dark;
// scss-docs-start root-dark-mode-vars
--#{$prefix}body-color: #{$body-color-dark};
--#{$prefix}body-color-rgb: #{to-rgb($body-color-dark)};
--#{$prefix}body-bg: #{$body-bg-dark};
--#{$prefix}body-bg-rgb: #{to-rgb($body-bg-dark)};
--#{$prefix}emphasis-color: #{$body-emphasis-color-dark};
--#{$prefix}emphasis-color-rgb: #{to-rgb($body-emphasis-color-dark)};
--#{$prefix}secondary-color: #{$body-secondary-color-dark};
--#{$prefix}secondary-color-rgb: #{to-rgb($body-secondary-color-dark)};
--#{$prefix}secondary-bg: #{$body-secondary-bg-dark};
--#{$prefix}secondary-bg-rgb: #{to-rgb($body-secondary-bg-dark)};
--#{$prefix}tertiary-color: #{$body-tertiary-color-dark};
--#{$prefix}tertiary-color-rgb: #{to-rgb($body-tertiary-color-dark)};
--#{$prefix}tertiary-bg: #{$body-tertiary-bg-dark};
--#{$prefix}tertiary-bg-rgb: #{to-rgb($body-tertiary-bg-dark)};
@each $color, $value in $theme-colors-text-dark {
--#{$prefix}#{$color}-text-emphasis: #{$value};
}
@each $color, $value in $theme-colors-bg-subtle-dark {
--#{$prefix}#{$color}-bg-subtle: #{$value};
}
@each $color, $value in $theme-colors-border-subtle-dark {
--#{$prefix}#{$color}-border-subtle: #{$value};
}
--#{$prefix}heading-color: #{$headings-color-dark};
--#{$prefix}link-color: #{$link-color-dark};
--#{$prefix}link-hover-color: #{$link-hover-color-dark};
--#{$prefix}link-color-rgb: #{to-rgb($link-color-dark)};
--#{$prefix}link-hover-color-rgb: #{to-rgb($link-hover-color-dark)};
--#{$prefix}code-color: #{$code-color-dark};
--#{$prefix}border-color: #{$border-color-dark};
--#{$prefix}border-color-translucent: #{$border-color-translucent-dark};
--#{$prefix}form-valid-color: #{$form-valid-color-dark};
--#{$prefix}form-valid-border-color: #{$form-valid-border-color-dark};
--#{$prefix}form-invalid-color: #{$form-invalid-color-dark};
--#{$prefix}form-invalid-border-color: #{$form-invalid-border-color-dark};
// scss-docs-end root-dark-mode-vars
}
}

View File

@ -0,0 +1,85 @@
//
// Rotating border
//
.spinner-grow,
.spinner-border {
display: inline-block;
width: var(--#{$prefix}spinner-width);
height: var(--#{$prefix}spinner-height);
vertical-align: var(--#{$prefix}spinner-vertical-align);
// stylelint-disable-next-line property-disallowed-list
border-radius: 50%;
animation: var(--#{$prefix}spinner-animation-speed) linear infinite var(--#{$prefix}spinner-animation-name);
}
// scss-docs-start spinner-border-keyframes
@keyframes spinner-border {
to { transform: rotate(360deg) #{"/* rtl:ignore */"}; }
}
// scss-docs-end spinner-border-keyframes
.spinner-border {
// scss-docs-start spinner-border-css-vars
--#{$prefix}spinner-width: #{$spinner-width};
--#{$prefix}spinner-height: #{$spinner-height};
--#{$prefix}spinner-vertical-align: #{$spinner-vertical-align};
--#{$prefix}spinner-border-width: #{$spinner-border-width};
--#{$prefix}spinner-animation-speed: #{$spinner-animation-speed};
--#{$prefix}spinner-animation-name: spinner-border;
// scss-docs-end spinner-border-css-vars
border: var(--#{$prefix}spinner-border-width) solid currentcolor;
border-right-color: transparent;
}
.spinner-border-sm {
// scss-docs-start spinner-border-sm-css-vars
--#{$prefix}spinner-width: #{$spinner-width-sm};
--#{$prefix}spinner-height: #{$spinner-height-sm};
--#{$prefix}spinner-border-width: #{$spinner-border-width-sm};
// scss-docs-end spinner-border-sm-css-vars
}
//
// Growing circle
//
// scss-docs-start spinner-grow-keyframes
@keyframes spinner-grow {
0% {
transform: scale(0);
}
50% {
opacity: 1;
transform: none;
}
}
// scss-docs-end spinner-grow-keyframes
.spinner-grow {
// scss-docs-start spinner-grow-css-vars
--#{$prefix}spinner-width: #{$spinner-width};
--#{$prefix}spinner-height: #{$spinner-height};
--#{$prefix}spinner-vertical-align: #{$spinner-vertical-align};
--#{$prefix}spinner-animation-speed: #{$spinner-animation-speed};
--#{$prefix}spinner-animation-name: spinner-grow;
// scss-docs-end spinner-grow-css-vars
background-color: currentcolor;
opacity: 0;
}
.spinner-grow-sm {
--#{$prefix}spinner-width: #{$spinner-width-sm};
--#{$prefix}spinner-height: #{$spinner-height-sm};
}
@if $enable-reduced-motion {
@media (prefers-reduced-motion: reduce) {
.spinner-border,
.spinner-grow {
--#{$prefix}spinner-animation-speed: #{$spinner-animation-speed * 2};
}
}
}

View File

@ -0,0 +1,171 @@
//
// Basic Bootstrap table
//
.table {
// Reset needed for nesting tables
--#{$prefix}table-color-type: initial;
--#{$prefix}table-bg-type: initial;
--#{$prefix}table-color-state: initial;
--#{$prefix}table-bg-state: initial;
// End of reset
--#{$prefix}table-color: #{$table-color};
--#{$prefix}table-bg: #{$table-bg};
--#{$prefix}table-border-color: #{$table-border-color};
--#{$prefix}table-accent-bg: #{$table-accent-bg};
--#{$prefix}table-striped-color: #{$table-striped-color};
--#{$prefix}table-striped-bg: #{$table-striped-bg};
--#{$prefix}table-active-color: #{$table-active-color};
--#{$prefix}table-active-bg: #{$table-active-bg};
--#{$prefix}table-hover-color: #{$table-hover-color};
--#{$prefix}table-hover-bg: #{$table-hover-bg};
width: 100%;
margin-bottom: $spacer;
vertical-align: $table-cell-vertical-align;
border-color: var(--#{$prefix}table-border-color);
// Target th & td
// We need the child combinator to prevent styles leaking to nested tables which doesn't have a `.table` class.
// We use the universal selectors here to simplify the selector (else we would need 6 different selectors).
// Another advantage is that this generates less code and makes the selector less specific making it easier to override.
// stylelint-disable-next-line selector-max-universal
> :not(caption) > * > * {
padding: $table-cell-padding-y $table-cell-padding-x;
// Following the precept of cascades: https://codepen.io/miriamsuzanne/full/vYNgodb
color: var(--#{$prefix}table-color-state, var(--#{$prefix}table-color-type, var(--#{$prefix}table-color)));
background-color: var(--#{$prefix}table-bg);
border-bottom-width: $table-border-width;
box-shadow: inset 0 0 0 9999px var(--#{$prefix}table-bg-state, var(--#{$prefix}table-bg-type, var(--#{$prefix}table-accent-bg)));
}
> tbody {
vertical-align: inherit;
}
> thead {
vertical-align: bottom;
}
}
.table-group-divider {
border-top: calc(#{$table-border-width} * 2) solid $table-group-separator-color; // stylelint-disable-line function-disallowed-list
}
//
// Change placement of captions with a class
//
.caption-top {
caption-side: top;
}
//
// Condensed table w/ half padding
//
.table-sm {
// stylelint-disable-next-line selector-max-universal
> :not(caption) > * > * {
padding: $table-cell-padding-y-sm $table-cell-padding-x-sm;
}
}
// Border versions
//
// Add or remove borders all around the table and between all the columns.
//
// When borders are added on all sides of the cells, the corners can render odd when
// these borders do not have the same color or if they are semi-transparent.
// Therefor we add top and border bottoms to the `tr`s and left and right borders
// to the `td`s or `th`s
.table-bordered {
> :not(caption) > * {
border-width: $table-border-width 0;
// stylelint-disable-next-line selector-max-universal
> * {
border-width: 0 $table-border-width;
}
}
}
.table-borderless {
// stylelint-disable-next-line selector-max-universal
> :not(caption) > * > * {
border-bottom-width: 0;
}
> :not(:first-child) {
border-top-width: 0;
}
}
// Zebra-striping
//
// Default zebra-stripe styles (alternating gray and transparent backgrounds)
// For rows
.table-striped {
> tbody > tr:nth-of-type(#{$table-striped-order}) > * {
--#{$prefix}table-color-type: var(--#{$prefix}table-striped-color);
--#{$prefix}table-bg-type: var(--#{$prefix}table-striped-bg);
}
}
// For columns
.table-striped-columns {
> :not(caption) > tr > :nth-child(#{$table-striped-columns-order}) {
--#{$prefix}table-color-type: var(--#{$prefix}table-striped-color);
--#{$prefix}table-bg-type: var(--#{$prefix}table-striped-bg);
}
}
// Active table
//
// The `.table-active` class can be added to highlight rows or cells
.table-active {
--#{$prefix}table-color-state: var(--#{$prefix}table-active-color);
--#{$prefix}table-bg-state: var(--#{$prefix}table-active-bg);
}
// Hover effect
//
// Placed here since it has to come after the potential zebra striping
.table-hover {
> tbody > tr:hover > * {
--#{$prefix}table-color-state: var(--#{$prefix}table-hover-color);
--#{$prefix}table-bg-state: var(--#{$prefix}table-hover-bg);
}
}
// Table variants
//
// Table variants set the table cell backgrounds, border colors
// and the colors of the striped, hovered & active tables
@each $color, $value in $table-variants {
@include table-variant($color, $value);
}
// Responsive tables
//
// Generate series of `.table-responsive-*` classes for configuring the screen
// size of where your table will overflow.
@each $breakpoint in map-keys($grid-breakpoints) {
$infix: breakpoint-infix($breakpoint, $grid-breakpoints);
@include media-breakpoint-down($breakpoint) {
.table-responsive#{$infix} {
overflow-x: auto;
-webkit-overflow-scrolling: touch;
}
}
}

View File

@ -0,0 +1,73 @@
.toast {
// scss-docs-start toast-css-vars
--#{$prefix}toast-zindex: #{$zindex-toast};
--#{$prefix}toast-padding-x: #{$toast-padding-x};
--#{$prefix}toast-padding-y: #{$toast-padding-y};
--#{$prefix}toast-spacing: #{$toast-spacing};
--#{$prefix}toast-max-width: #{$toast-max-width};
@include rfs($toast-font-size, --#{$prefix}toast-font-size);
--#{$prefix}toast-color: #{$toast-color};
--#{$prefix}toast-bg: #{$toast-background-color};
--#{$prefix}toast-border-width: #{$toast-border-width};
--#{$prefix}toast-border-color: #{$toast-border-color};
--#{$prefix}toast-border-radius: #{$toast-border-radius};
--#{$prefix}toast-box-shadow: #{$toast-box-shadow};
--#{$prefix}toast-header-color: #{$toast-header-color};
--#{$prefix}toast-header-bg: #{$toast-header-background-color};
--#{$prefix}toast-header-border-color: #{$toast-header-border-color};
// scss-docs-end toast-css-vars
width: var(--#{$prefix}toast-max-width);
max-width: 100%;
@include font-size(var(--#{$prefix}toast-font-size));
color: var(--#{$prefix}toast-color);
pointer-events: auto;
background-color: var(--#{$prefix}toast-bg);
background-clip: padding-box;
border: var(--#{$prefix}toast-border-width) solid var(--#{$prefix}toast-border-color);
box-shadow: var(--#{$prefix}toast-box-shadow);
@include border-radius(var(--#{$prefix}toast-border-radius));
&.showing {
opacity: 0;
}
&:not(.show) {
display: none;
}
}
.toast-container {
--#{$prefix}toast-zindex: #{$zindex-toast};
position: absolute;
z-index: var(--#{$prefix}toast-zindex);
width: max-content;
max-width: 100%;
pointer-events: none;
> :not(:last-child) {
margin-bottom: var(--#{$prefix}toast-spacing);
}
}
.toast-header {
display: flex;
align-items: center;
padding: var(--#{$prefix}toast-padding-y) var(--#{$prefix}toast-padding-x);
color: var(--#{$prefix}toast-header-color);
background-color: var(--#{$prefix}toast-header-bg);
background-clip: padding-box;
border-bottom: var(--#{$prefix}toast-border-width) solid var(--#{$prefix}toast-header-border-color);
@include border-top-radius(calc(var(--#{$prefix}toast-border-radius) - var(--#{$prefix}toast-border-width)));
.btn-close {
margin-right: calc(-.5 * var(--#{$prefix}toast-padding-x)); // stylelint-disable-line function-disallowed-list
margin-left: var(--#{$prefix}toast-padding-x);
}
}
.toast-body {
padding: var(--#{$prefix}toast-padding-x);
word-wrap: break-word;
}

View File

@ -0,0 +1,119 @@
// Base class
.tooltip {
// scss-docs-start tooltip-css-vars
--#{$prefix}tooltip-zindex: #{$zindex-tooltip};
--#{$prefix}tooltip-max-width: #{$tooltip-max-width};
--#{$prefix}tooltip-padding-x: #{$tooltip-padding-x};
--#{$prefix}tooltip-padding-y: #{$tooltip-padding-y};
--#{$prefix}tooltip-margin: #{$tooltip-margin};
@include rfs($tooltip-font-size, --#{$prefix}tooltip-font-size);
--#{$prefix}tooltip-color: #{$tooltip-color};
--#{$prefix}tooltip-bg: #{$tooltip-bg};
--#{$prefix}tooltip-border-radius: #{$tooltip-border-radius};
--#{$prefix}tooltip-opacity: #{$tooltip-opacity};
--#{$prefix}tooltip-arrow-width: #{$tooltip-arrow-width};
--#{$prefix}tooltip-arrow-height: #{$tooltip-arrow-height};
// scss-docs-end tooltip-css-vars
z-index: var(--#{$prefix}tooltip-zindex);
display: block;
margin: var(--#{$prefix}tooltip-margin);
@include deprecate("`$tooltip-margin`", "v5", "v5.x", true);
// Our parent element can be arbitrary since tooltips are by default inserted as a sibling of their target element.
// So reset our font and text properties to avoid inheriting weird values.
@include reset-text();
@include font-size(var(--#{$prefix}tooltip-font-size));
// Allow breaking very long words so they don't overflow the tooltip's bounds
word-wrap: break-word;
opacity: 0;
&.show { opacity: var(--#{$prefix}tooltip-opacity); }
.tooltip-arrow {
display: block;
width: var(--#{$prefix}tooltip-arrow-width);
height: var(--#{$prefix}tooltip-arrow-height);
&::before {
position: absolute;
content: "";
border-color: transparent;
border-style: solid;
}
}
}
.bs-tooltip-top .tooltip-arrow {
bottom: calc(-1 * var(--#{$prefix}tooltip-arrow-height)); // stylelint-disable-line function-disallowed-list
&::before {
top: -1px;
border-width: var(--#{$prefix}tooltip-arrow-height) calc(var(--#{$prefix}tooltip-arrow-width) * .5) 0; // stylelint-disable-line function-disallowed-list
border-top-color: var(--#{$prefix}tooltip-bg);
}
}
/* rtl:begin:ignore */
.bs-tooltip-end .tooltip-arrow {
left: calc(-1 * var(--#{$prefix}tooltip-arrow-height)); // stylelint-disable-line function-disallowed-list
width: var(--#{$prefix}tooltip-arrow-height);
height: var(--#{$prefix}tooltip-arrow-width);
&::before {
right: -1px;
border-width: calc(var(--#{$prefix}tooltip-arrow-width) * .5) var(--#{$prefix}tooltip-arrow-height) calc(var(--#{$prefix}tooltip-arrow-width) * .5) 0; // stylelint-disable-line function-disallowed-list
border-right-color: var(--#{$prefix}tooltip-bg);
}
}
/* rtl:end:ignore */
.bs-tooltip-bottom .tooltip-arrow {
top: calc(-1 * var(--#{$prefix}tooltip-arrow-height)); // stylelint-disable-line function-disallowed-list
&::before {
bottom: -1px;
border-width: 0 calc(var(--#{$prefix}tooltip-arrow-width) * .5) var(--#{$prefix}tooltip-arrow-height); // stylelint-disable-line function-disallowed-list
border-bottom-color: var(--#{$prefix}tooltip-bg);
}
}
/* rtl:begin:ignore */
.bs-tooltip-start .tooltip-arrow {
right: calc(-1 * var(--#{$prefix}tooltip-arrow-height)); // stylelint-disable-line function-disallowed-list
width: var(--#{$prefix}tooltip-arrow-height);
height: var(--#{$prefix}tooltip-arrow-width);
&::before {
left: -1px;
border-width: calc(var(--#{$prefix}tooltip-arrow-width) * .5) 0 calc(var(--#{$prefix}tooltip-arrow-width) * .5) var(--#{$prefix}tooltip-arrow-height); // stylelint-disable-line function-disallowed-list
border-left-color: var(--#{$prefix}tooltip-bg);
}
}
/* rtl:end:ignore */
.bs-tooltip-auto {
&[data-popper-placement^="top"] {
@extend .bs-tooltip-top;
}
&[data-popper-placement^="right"] {
@extend .bs-tooltip-end;
}
&[data-popper-placement^="bottom"] {
@extend .bs-tooltip-bottom;
}
&[data-popper-placement^="left"] {
@extend .bs-tooltip-start;
}
}
// Wrapper for the tooltip content
.tooltip-inner {
max-width: var(--#{$prefix}tooltip-max-width);
padding: var(--#{$prefix}tooltip-padding-y) var(--#{$prefix}tooltip-padding-x);
color: var(--#{$prefix}tooltip-color);
text-align: center;
background-color: var(--#{$prefix}tooltip-bg);
@include border-radius(var(--#{$prefix}tooltip-border-radius));
}

View File

@ -0,0 +1,27 @@
.fade {
@include transition($transition-fade);
&:not(.show) {
opacity: 0;
}
}
// scss-docs-start collapse-classes
.collapse {
&:not(.show) {
display: none;
}
}
.collapsing {
height: 0;
overflow: hidden;
@include transition($transition-collapse);
&.collapse-horizontal {
width: 0;
height: auto;
@include transition($transition-collapse-width);
}
}
// scss-docs-end collapse-classes

View File

@ -0,0 +1,106 @@
//
// Headings
//
.h1 {
@extend h1;
}
.h2 {
@extend h2;
}
.h3 {
@extend h3;
}
.h4 {
@extend h4;
}
.h5 {
@extend h5;
}
.h6 {
@extend h6;
}
.lead {
@include font-size($lead-font-size);
font-weight: $lead-font-weight;
}
// Type display classes
@each $display, $font-size in $display-font-sizes {
.display-#{$display} {
@include font-size($font-size);
font-family: $display-font-family;
font-style: $display-font-style;
font-weight: $display-font-weight;
line-height: $display-line-height;
}
}
//
// Emphasis
//
.small {
@extend small;
}
.mark {
@extend mark;
}
//
// Lists
//
.list-unstyled {
@include list-unstyled();
}
// Inline turns list items into inline-block
.list-inline {
@include list-unstyled();
}
.list-inline-item {
display: inline-block;
&:not(:last-child) {
margin-right: $list-inline-padding;
}
}
//
// Misc
//
// Builds on `abbr`
.initialism {
@include font-size($initialism-font-size);
text-transform: uppercase;
}
// Blockquotes
.blockquote {
margin-bottom: $blockquote-margin-y;
@include font-size($blockquote-font-size);
> :last-child {
margin-bottom: 0;
}
}
.blockquote-footer {
margin-top: -$blockquote-margin-y;
margin-bottom: $blockquote-margin-y;
@include font-size($blockquote-footer-font-size);
color: $blockquote-footer-color;
&::before {
content: "\2014\00A0"; // em dash, nbsp
}
}

Some files were not shown because too many files have changed in this diff Show More