Initial commit: Tonalmine, a Material Design 3 theme for Redmine 7
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@@ -0,0 +1,5 @@
|
|||||||
|
node_modules/
|
||||||
|
screenshots/
|
||||||
|
.DS_Store
|
||||||
|
tools/.cache/
|
||||||
|
docs/plans/
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2026 nonameweb
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
|
|
||||||
|
Bundled third-party assets keep their own licenses:
|
||||||
|
- tonalmine/fonts/ — Roboto, SIL Open Font License 1.1 (see OFL.txt there)
|
||||||
|
- tonalmine/images/icons.svg — Material Symbols, Apache License 2.0
|
||||||
@@ -0,0 +1,70 @@
|
|||||||
|
# Tonalmine
|
||||||
|
|
||||||
|
Material Design 3 theme for Redmine 7.0.
|
||||||
|
|
||||||
|
## Install
|
||||||
|
|
||||||
|
1. Copy the `tonalmine/` folder into `<redmine>/themes/`.
|
||||||
|
2. Restart Redmine (theme assets are compiled at boot).
|
||||||
|
3. Select **Tonalmine** in Administration → Settings → Display → Theme.
|
||||||
|
|
||||||
|
## Development
|
||||||
|
|
||||||
|
Requires Docker.
|
||||||
|
|
||||||
|
```sh
|
||||||
|
cd dev
|
||||||
|
docker compose up -d # Redmine 7.0.1 on http://localhost:3070
|
||||||
|
docker compose exec redmine bin/rails runner /seed/seed.rb # once: demo data, selects the theme
|
||||||
|
docker compose restart redmine # after every CSS change
|
||||||
|
```
|
||||||
|
|
||||||
|
Login: `admin` / `admin`.
|
||||||
|
|
||||||
|
The theme folder is bind-mounted into the container, so edits are picked up on restart.
|
||||||
|
|
||||||
|
### Screenshots
|
||||||
|
|
||||||
|
```sh
|
||||||
|
cd e2e
|
||||||
|
npm install && npx playwright install chromium # once
|
||||||
|
node screenshots.mjs # all pages, light/dark × desktop/mobile → screenshots/
|
||||||
|
node screenshots.mjs issue # only pages whose name contains "issue"
|
||||||
|
node check-form-alignment.mjs # fails if a form label is not level with its field
|
||||||
|
node check-font-sizes.mjs # fails if any text is off the type scale (e.g. core 0.9em leftovers)
|
||||||
|
```
|
||||||
|
|
||||||
|
### Icons
|
||||||
|
|
||||||
|
`tonalmine/images/icons.svg` replaces Redmine's icon sprite with Material Symbols Outlined.
|
||||||
|
It is generated from `tools/icon_map.yml`:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
ruby tools/build_icons.rb
|
||||||
|
```
|
||||||
|
|
||||||
|
The script fails when Redmine's `config/icon_source.yml` (7.0-stable) has icon names that are missing from
|
||||||
|
the map, so run it after every Redmine update.
|
||||||
|
|
||||||
|
### Colors
|
||||||
|
|
||||||
|
Each user picks a mode (Auto / Light / Dark) and a color (Purple, Blue, Teal, Green, Orange) in the
|
||||||
|
**Appearance** section of the profile menu (top right; in the mobile menu at the bottom). The choice is
|
||||||
|
stored per browser (`localStorage`); Auto follows the operating system.
|
||||||
|
|
||||||
|
The color roles are generated from one seed color per palette with `@material/material-color-utilities`
|
||||||
|
(scheme TonalSpot) into `tonalmine/stylesheets/palettes.css`:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
cd tools/palettes
|
||||||
|
npm install # once
|
||||||
|
npm run build # writes palettes.css
|
||||||
|
```
|
||||||
|
|
||||||
|
To add or change a palette, edit `PALETTES` in `tools/palettes/build_palettes.mjs` and in
|
||||||
|
`tonalmine/javascripts/theme.js` (the build fails if they differ), then rebuild. The only other
|
||||||
|
hard-coded colors are the select chevrons `images/arrow-drop-down*.svg` (one per mode).
|
||||||
|
|
||||||
|
## License
|
||||||
|
|
||||||
|
MIT, see `LICENSE`. Roboto (OFL 1.1) and Material Symbols (Apache 2.0) keep their own licenses.
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
services:
|
||||||
|
redmine:
|
||||||
|
image: redmine:7.0.1
|
||||||
|
ports:
|
||||||
|
- "3070:3000"
|
||||||
|
volumes:
|
||||||
|
- redmine-sqlite:/usr/src/redmine/sqlite
|
||||||
|
- redmine-files:/usr/src/redmine/files
|
||||||
|
- ../tonalmine:/usr/src/redmine/themes/tonalmine
|
||||||
|
- .:/seed:ro
|
||||||
|
|
||||||
|
volumes:
|
||||||
|
redmine-sqlite:
|
||||||
|
redmine-files:
|
||||||
@@ -0,0 +1,201 @@
|
|||||||
|
# Demo data for visual theme testing.
|
||||||
|
# Run: docker compose exec redmine bin/rails runner /seed/seed.rb
|
||||||
|
# Idempotent: exits if the demo project already exists. Dates are relative to today
|
||||||
|
# so Gantt, calendar and roadmap always show current data.
|
||||||
|
|
||||||
|
if Project.exists?(identifier: 'apollo')
|
||||||
|
puts 'Demo data already present.'
|
||||||
|
load File.join(__dir__, 'seed_extras.rb')
|
||||||
|
exit
|
||||||
|
end
|
||||||
|
|
||||||
|
srand(42)
|
||||||
|
today = Date.today
|
||||||
|
|
||||||
|
# One transaction: a failure leaves no partial data.
|
||||||
|
ActiveRecord::Base.transaction do
|
||||||
|
Redmine::DefaultData::Loader.load('en') if Redmine::DefaultData::Loader.no_data?
|
||||||
|
|
||||||
|
Setting.ui_theme = 'tonalmine'
|
||||||
|
Setting.text_formatting = 'common_mark'
|
||||||
|
Setting.notified_events = [] # demo data must not send mail
|
||||||
|
|
||||||
|
admin = User.find_by(login: 'admin')
|
||||||
|
admin.update!(must_change_passwd: false)
|
||||||
|
User.current = admin
|
||||||
|
|
||||||
|
people = [
|
||||||
|
%w[jdoe Jane Doe], %w[msmith Max Smith], %w[lnguyen Linh Nguyen], %w[pweber Paula Weber]
|
||||||
|
].map do |login, first, last|
|
||||||
|
User.create!(login: login, firstname: first, lastname: last, mail: "#{login}@example.com",
|
||||||
|
password: 'password123', password_confirmation: 'password123', language: 'en')
|
||||||
|
end
|
||||||
|
team = Group.create!(lastname: 'Developers')
|
||||||
|
team.users << people[0..2]
|
||||||
|
|
||||||
|
manager = Role.find_by!(name: 'Manager')
|
||||||
|
developer = Role.find_by!(name: 'Developer')
|
||||||
|
reporter = Role.find_by!(name: 'Reporter')
|
||||||
|
|
||||||
|
customer_field = IssueCustomField.create!(name: 'Customer', field_format: 'list', possible_values: %w[Acme Globex Initech],
|
||||||
|
is_for_all: true, is_filter: true, tracker_ids: Tracker.ids)
|
||||||
|
review_field = IssueCustomField.create!(name: 'Review date', field_format: 'date', is_for_all: true,
|
||||||
|
is_filter: true, tracker_ids: Tracker.ids)
|
||||||
|
|
||||||
|
modules = Redmine::AccessControl.available_project_modules.map(&:to_s)
|
||||||
|
make_project = lambda do |name, identifier, parent, description|
|
||||||
|
Project.create!(name: name, identifier: identifier, description: description, is_public: true,
|
||||||
|
parent: parent, tracker_ids: Tracker.ids, enabled_module_names: modules)
|
||||||
|
end
|
||||||
|
|
||||||
|
apollo = make_project.('Apollo', 'apollo', nil, "Customer portal relaunch.\n\n**Goal:** ship v2.0 this quarter.")
|
||||||
|
web = make_project.('Apollo Web', 'apollo-web', apollo, 'Frontend of the customer portal.')
|
||||||
|
api = make_project.('Apollo API', 'apollo-api', apollo, 'REST backend.')
|
||||||
|
infra = make_project.('Infrastructure', 'infra', nil, 'Servers, CI and monitoring.')
|
||||||
|
projects = [apollo, web, api, infra]
|
||||||
|
|
||||||
|
projects.each do |p|
|
||||||
|
Member.create!(project: p, principal: admin, role_ids: [manager.id])
|
||||||
|
Member.create!(project: p, principal: people[0], role_ids: [manager.id])
|
||||||
|
Member.create!(project: p, principal: team, role_ids: [developer.id])
|
||||||
|
Member.create!(project: p, principal: people[3], role_ids: [reporter.id])
|
||||||
|
%w[Frontend Backend Docs].each { |c| IssueCategory.create!(project: p, name: c) }
|
||||||
|
end
|
||||||
|
|
||||||
|
v1 = Version.create!(project: apollo, name: '1.0', effective_date: today - 60, sharing: 'descendants')
|
||||||
|
v2 = Version.create!(project: apollo, name: '2.0', effective_date: today + 14, sharing: 'descendants',
|
||||||
|
description: 'Portal relaunch')
|
||||||
|
v3 = Version.create!(project: apollo, name: '2.1', effective_date: today + 60, sharing: 'descendants')
|
||||||
|
vi = Version.create!(project: infra, name: 'Q4 hardening', effective_date: today + 30)
|
||||||
|
|
||||||
|
titles = [
|
||||||
|
'Login page shows wrong error message', 'Add CSV export to reports', 'Upgrade database driver',
|
||||||
|
'Dashboard loads slowly with many widgets', 'Password reset mail not localized', 'Add dark mode',
|
||||||
|
'Refactor session handling', 'Document REST authentication', 'Search ignores umlauts',
|
||||||
|
'Broken layout on small screens', 'Add audit log', 'Rate limit API endpoints', 'Improve onboarding tour',
|
||||||
|
'Fix timezone in due dates', 'Add SSO via OIDC', 'Remove legacy XML endpoints', 'Paginate project list',
|
||||||
|
'Cache avatar images', 'Nightly backup verification', 'Migrate CI to new runners'
|
||||||
|
]
|
||||||
|
open_statuses = IssueStatus.sorted.reject(&:is_closed?)
|
||||||
|
closed_status = IssueStatus.sorted.find(&:is_closed?)
|
||||||
|
priorities = IssuePriority.active.to_a
|
||||||
|
assignees = people + [admin, nil]
|
||||||
|
|
||||||
|
issues = Array.new(60) do |i|
|
||||||
|
project = projects[i % projects.size]
|
||||||
|
version = project == infra ? vi : [v1, v2, v2, v3, nil][i % 5]
|
||||||
|
status = version == v1 || i % 9 == 7 ? closed_status : open_statuses[i % open_statuses.size]
|
||||||
|
start = today + rand(-40..20)
|
||||||
|
suffix = i >= titles.size ? " (#{i / titles.size + 1})" : ''
|
||||||
|
issue = Issue.new(project: project, tracker: project.trackers.to_a[i % project.trackers.size],
|
||||||
|
author: people[i % people.size], subject: titles[i % titles.size] + suffix,
|
||||||
|
description: "Steps to reproduce:\n\n1. Open the page\n2. Click **Save**\n3. See the error\n\n```ruby\nputs 'hello'\n```",
|
||||||
|
priority: priorities[i % priorities.size], assigned_to: assignees[i % assignees.size],
|
||||||
|
category: project.issue_categories.to_a[i % 3], fixed_version: version,
|
||||||
|
start_date: start, due_date: start + rand(3..30), estimated_hours: [2, 4, 8, 16, nil][i % 5],
|
||||||
|
done_ratio: status.is_closed? ? 100 : [0, 10, 30, 50, 80][i % 5], is_private: i == 5)
|
||||||
|
issue.status = status
|
||||||
|
issue.custom_field_values = { customer_field.id => %w[Acme Globex Initech][i % 3], review_field.id => (today + i).to_s }
|
||||||
|
issue.save!
|
||||||
|
issue
|
||||||
|
end
|
||||||
|
|
||||||
|
v1.update!(status: 'closed') # closed versions reject new issues, so close it afterwards
|
||||||
|
|
||||||
|
# Subtasks and relations (same project: cross-project relations are off by default)
|
||||||
|
showcase = issues[12] # open apollo issue: gets subtasks, attachments and watchers
|
||||||
|
[issues[24], issues[28]].each { |child| child.reload.update!(parent_issue_id: showcase.id) }
|
||||||
|
IssueRelation.create!(issue_from: showcase, issue_to: issues[32], relation_type: 'relates')
|
||||||
|
IssueRelation.create!(issue_from: issues[9], issue_to: issues[13], relation_type: 'blocks')
|
||||||
|
IssueRelation.create!(issue_from: issues[14], issue_to: issues[18], relation_type: 'precedes')
|
||||||
|
|
||||||
|
# Journals: notes and attribute changes
|
||||||
|
issues.first(15).each_with_index do |issue, i|
|
||||||
|
issue.reload.init_journal(people[i % 3], "Looked into this. #{i.even? ? 'Needs a decision from **product**.' : 'Fix is in review.'}")
|
||||||
|
issue.done_ratio = [issue.done_ratio.to_i + 10, 100].min unless issue.closed?
|
||||||
|
issue.save!
|
||||||
|
end
|
||||||
|
showcase.watcher_users << people[1..2]
|
||||||
|
|
||||||
|
# Attachments
|
||||||
|
# 160x90 solid-color RGB PNG, built by hand so the seed needs no image file
|
||||||
|
png_chunk = ->(type, data) { [data.bytesize].pack('N') + type + data + [Zlib.crc32(type + data)].pack('N') }
|
||||||
|
png = "\x89PNG\r\n\x1a\n".b + png_chunk.('IHDR', [160, 90, 8, 2, 0, 0, 0].pack('NNC5')) +
|
||||||
|
png_chunk.('IDAT', Zlib::Deflate.deflate(([0] + [103, 80, 164] * 160).pack('C*') * 90)) + png_chunk.('IEND', '')
|
||||||
|
[['screenshot.png', png, 'image/png'], ['notes.txt', "Some notes\n", 'text/plain']].each do |name, data, type|
|
||||||
|
Attachment.create!(file: StringIO.new(data), author: admin, filename: name, content_type: type, container: showcase)
|
||||||
|
end
|
||||||
|
|
||||||
|
# Wiki
|
||||||
|
wiki = apollo.reload.wiki
|
||||||
|
start_text = <<~MD
|
||||||
|
# Apollo wiki
|
||||||
|
|
||||||
|
{{toc}}
|
||||||
|
|
||||||
|
## Overview
|
||||||
|
|
||||||
|
The customer portal lets clients see **tickets**, *invoices* and `usage`.
|
||||||
|
|
||||||
|
> Keep this page short. Details go into child pages.
|
||||||
|
|
||||||
|
## Team
|
||||||
|
|
||||||
|
| Name | Role | Since |
|
||||||
|
|------|------|-------|
|
||||||
|
| Jane Doe | Product owner | 2024 |
|
||||||
|
| Max Smith | Backend | 2025 |
|
||||||
|
| Linh Nguyen | Frontend | 2026 |
|
||||||
|
|
||||||
|
## Setup
|
||||||
|
|
||||||
|
```ruby
|
||||||
|
class Portal
|
||||||
|
def initialize(user)
|
||||||
|
@user = user # current user
|
||||||
|
end
|
||||||
|
end
|
||||||
|
```
|
||||||
|
|
||||||
|
- [ ] Install dependencies
|
||||||
|
- [x] Configure database
|
||||||
|
|
||||||
|
See [[Architecture]] and issue #13.
|
||||||
|
MD
|
||||||
|
page = WikiPage.new(wiki: wiki, title: wiki.start_page)
|
||||||
|
page.content = WikiContent.new(page: page, text: start_text, author: admin)
|
||||||
|
page.save!
|
||||||
|
child = WikiPage.new(wiki: wiki, title: 'Architecture', parent: page)
|
||||||
|
child.content = WikiContent.new(page: child, text: "# Architecture\n\nThree tiers: web, API, database.", author: people[1])
|
||||||
|
child.save!
|
||||||
|
|
||||||
|
# News, forum, documents
|
||||||
|
news = News.create!(project: apollo, title: 'Version 2.0 beta available', summary: 'Try the new portal',
|
||||||
|
description: 'The beta is live on staging. Please report issues.', author: people[0])
|
||||||
|
Comment.create!(commented: news, author: people[1], content: 'Great work!')
|
||||||
|
|
||||||
|
board = Board.create!(project: apollo, name: 'General', description: 'General discussion')
|
||||||
|
topic = Message.create!(board: board, subject: 'Release planning', content: 'When do we freeze 2.0?', author: people[0])
|
||||||
|
Message.create!(board: board, parent: topic, subject: 'RE: Release planning', content: 'Next Friday.', author: people[1])
|
||||||
|
|
||||||
|
Document.create!(project: apollo, title: 'Requirements', description: 'Signed-off requirements.',
|
||||||
|
category: DocumentCategory.first)
|
||||||
|
|
||||||
|
# Time entries over the last 30 days
|
||||||
|
activities = TimeEntryActivity.active.to_a
|
||||||
|
issues.first(20).each_with_index do |issue, i|
|
||||||
|
user = people[i % 3]
|
||||||
|
TimeEntry.create!(project: issue.project, issue: issue, user: user, author: user, hours: [0.5, 1, 2, 3.5][i % 4],
|
||||||
|
spent_on: today - (i % 30), activity: activities[i % activities.size], comments: 'Work on issue')
|
||||||
|
end
|
||||||
|
|
||||||
|
# Saved public query: grouped, with totals
|
||||||
|
IssueQuery.create!(name: 'Open by assignee', user: admin, visibility: Query::VISIBILITY_PUBLIC,
|
||||||
|
group_by: 'assigned_to', totalable_names: %w[estimated_hours spent_hours],
|
||||||
|
column_names: %i[tracker status priority subject assigned_to due_date done_ratio])
|
||||||
|
end
|
||||||
|
|
||||||
|
puts "Seeded #{Project.count} projects, #{Issue.count} issues, #{User.count} users."
|
||||||
|
|
||||||
|
load File.join(__dir__, 'spread_activity.rb')
|
||||||
|
load File.join(__dir__, 'seed_extras.rb')
|
||||||
@@ -0,0 +1,67 @@
|
|||||||
|
# Extra demo data for pages the base seed does not cover: repository, wiki diff, description diff.
|
||||||
|
# Loaded by seed.rb. Each block has its own guard, so rerunning the seed adds only what is missing.
|
||||||
|
|
||||||
|
require 'fileutils'
|
||||||
|
require 'open3'
|
||||||
|
require 'tmpdir'
|
||||||
|
|
||||||
|
apollo = Project.find_by!(identifier: 'apollo')
|
||||||
|
admin = User.find_by!(login: 'admin')
|
||||||
|
User.current = admin
|
||||||
|
|
||||||
|
# Git repository: built in a work tree, then cloned bare into the files volume (persists restarts).
|
||||||
|
unless apollo.repository
|
||||||
|
bare = '/usr/src/redmine/files/demo-repo.git'
|
||||||
|
work = Dir.mktmpdir
|
||||||
|
git = lambda do |*args|
|
||||||
|
out, status = Open3.capture2e('git', '-C', work, *args)
|
||||||
|
raise "git #{args.join(' ')} failed: #{out}" unless status.success?
|
||||||
|
end
|
||||||
|
env = { 'user.name' => 'Jane Doe', 'user.email' => 'jdoe@example.com' }.flat_map { |k, v| ['-c', "#{k}=#{v}"] }
|
||||||
|
|
||||||
|
git.('init', '-q', '-b', 'main')
|
||||||
|
File.write(File.join(work, 'README.md'), "# Apollo\n\nCustomer portal.\n")
|
||||||
|
FileUtils.mkdir_p(File.join(work, 'lib'))
|
||||||
|
File.write(File.join(work, 'lib/portal.rb'), "class Portal\n def initialize(user)\n @user = user\n end\nend\n")
|
||||||
|
git.(*env, 'add', '.')
|
||||||
|
git.(*env, 'commit', '-q', '-m', 'Initial import')
|
||||||
|
File.write(File.join(work, 'lib/portal.rb'),
|
||||||
|
"class Portal\n def initialize(user, locale = :en)\n @user = user\n @locale = locale\n end\n\n def greeting\n \"Hello, \#{@user}\"\n end\nend\n")
|
||||||
|
git.(*env, 'commit', '-q', '-am', 'Add locale and greeting (refs #13)')
|
||||||
|
File.write(File.join(work, 'README.md'), "# Apollo\n\nCustomer portal.\n\n## Setup\n\nRun `bin/setup`.\n")
|
||||||
|
git.(*env, 'commit', '-q', '-am', 'Document setup')
|
||||||
|
|
||||||
|
FileUtils.rm_rf(bare)
|
||||||
|
out, status = Open3.capture2e('git', 'clone', '-q', '--bare', work, bare)
|
||||||
|
raise "git clone failed: #{out}" unless status.success?
|
||||||
|
FileUtils.rm_rf(work)
|
||||||
|
FileUtils.chown_R('redmine', 'redmine', bare) if Process.uid.zero? # the app runs as redmine
|
||||||
|
|
||||||
|
apollo.enabled_module_names = apollo.enabled_module_names | ['repository']
|
||||||
|
repo = Repository::Git.create!(project: apollo, url: bare, identifier: 'portal', is_default: true)
|
||||||
|
repo.fetch_changesets
|
||||||
|
end
|
||||||
|
|
||||||
|
# Second wiki version, so history and diff have something to compare
|
||||||
|
start = apollo.wiki.find_page(apollo.wiki.start_page)
|
||||||
|
if start && start.content.version == 1
|
||||||
|
start.content.text = start.content.text.sub('Keep this page short.', 'Keep this page short and current.') +
|
||||||
|
"\n## Release\n\nVersion 2.0 ships at the end of the sprint.\n"
|
||||||
|
start.content.author = User.find_by!(login: 'jdoe')
|
||||||
|
start.content.comments = 'Add release section'
|
||||||
|
start.content.save!
|
||||||
|
end
|
||||||
|
|
||||||
|
# Description change on the showcase issue, so the journal has a "diff" link
|
||||||
|
showcase = Issue.find(13) # the issue the screenshot checklist shows
|
||||||
|
unless showcase.journals.joins(:details).exists?(journal_details: { prop_key: 'description' })
|
||||||
|
showcase.init_journal(User.find_by!(login: 'msmith'))
|
||||||
|
showcase.description = "#{showcase.description}\n\nAlso happens in the API search endpoint."
|
||||||
|
showcase.save!
|
||||||
|
end
|
||||||
|
|
||||||
|
# Second forum, so the forum index lists boards instead of redirecting to the only one
|
||||||
|
Board.create!(project: apollo, name: 'Support', description: 'Questions from customers') if apollo.boards.count < 2
|
||||||
|
|
||||||
|
puts "Extras: #{Repository.count} repositories, wiki v#{start&.content&.reload&.version}, " \
|
||||||
|
"#{JournalDetail.where(prop_key: 'description').count} description diffs, #{apollo.boards.count} forums."
|
||||||
@@ -0,0 +1,60 @@
|
|||||||
|
# Spreads demo record timestamps over the last two weeks (working hours), so the activity page,
|
||||||
|
# "updated" columns and history show different days and times. Deterministic (based on ids),
|
||||||
|
# safe to run again. Called by seed.rb; can also run alone:
|
||||||
|
# docker compose exec redmine bin/rails runner /seed/spread_activity.rb
|
||||||
|
|
||||||
|
now = Time.current
|
||||||
|
today = Date.current
|
||||||
|
DAYS = 14
|
||||||
|
|
||||||
|
# Day `days_ago` at a working-hour time derived from `n`
|
||||||
|
at = lambda do |days_ago, n|
|
||||||
|
(today - days_ago).in_time_zone.change(hour: 8 + (n * 7) % 10, min: (n * 13) % 60)
|
||||||
|
end
|
||||||
|
not_future = ->(t, n) { t < now ? t : now - (n % 90 + 5).minutes }
|
||||||
|
|
||||||
|
ActiveRecord::Base.transaction do
|
||||||
|
Issue.order(:id).each_with_index do |issue, i|
|
||||||
|
created = at.(DAYS - 1 - (i % DAYS), i)
|
||||||
|
last = created
|
||||||
|
issue.journals.order(:id).each do |journal|
|
||||||
|
t = not_future.(created + (1 + journal.id % 3).days + (journal.id * 17 % 300).minutes, journal.id)
|
||||||
|
journal.update_columns(created_on: t, updated_on: t)
|
||||||
|
last = [last, t].max
|
||||||
|
end
|
||||||
|
closed = issue.closed? ? [last, created + 1.day].max : nil
|
||||||
|
issue.update_columns(created_on: created, updated_on: last, closed_on: closed && not_future.(closed, issue.id))
|
||||||
|
end
|
||||||
|
|
||||||
|
TimeEntry.find_each do |entry|
|
||||||
|
t = not_future.(entry.spent_on.in_time_zone.change(hour: 17, min: entry.id * 7 % 60), entry.id)
|
||||||
|
entry.update_columns(created_on: t, updated_on: t)
|
||||||
|
end
|
||||||
|
|
||||||
|
Attachment.find_each { |a| a.update_columns(created_on: not_future.(a.container.try(:created_on).to_time + 2.hours, a.id)) if a.container }
|
||||||
|
|
||||||
|
WikiContentVersion.order(:id).each_with_index do |version, i|
|
||||||
|
t = at.(9 - i * 2, version.id)
|
||||||
|
version.update_columns(updated_on: t)
|
||||||
|
version.page.content.update_columns(updated_on: t) if version.version == version.page.content.version
|
||||||
|
end
|
||||||
|
WikiPage.find_each { |page| page.update_columns(created_on: page.content.versions.minimum(:updated_on) || page.created_on) }
|
||||||
|
|
||||||
|
News.find_each do |news|
|
||||||
|
news.update_columns(created_on: at.(6, news.id))
|
||||||
|
news.comments.each_with_index { |c, i| c.update_columns(created_on: at.(5 - i, c.id), updated_on: at.(5 - i, c.id)) }
|
||||||
|
end
|
||||||
|
|
||||||
|
Message.where(parent_id: nil).find_each do |topic|
|
||||||
|
topic.update_columns(created_on: at.(4, topic.id), updated_on: at.(4, topic.id))
|
||||||
|
topic.children.each_with_index do |reply, i|
|
||||||
|
t = not_future.(at.(3 - i, reply.id), reply.id)
|
||||||
|
reply.update_columns(created_on: t, updated_on: t)
|
||||||
|
topic.update_columns(updated_on: t)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
Document.find_each { |d| d.update_columns(created_on: at.(8, d.id)) }
|
||||||
|
end
|
||||||
|
|
||||||
|
puts "Spread activity over the last #{DAYS} days."
|
||||||
@@ -0,0 +1,94 @@
|
|||||||
|
// Reports visible elements that still carry core Redmine shapes the theme should have replaced:
|
||||||
|
// 1-3px corners (core uses 3px, M3 uses 4/8/12/16/28px or full), core's grey box shadow
|
||||||
|
// (rgba of --oc-gray-9, theme shadows never use it), square boxes outlined on all four sides
|
||||||
|
// (core's card style, e.g. the old .mypage-box), and dashed or dotted borders.
|
||||||
|
// Checks desktop and mobile, because core's responsive.css brings its own shapes. Exits 1 on any hit.
|
||||||
|
// Usage: node check-core-leaks.mjs [--verbose]
|
||||||
|
import { chromium } from 'playwright';
|
||||||
|
|
||||||
|
const BASE = process.env.REDMINE_URL ?? 'http://127.0.0.1:3070';
|
||||||
|
const pages = [
|
||||||
|
'/my/page', '/projects', '/projects?display_type=list', '/projects/apollo', '/projects/apollo/issues', '/issues/13',
|
||||||
|
'/projects/apollo/issues/new', '/issues/13/edit', '/issues/bulk_edit?ids[]=13&ids[]=17', '/projects/apollo/issues/gantt',
|
||||||
|
'/projects/apollo/issues/calendar', '/projects/apollo/roadmap', '/versions/2', '/projects/apollo/activity',
|
||||||
|
'/projects/apollo/wiki', '/projects/apollo/wiki/Wiki/edit', '/news/1', '/boards/1/topics/1', '/projects/apollo/documents',
|
||||||
|
'/projects/apollo/files', '/projects/apollo/time_entries', '/projects/apollo/time_entries/report?criteria[]=user&columns=month',
|
||||||
|
'/search?q=login', '/my/account', '/admin', '/settings', '/users', '/roles/permissions',
|
||||||
|
'/workflows/edit?role_id=3&tracker_id=1', '/workflows/permissions?role_id=3&tracker_id=1',
|
||||||
|
'/projects/apollo/repository', '/projects/apollo/repository/portal/revisions', '/projects/apollo/repository/portal/entry/lib/portal.rb',
|
||||||
|
'/projects/apollo/repository/portal/annotate/lib/portal.rb', '/projects/apollo/repository/portal/revisions/main/diff',
|
||||||
|
'/projects/apollo/wiki/Wiki/history', '/projects/apollo/wiki/Wiki/diff?version=2&version_from=1', '/projects/apollo/settings',
|
||||||
|
'/projects/apollo/settings/members', '/projects/apollo/settings/versions', '/projects/apollo/settings/repositories', '/trackers',
|
||||||
|
'/issue_statuses', '/custom_fields', '/custom_fields/1/edit', '/enumerations', '/admin/info', '/admin/plugins',
|
||||||
|
'/projects/apollo/boards',
|
||||||
|
];
|
||||||
|
// Elements whose core shape is intended. Each entry needs a reason.
|
||||||
|
const ALLOW = [
|
||||||
|
'div.gantt_hdr', // Gantt chart header cells form the chart grid
|
||||||
|
];
|
||||||
|
const viewports = {
|
||||||
|
desktop: { viewport: { width: 1440, height: 900 } },
|
||||||
|
mobile: { viewport: { width: 390, height: 844 }, isMobile: true, hasTouch: true },
|
||||||
|
};
|
||||||
|
|
||||||
|
const browser = await chromium.launch();
|
||||||
|
const offenders = new Map(); // "viewport selector reason" -> pages
|
||||||
|
for (const [vpName, opts] of Object.entries(viewports)) {
|
||||||
|
const page = await browser.newPage(opts);
|
||||||
|
await page.goto(`${BASE}/login`);
|
||||||
|
await page.fill('#username', 'admin');
|
||||||
|
await page.fill('#password', 'admin');
|
||||||
|
await page.click('#login-submit');
|
||||||
|
await page.waitForURL((url) => !url.pathname.startsWith('/login'));
|
||||||
|
|
||||||
|
for (const path of pages) {
|
||||||
|
await page.goto(`${BASE}${path}`, { waitUntil: 'networkidle' });
|
||||||
|
const found = await page.evaluate((allow) => {
|
||||||
|
const describe = (el) => {
|
||||||
|
const parts = [];
|
||||||
|
for (let e = el; e && e !== document.body && parts.length < 3; e = e.parentElement) {
|
||||||
|
parts.unshift(e.id ? `#${e.id}` : e.tagName.toLowerCase() + [...e.classList].slice(0, 2).map((c) => `.${c}`).join(''));
|
||||||
|
if (e.id) break;
|
||||||
|
}
|
||||||
|
return parts.join(' > ');
|
||||||
|
};
|
||||||
|
const opaque = (color) => !/^rgba\(.*,\s*0\)$/.test(color) && color !== 'transparent';
|
||||||
|
const sides = ['Top', 'Right', 'Bottom', 'Left'];
|
||||||
|
const out = [];
|
||||||
|
for (const el of document.querySelectorAll('body *:not(script):not(style):not(svg *)')) {
|
||||||
|
const r = el.getBoundingClientRect();
|
||||||
|
if (!r.width || !r.height || allow.some((s) => el.matches(s))) continue;
|
||||||
|
const cs = getComputedStyle(el);
|
||||||
|
if (cs.visibility === 'hidden' || cs.display === 'none') continue;
|
||||||
|
const borders = sides.filter((s) => parseFloat(cs[`border${s}Width`]) > 0 && cs[`border${s}Style`] !== 'none'
|
||||||
|
&& opaque(cs[`border${s}Color`]));
|
||||||
|
const radii = ['TopLeft', 'TopRight', 'BottomRight', 'BottomLeft'].map((c) => parseFloat(cs[`border${c}Radius`]));
|
||||||
|
if (radii.some((x) => x >= 1 && x <= 3) && (borders.length || opaque(cs.backgroundColor))) {
|
||||||
|
out.push([describe(el), `${Math.max(...radii)}px corner`]);
|
||||||
|
}
|
||||||
|
if (cs.boxShadow.includes('rgba(33, 37, 41')) out.push([describe(el), 'core shadow']);
|
||||||
|
if (borders.length === 4 && radii.every((x) => x === 0) && r.width >= 100 && r.height >= 32
|
||||||
|
&& !['TABLE', 'TD', 'TH', 'TR'].includes(el.tagName)) {
|
||||||
|
out.push([describe(el), 'square outlined box']);
|
||||||
|
}
|
||||||
|
const dashed = borders.find((s) => ['dashed', 'dotted'].includes(cs[`border${s}Style`]));
|
||||||
|
if (dashed) out.push([describe(el), `${cs[`border${dashed}Style`]} border`]);
|
||||||
|
}
|
||||||
|
return out;
|
||||||
|
}, ALLOW);
|
||||||
|
for (const [sel, reason] of found) {
|
||||||
|
const key = `${vpName.padEnd(7)} ${sel} (${reason})`;
|
||||||
|
if (!offenders.has(key)) offenders.set(key, new Set());
|
||||||
|
offenders.get(key).add(path);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
await page.close();
|
||||||
|
}
|
||||||
|
await browser.close();
|
||||||
|
|
||||||
|
const rows = [...offenders].sort(([a], [b]) => a.localeCompare(b));
|
||||||
|
for (const [key, where] of rows) {
|
||||||
|
console.log(`${key} ${process.argv.includes('--verbose') ? [...where].join(', ') : `${where.size} page${where.size > 1 ? 's' : ''}`}`);
|
||||||
|
}
|
||||||
|
console.log(rows.length ? `\n${rows.length} core shapes left` : 'No core shapes left.');
|
||||||
|
process.exit(rows.length ? 1 : 0);
|
||||||
@@ -0,0 +1,67 @@
|
|||||||
|
// Reports visible text whose computed font size is off the theme's type scale.
|
||||||
|
// Core Redmine uses relative sizes (0.8em, 90%, …) that compound when nested; the theme should
|
||||||
|
// leave only M3 scale sizes. Exits 1 if anything is off-scale.
|
||||||
|
// Usage: node check-font-sizes.mjs [--verbose]
|
||||||
|
import { chromium } from 'playwright';
|
||||||
|
|
||||||
|
const BASE = process.env.REDMINE_URL ?? 'http://127.0.0.1:3070';
|
||||||
|
// M3 type scale in px (label-small 11 … display-large 57)
|
||||||
|
const SCALE = [11, 12, 14, 16, 22, 24, 28, 32, 36, 45, 57];
|
||||||
|
const pages = [
|
||||||
|
'/my/page', '/projects', '/projects/apollo', '/projects/apollo/issues', '/issues/13', '/projects/apollo/issues/new',
|
||||||
|
'/projects/apollo/roadmap', '/versions/2', '/projects/apollo/activity', '/projects/apollo/wiki', '/news/1',
|
||||||
|
'/boards/1/topics/1', '/projects/apollo/documents', '/projects/apollo/files', '/projects/apollo/time_entries',
|
||||||
|
'/projects/apollo/time_entries/report?criteria[]=user&columns=month', '/search?q=login', '/my/account',
|
||||||
|
'/admin', '/settings', '/users', '/roles/permissions', '/projects/apollo/issues/calendar',
|
||||||
|
'/projects/apollo/repository', '/projects/apollo/repository/portal/revisions', '/projects/apollo/repository/portal/entry/lib/portal.rb',
|
||||||
|
'/projects/apollo/repository/portal/annotate/lib/portal.rb', '/projects/apollo/repository/portal/revisions/main/diff',
|
||||||
|
'/projects/apollo/wiki/Wiki/history', '/projects/apollo/wiki/Wiki/diff?version=2&version_from=1', '/projects/apollo/settings',
|
||||||
|
'/projects/apollo/settings/members', '/projects/apollo/settings/versions', '/projects/apollo/settings/repositories', '/trackers',
|
||||||
|
'/issue_statuses', '/custom_fields', '/custom_fields/1/edit', '/enumerations', '/admin/info', '/admin/plugins',
|
||||||
|
'/workflows/permissions?role_id=3&tracker_id=1', '/projects/apollo/boards',
|
||||||
|
];
|
||||||
|
|
||||||
|
const browser = await chromium.launch();
|
||||||
|
const page = await browser.newPage({ viewport: { width: 1440, height: 900 } });
|
||||||
|
await page.goto(`${BASE}/login`);
|
||||||
|
await page.fill('#username', 'admin');
|
||||||
|
await page.fill('#password', 'admin');
|
||||||
|
await page.click('#login-submit');
|
||||||
|
await page.waitForURL((url) => !url.pathname.startsWith('/login'));
|
||||||
|
|
||||||
|
const offenders = new Map(); // "selector @ size" -> pages
|
||||||
|
for (const path of pages) {
|
||||||
|
await page.goto(`${BASE}${path}`, { waitUntil: 'networkidle' });
|
||||||
|
const found = await page.evaluate((scale) => {
|
||||||
|
const out = [];
|
||||||
|
const describe = (el) => {
|
||||||
|
const parts = [];
|
||||||
|
for (let e = el; e && e !== document.body && parts.length < 3; e = e.parentElement) {
|
||||||
|
parts.unshift(e.id ? `#${e.id}` : e.tagName.toLowerCase() + [...e.classList].slice(0, 2).map((c) => `.${c}`).join(''));
|
||||||
|
if (e.id) break;
|
||||||
|
}
|
||||||
|
return parts.join(' > ');
|
||||||
|
};
|
||||||
|
for (const el of document.querySelectorAll('body *:not(script):not(style):not(svg *)')) {
|
||||||
|
if (el.closest('table.gantt-table, .avatar')) continue; // Gantt is zoomed; avatar initials are graphics
|
||||||
|
const hasText = [...el.childNodes].some((n) => n.nodeType === 3 && n.textContent.trim());
|
||||||
|
if (!hasText || !el.offsetParent) continue;
|
||||||
|
const size = parseFloat(getComputedStyle(el).fontSize);
|
||||||
|
if (!scale.some((s) => Math.abs(s - size) < 0.3)) out.push([describe(el), Math.round(size * 10) / 10]);
|
||||||
|
}
|
||||||
|
return out;
|
||||||
|
}, SCALE);
|
||||||
|
for (const [sel, size] of found) {
|
||||||
|
const key = `${sel} @ ${size}px`;
|
||||||
|
if (!offenders.has(key)) offenders.set(key, new Set());
|
||||||
|
offenders.get(key).add(path);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
await browser.close();
|
||||||
|
|
||||||
|
const rows = [...offenders].sort((a, b) => parseFloat(a[0].split('@ ')[1]) - parseFloat(b[0].split('@ ')[1]));
|
||||||
|
for (const [key, where] of rows) {
|
||||||
|
console.log(`${key} (${where.size} page${where.size > 1 ? 's' : ''}${process.argv.includes('--verbose') ? ': ' + [...where].join(', ') : ''})`);
|
||||||
|
}
|
||||||
|
console.log(rows.length ? `\n${rows.length} off-scale text styles` : 'All text on the type scale.');
|
||||||
|
process.exit(rows.length ? 1 : 0);
|
||||||
@@ -0,0 +1,48 @@
|
|||||||
|
// Checks that each form label (.tabular forms, query filters) lines up with the field next to it.
|
||||||
|
// Usage: node check-form-alignment.mjs (exits 1 if any row is off by more than 2px)
|
||||||
|
import { chromium } from 'playwright';
|
||||||
|
|
||||||
|
const BASE = process.env.REDMINE_URL ?? 'http://127.0.0.1:3070';
|
||||||
|
const pages = [
|
||||||
|
'/projects?display_type=list', '/projects/apollo/issues', '/projects/apollo/time_entries', '/projects/apollo/issues/new', '/issues/13/edit', '/issues/bulk_edit?ids[]=13&ids[]=17',
|
||||||
|
'/projects/apollo/time_entries/new', '/settings', '/my/account', '/users/5/edit',
|
||||||
|
'/projects/apollo/settings', '/custom_fields/1/edit', '/projects/apollo/wiki/Wiki/edit',
|
||||||
|
];
|
||||||
|
|
||||||
|
const browser = await chromium.launch();
|
||||||
|
const page = await browser.newPage({ viewport: { width: 1440, height: 900 } });
|
||||||
|
await page.goto(`${BASE}/login`);
|
||||||
|
await page.fill('#username', 'admin');
|
||||||
|
await page.fill('#password', 'admin');
|
||||||
|
await page.click('#login-submit');
|
||||||
|
await page.waitForURL((url) => !url.pathname.startsWith('/login'));
|
||||||
|
|
||||||
|
let failures = 0;
|
||||||
|
for (const path of pages) {
|
||||||
|
await page.goto(`${BASE}${path}`, { waitUntil: 'networkidle' });
|
||||||
|
const rows = await page.evaluate(() => [
|
||||||
|
// Query filters: label text vs. operator select
|
||||||
|
...[...document.querySelectorAll('#filters-table .filter')].flatMap((row) => {
|
||||||
|
const label = row.querySelector('.field label'), control = row.querySelector('.operator select');
|
||||||
|
if (!label || !control || !control.offsetParent) return [];
|
||||||
|
const l = label.getBoundingClientRect(), c = control.getBoundingClientRect();
|
||||||
|
return [{ label: `filter ${label.textContent.trim().slice(0, 22)}`, offset: Math.round(l.top + l.height / 2 - (c.top + c.height / 2)) }];
|
||||||
|
}),
|
||||||
|
...[...document.querySelectorAll('.tabular p')].flatMap((row) => {
|
||||||
|
const label = row.querySelector(':scope > label:not(.floating):not(.block):not(.inline):not(.no-css)');
|
||||||
|
const control = row.querySelector(':scope > input:not([type=hidden]), :scope > select, :scope > span > input:not([type=hidden]), :scope > span > select');
|
||||||
|
if (!label || !control || !label.offsetParent || !control.offsetParent) return [];
|
||||||
|
const style = getComputedStyle(label);
|
||||||
|
const labelBox = label.getBoundingClientRect();
|
||||||
|
const controlBox = control.getBoundingClientRect();
|
||||||
|
const labelMiddle = labelBox.top + parseFloat(style.paddingTop) + parseFloat(style.lineHeight) / 2;
|
||||||
|
return [{ label: label.textContent.trim().slice(0, 30), offset: Math.round(labelMiddle - (controlBox.top + controlBox.height / 2)) }];
|
||||||
|
}),
|
||||||
|
]);
|
||||||
|
const bad = rows.filter((r) => Math.abs(r.offset) > 2);
|
||||||
|
failures += bad.length;
|
||||||
|
console.log(`${bad.length ? 'FAIL' : 'ok '} ${path} (${rows.length} rows)${bad.map((r) => `\n ${r.label}: ${r.offset}px`).join('')}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
await browser.close();
|
||||||
|
process.exit(failures ? 1 : 0);
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
Subject,Tracker,Status,Priority,Assignee,Due date
|
||||||
|
Import check,Bug,New,Normal,,2026-12-01
|
||||||
|
Second row,Feature,New,High,,
|
||||||
|
@@ -0,0 +1,40 @@
|
|||||||
|
{
|
||||||
|
"name": "tonalmine-e2e",
|
||||||
|
"lockfileVersion": 3,
|
||||||
|
"requires": true,
|
||||||
|
"packages": {
|
||||||
|
"": {
|
||||||
|
"name": "tonalmine-e2e",
|
||||||
|
"dependencies": {
|
||||||
|
"playwright": "^1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/playwright": {
|
||||||
|
"version": "1.63.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/playwright/-/playwright-1.63.0.tgz",
|
||||||
|
"integrity": "sha512-+7ziBLidS4NaNCdt57SUDT+wYmmd5fmiQejUic/kb+YsYSCPyOOE9sebzMjNmQrsnNpDJqd4WHvV/8lfKfUDUg==",
|
||||||
|
"license": "Apache-2.0",
|
||||||
|
"dependencies": {
|
||||||
|
"playwright-core": "1.63.0"
|
||||||
|
},
|
||||||
|
"bin": {
|
||||||
|
"playwright": "cli.js"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=20"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/playwright-core": {
|
||||||
|
"version": "1.63.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.63.0.tgz",
|
||||||
|
"integrity": "sha512-rYCsBF/M5HjUch52bbtVONEFjv6Xu8sm8h72dNlR5bzIE1fvC/bxgspzkjSfU+MweEMmPM8KJebG6nnyxo5mCg==",
|
||||||
|
"license": "Apache-2.0",
|
||||||
|
"bin": {
|
||||||
|
"playwright-core": "cli.js"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=20"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
{
|
||||||
|
"name": "tonalmine-e2e",
|
||||||
|
"private": true,
|
||||||
|
"type": "module",
|
||||||
|
"scripts": {
|
||||||
|
"screenshots": "node screenshots.mjs"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"playwright": "^1"
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,143 @@
|
|||||||
|
// Captures the page checklist in light/dark × desktop/mobile into ../screenshots/.
|
||||||
|
// Usage: node screenshots.mjs [filter] e.g. `node screenshots.mjs issue` for pages whose name contains "issue".
|
||||||
|
// Needs the dev server with seed data (see README).
|
||||||
|
import { chromium } from 'playwright';
|
||||||
|
import { mkdir } from 'node:fs/promises';
|
||||||
|
|
||||||
|
const BASE = process.env.REDMINE_URL ?? 'http://127.0.0.1:3070';
|
||||||
|
const OUT = new URL('../screenshots/', import.meta.url).pathname;
|
||||||
|
const filter = process.argv[2] ?? '';
|
||||||
|
|
||||||
|
const pages = [
|
||||||
|
['my-page', '/my/page'],
|
||||||
|
['projects-board', '/projects?display_type=board'],
|
||||||
|
['projects-list', '/projects?display_type=list'],
|
||||||
|
['project-overview', '/projects/apollo'],
|
||||||
|
['issues-grouped', '/projects/apollo/issues?set_filter=1&f[]=status_id&op[status_id]=*&group_by=status&t[]=estimated_hours&t[]=spent_hours'],
|
||||||
|
['issue-show', '/issues/13'],
|
||||||
|
['issue-new', '/projects/apollo/issues/new'],
|
||||||
|
['issue-edit', '/issues/13/edit'],
|
||||||
|
['issue-bulk-edit', '/issues/bulk_edit?ids[]=13&ids[]=17'],
|
||||||
|
['gantt', '/projects/apollo/issues/gantt'],
|
||||||
|
['calendar', '/projects/apollo/issues/calendar'],
|
||||||
|
['roadmap', '/projects/apollo/roadmap'],
|
||||||
|
['version', '/versions/2'],
|
||||||
|
['activity', '/projects/apollo/activity'],
|
||||||
|
['wiki', '/projects/apollo/wiki'],
|
||||||
|
['wiki-edit', '/projects/apollo/wiki/Wiki/edit'],
|
||||||
|
['news', '/news/1'],
|
||||||
|
['forum-topic', '/boards/1/topics/1'],
|
||||||
|
['documents', '/projects/apollo/documents'],
|
||||||
|
['files', '/projects/apollo/files'],
|
||||||
|
['time-entries', '/projects/apollo/time_entries'],
|
||||||
|
['time-report', '/projects/apollo/time_entries/report?criteria[]=user&columns=month'],
|
||||||
|
['search', '/search?q=login'],
|
||||||
|
['my-account', '/my/account'],
|
||||||
|
['admin', '/admin'],
|
||||||
|
['settings', '/settings'],
|
||||||
|
['users', '/users'],
|
||||||
|
['permissions', '/roles/permissions'],
|
||||||
|
['workflow', '/workflows/edit?role_id=3&tracker_id=1'],
|
||||||
|
['not-found', '/issues/99999'],
|
||||||
|
['repository', '/projects/apollo/repository'],
|
||||||
|
['repository-revisions', '/projects/apollo/repository/portal/revisions'],
|
||||||
|
['repository-entry', '/projects/apollo/repository/portal/entry/lib/portal.rb'],
|
||||||
|
['repository-annotate', '/projects/apollo/repository/portal/annotate/lib/portal.rb'],
|
||||||
|
['repository-diff', '/projects/apollo/repository/portal/revisions/main/diff'],
|
||||||
|
['wiki-history', '/projects/apollo/wiki/Wiki/history'],
|
||||||
|
['wiki-diff', '/projects/apollo/wiki/Wiki/diff?version=2&version_from=1'],
|
||||||
|
['project-settings', '/projects/apollo/settings'],
|
||||||
|
['project-settings-members', '/projects/apollo/settings/members'],
|
||||||
|
['project-settings-versions', '/projects/apollo/settings/versions'],
|
||||||
|
['project-settings-repositories', '/projects/apollo/settings/repositories'],
|
||||||
|
['trackers', '/trackers'],
|
||||||
|
['issue-statuses', '/issue_statuses'],
|
||||||
|
['custom-fields', '/custom_fields'],
|
||||||
|
['custom-field-edit', '/custom_fields/1/edit'],
|
||||||
|
['enumerations', '/enumerations'],
|
||||||
|
['admin-info', '/admin/info'],
|
||||||
|
['admin-plugins', '/admin/plugins'],
|
||||||
|
['workflow-fields', '/workflows/permissions?role_id=3&tracker_id=1'],
|
||||||
|
['forums', '/projects/apollo/boards'],
|
||||||
|
];
|
||||||
|
|
||||||
|
// Pages only reachable while logged out.
|
||||||
|
const publicPages = [
|
||||||
|
['login', '/login'],
|
||||||
|
['register', '/account/register'],
|
||||||
|
['lost-password', '/account/lost_password'],
|
||||||
|
];
|
||||||
|
|
||||||
|
// Pages that need an interaction before the capture.
|
||||||
|
const interactions = [
|
||||||
|
['issue-new-error', '/projects/apollo/issues/new', async (p) => {
|
||||||
|
await p.click('#issue-form input[name=commit]');
|
||||||
|
await p.waitForLoadState('networkidle');
|
||||||
|
}],
|
||||||
|
['issues-context-menu', '/projects/apollo/issues', async (p) => {
|
||||||
|
await p.click('table.list.issues tr.issue td.status', { button: 'right' });
|
||||||
|
await p.waitForSelector('#context-menu ul');
|
||||||
|
}, { desktopOnly: true }],
|
||||||
|
['journal-diff', '/issues/13', async (p) => {
|
||||||
|
// The journal ID differs per database, so follow the first description diff link.
|
||||||
|
await Promise.all([p.waitForURL(/\/journals\/\d+\/diff/), p.click('#history a[href*="/diff"]')]);
|
||||||
|
await p.waitForLoadState('networkidle');
|
||||||
|
}],
|
||||||
|
['import-mapping', '/issues/imports/new?project_id=apollo', async (p) => {
|
||||||
|
await p.setInputFiles('#file', new URL('fixtures/issues.csv', import.meta.url).pathname);
|
||||||
|
await Promise.all([p.waitForURL(/\/imports\/[^/]+\/settings/), p.click('input[type=submit]')]);
|
||||||
|
await Promise.all([p.waitForURL(/\/imports\/[^/]+\/mapping/), p.click('input[type=submit]')]);
|
||||||
|
await p.waitForLoadState('networkidle');
|
||||||
|
}],
|
||||||
|
['project-jump', '/projects/apollo-api/issues', async (p) => {
|
||||||
|
await p.click('#project-jump .drdn-trigger');
|
||||||
|
await p.waitForSelector('#project-jump .drdn-items');
|
||||||
|
}, { desktopOnly: true }],
|
||||||
|
['mobile-flyout', '/projects/apollo/issues', async (p) => {
|
||||||
|
await p.click('.mobile-toggle-button');
|
||||||
|
await p.waitForTimeout(300);
|
||||||
|
}, { mobileOnly: true, viewportOnly: true }],
|
||||||
|
];
|
||||||
|
|
||||||
|
const viewports = {
|
||||||
|
desktop: { width: 1440, height: 900 },
|
||||||
|
mobile: { width: 390, height: 844, isMobile: true, hasTouch: true },
|
||||||
|
};
|
||||||
|
|
||||||
|
await mkdir(OUT, { recursive: true });
|
||||||
|
const browser = await chromium.launch();
|
||||||
|
|
||||||
|
for (const scheme of ['light', 'dark']) {
|
||||||
|
for (const [vpName, vp] of Object.entries(viewports)) {
|
||||||
|
const { width, height, ...rest } = vp;
|
||||||
|
const context = await browser.newContext({ viewport: { width, height }, colorScheme: scheme, ...rest });
|
||||||
|
const page = await context.newPage();
|
||||||
|
const shot = (name, fullPage = true) =>
|
||||||
|
page.screenshot({ path: `${OUT}${name}-${scheme}-${vpName}.png`, fullPage });
|
||||||
|
|
||||||
|
for (const [name, path] of publicPages.filter(([n]) => n.includes(filter))) {
|
||||||
|
await page.goto(`${BASE}${path}`, { waitUntil: 'networkidle' });
|
||||||
|
await shot(name);
|
||||||
|
}
|
||||||
|
await page.goto(`${BASE}/login`);
|
||||||
|
await page.fill('#username', 'admin');
|
||||||
|
await page.fill('#password', 'admin');
|
||||||
|
await page.click('#login-submit');
|
||||||
|
await page.waitForURL((url) => !url.pathname.startsWith('/login'));
|
||||||
|
|
||||||
|
for (const [name, path] of pages.filter(([n]) => n.includes(filter))) {
|
||||||
|
await page.goto(`${BASE}${path}`, { waitUntil: 'networkidle' });
|
||||||
|
await shot(name);
|
||||||
|
}
|
||||||
|
for (const [name, path, act, opts = {}] of interactions.filter(([n]) => n.includes(filter))) {
|
||||||
|
if ((opts.desktopOnly && vpName !== 'desktop') || (opts.mobileOnly && vpName !== 'mobile')) continue;
|
||||||
|
await page.goto(`${BASE}${path}`, { waitUntil: 'networkidle' });
|
||||||
|
await act(page);
|
||||||
|
await shot(name, !opts.viewportOnly);
|
||||||
|
}
|
||||||
|
await context.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
await browser.close();
|
||||||
|
console.log(`Screenshots written to ${OUT}`);
|
||||||
|
After Width: | Height: | Size: 2.4 KiB |
@@ -0,0 +1,93 @@
|
|||||||
|
Copyright 2011 The Roboto Project Authors (https://github.com/googlefonts/roboto-classic) Roboto-Italic[wdth,wght].ttf: Copyright 2011 The Roboto Project Authors (https://github.com/googlefonts/roboto-classic)
|
||||||
|
|
||||||
|
This Font Software is licensed under the SIL Open Font License, Version 1.1.
|
||||||
|
This license is copied below, and is also available with a FAQ at:
|
||||||
|
http://scripts.sil.org/OFL
|
||||||
|
|
||||||
|
|
||||||
|
-----------------------------------------------------------
|
||||||
|
SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
|
||||||
|
-----------------------------------------------------------
|
||||||
|
|
||||||
|
PREAMBLE
|
||||||
|
The goals of the Open Font License (OFL) are to stimulate worldwide
|
||||||
|
development of collaborative font projects, to support the font creation
|
||||||
|
efforts of academic and linguistic communities, and to provide a free and
|
||||||
|
open framework in which fonts may be shared and improved in partnership
|
||||||
|
with others.
|
||||||
|
|
||||||
|
The OFL allows the licensed fonts to be used, studied, modified and
|
||||||
|
redistributed freely as long as they are not sold by themselves. The
|
||||||
|
fonts, including any derivative works, can be bundled, embedded,
|
||||||
|
redistributed and/or sold with any software provided that any reserved
|
||||||
|
names are not used by derivative works. The fonts and derivatives,
|
||||||
|
however, cannot be released under any other type of license. The
|
||||||
|
requirement for fonts to remain under this license does not apply
|
||||||
|
to any document created using the fonts or their derivatives.
|
||||||
|
|
||||||
|
DEFINITIONS
|
||||||
|
"Font Software" refers to the set of files released by the Copyright
|
||||||
|
Holder(s) under this license and clearly marked as such. This may
|
||||||
|
include source files, build scripts and documentation.
|
||||||
|
|
||||||
|
"Reserved Font Name" refers to any names specified as such after the
|
||||||
|
copyright statement(s).
|
||||||
|
|
||||||
|
"Original Version" refers to the collection of Font Software components as
|
||||||
|
distributed by the Copyright Holder(s).
|
||||||
|
|
||||||
|
"Modified Version" refers to any derivative made by adding to, deleting,
|
||||||
|
or substituting -- in part or in whole -- any of the components of the
|
||||||
|
Original Version, by changing formats or by porting the Font Software to a
|
||||||
|
new environment.
|
||||||
|
|
||||||
|
"Author" refers to any designer, engineer, programmer, technical
|
||||||
|
writer or other person who contributed to the Font Software.
|
||||||
|
|
||||||
|
PERMISSION & CONDITIONS
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining
|
||||||
|
a copy of the Font Software, to use, study, copy, merge, embed, modify,
|
||||||
|
redistribute, and sell modified and unmodified copies of the Font
|
||||||
|
Software, subject to the following conditions:
|
||||||
|
|
||||||
|
1) Neither the Font Software nor any of its individual components,
|
||||||
|
in Original or Modified Versions, may be sold by itself.
|
||||||
|
|
||||||
|
2) Original or Modified Versions of the Font Software may be bundled,
|
||||||
|
redistributed and/or sold with any software, provided that each copy
|
||||||
|
contains the above copyright notice and this license. These can be
|
||||||
|
included either as stand-alone text files, human-readable headers or
|
||||||
|
in the appropriate machine-readable metadata fields within text or
|
||||||
|
binary files as long as those fields can be easily viewed by the user.
|
||||||
|
|
||||||
|
3) No Modified Version of the Font Software may use the Reserved Font
|
||||||
|
Name(s) unless explicit written permission is granted by the corresponding
|
||||||
|
Copyright Holder. This restriction only applies to the primary font name as
|
||||||
|
presented to the users.
|
||||||
|
|
||||||
|
4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
|
||||||
|
Software shall not be used to promote, endorse or advertise any
|
||||||
|
Modified Version, except to acknowledge the contribution(s) of the
|
||||||
|
Copyright Holder(s) and the Author(s) or with their explicit written
|
||||||
|
permission.
|
||||||
|
|
||||||
|
5) The Font Software, modified or unmodified, in part or in whole,
|
||||||
|
must be distributed entirely under this license, and must not be
|
||||||
|
distributed under any other license. The requirement for fonts to
|
||||||
|
remain under this license does not apply to any document created
|
||||||
|
using the Font Software.
|
||||||
|
|
||||||
|
TERMINATION
|
||||||
|
This license becomes null and void if any of the above conditions are
|
||||||
|
not met.
|
||||||
|
|
||||||
|
DISCLAIMER
|
||||||
|
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||||
|
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
|
||||||
|
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
|
||||||
|
OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
|
||||||
|
COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||||
|
INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
|
||||||
|
DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
|
||||||
|
OTHER DEALINGS IN THE FONT SOFTWARE.
|
||||||
@@ -0,0 +1,204 @@
|
|||||||
|
This license applies to images/icons.svg (Material Symbols by Google, https://github.com/google/material-design-icons).
|
||||||
|
|
||||||
|
|
||||||
|
Apache License
|
||||||
|
Version 2.0, January 2004
|
||||||
|
http://www.apache.org/licenses/
|
||||||
|
|
||||||
|
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||||
|
|
||||||
|
1. Definitions.
|
||||||
|
|
||||||
|
"License" shall mean the terms and conditions for use, reproduction,
|
||||||
|
and distribution as defined by Sections 1 through 9 of this document.
|
||||||
|
|
||||||
|
"Licensor" shall mean the copyright owner or entity authorized by
|
||||||
|
the copyright owner that is granting the License.
|
||||||
|
|
||||||
|
"Legal Entity" shall mean the union of the acting entity and all
|
||||||
|
other entities that control, are controlled by, or are under common
|
||||||
|
control with that entity. For the purposes of this definition,
|
||||||
|
"control" means (i) the power, direct or indirect, to cause the
|
||||||
|
direction or management of such entity, whether by contract or
|
||||||
|
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||||
|
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||||
|
|
||||||
|
"You" (or "Your") shall mean an individual or Legal Entity
|
||||||
|
exercising permissions granted by this License.
|
||||||
|
|
||||||
|
"Source" form shall mean the preferred form for making modifications,
|
||||||
|
including but not limited to software source code, documentation
|
||||||
|
source, and configuration files.
|
||||||
|
|
||||||
|
"Object" form shall mean any form resulting from mechanical
|
||||||
|
transformation or translation of a Source form, including but
|
||||||
|
not limited to compiled object code, generated documentation,
|
||||||
|
and conversions to other media types.
|
||||||
|
|
||||||
|
"Work" shall mean the work of authorship, whether in Source or
|
||||||
|
Object form, made available under the License, as indicated by a
|
||||||
|
copyright notice that is included in or attached to the work
|
||||||
|
(an example is provided in the Appendix below).
|
||||||
|
|
||||||
|
"Derivative Works" shall mean any work, whether in Source or Object
|
||||||
|
form, that is based on (or derived from) the Work and for which the
|
||||||
|
editorial revisions, annotations, elaborations, or other modifications
|
||||||
|
represent, as a whole, an original work of authorship. For the purposes
|
||||||
|
of this License, Derivative Works shall not include works that remain
|
||||||
|
separable from, or merely link (or bind by name) to the interfaces of,
|
||||||
|
the Work and Derivative Works thereof.
|
||||||
|
|
||||||
|
"Contribution" shall mean any work of authorship, including
|
||||||
|
the original version of the Work and any modifications or additions
|
||||||
|
to that Work or Derivative Works thereof, that is intentionally
|
||||||
|
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||||
|
or by an individual or Legal Entity authorized to submit on behalf of
|
||||||
|
the copyright owner. For the purposes of this definition, "submitted"
|
||||||
|
means any form of electronic, verbal, or written communication sent
|
||||||
|
to the Licensor or its representatives, including but not limited to
|
||||||
|
communication on electronic mailing lists, source code control systems,
|
||||||
|
and issue tracking systems that are managed by, or on behalf of, the
|
||||||
|
Licensor for the purpose of discussing and improving the Work, but
|
||||||
|
excluding communication that is conspicuously marked or otherwise
|
||||||
|
designated in writing by the copyright owner as "Not a Contribution."
|
||||||
|
|
||||||
|
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||||
|
on behalf of whom a Contribution has been received by Licensor and
|
||||||
|
subsequently incorporated within the Work.
|
||||||
|
|
||||||
|
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||||
|
this License, each Contributor hereby grants to You a perpetual,
|
||||||
|
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||||
|
copyright license to reproduce, prepare Derivative Works of,
|
||||||
|
publicly display, publicly perform, sublicense, and distribute the
|
||||||
|
Work and such Derivative Works in Source or Object form.
|
||||||
|
|
||||||
|
3. Grant of Patent License. Subject to the terms and conditions of
|
||||||
|
this License, each Contributor hereby grants to You a perpetual,
|
||||||
|
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||||
|
(except as stated in this section) patent license to make, have made,
|
||||||
|
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||||
|
where such license applies only to those patent claims licensable
|
||||||
|
by such Contributor that are necessarily infringed by their
|
||||||
|
Contribution(s) alone or by combination of their Contribution(s)
|
||||||
|
with the Work to which such Contribution(s) was submitted. If You
|
||||||
|
institute patent litigation against any entity (including a
|
||||||
|
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||||
|
or a Contribution incorporated within the Work constitutes direct
|
||||||
|
or contributory patent infringement, then any patent licenses
|
||||||
|
granted to You under this License for that Work shall terminate
|
||||||
|
as of the date such litigation is filed.
|
||||||
|
|
||||||
|
4. Redistribution. You may reproduce and distribute copies of the
|
||||||
|
Work or Derivative Works thereof in any medium, with or without
|
||||||
|
modifications, and in Source or Object form, provided that You
|
||||||
|
meet the following conditions:
|
||||||
|
|
||||||
|
(a) You must give any other recipients of the Work or
|
||||||
|
Derivative Works a copy of this License; and
|
||||||
|
|
||||||
|
(b) You must cause any modified files to carry prominent notices
|
||||||
|
stating that You changed the files; and
|
||||||
|
|
||||||
|
(c) You must retain, in the Source form of any Derivative Works
|
||||||
|
that You distribute, all copyright, patent, trademark, and
|
||||||
|
attribution notices from the Source form of the Work,
|
||||||
|
excluding those notices that do not pertain to any part of
|
||||||
|
the Derivative Works; and
|
||||||
|
|
||||||
|
(d) If the Work includes a "NOTICE" text file as part of its
|
||||||
|
distribution, then any Derivative Works that You distribute must
|
||||||
|
include a readable copy of the attribution notices contained
|
||||||
|
within such NOTICE file, excluding those notices that do not
|
||||||
|
pertain to any part of the Derivative Works, in at least one
|
||||||
|
of the following places: within a NOTICE text file distributed
|
||||||
|
as part of the Derivative Works; within the Source form or
|
||||||
|
documentation, if provided along with the Derivative Works; or,
|
||||||
|
within a display generated by the Derivative Works, if and
|
||||||
|
wherever such third-party notices normally appear. The contents
|
||||||
|
of the NOTICE file are for informational purposes only and
|
||||||
|
do not modify the License. You may add Your own attribution
|
||||||
|
notices within Derivative Works that You distribute, alongside
|
||||||
|
or as an addendum to the NOTICE text from the Work, provided
|
||||||
|
that such additional attribution notices cannot be construed
|
||||||
|
as modifying the License.
|
||||||
|
|
||||||
|
You may add Your own copyright statement to Your modifications and
|
||||||
|
may provide additional or different license terms and conditions
|
||||||
|
for use, reproduction, or distribution of Your modifications, or
|
||||||
|
for any such Derivative Works as a whole, provided Your use,
|
||||||
|
reproduction, and distribution of the Work otherwise complies with
|
||||||
|
the conditions stated in this License.
|
||||||
|
|
||||||
|
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||||
|
any Contribution intentionally submitted for inclusion in the Work
|
||||||
|
by You to the Licensor shall be under the terms and conditions of
|
||||||
|
this License, without any additional terms or conditions.
|
||||||
|
Notwithstanding the above, nothing herein shall supersede or modify
|
||||||
|
the terms of any separate license agreement you may have executed
|
||||||
|
with Licensor regarding such Contributions.
|
||||||
|
|
||||||
|
6. Trademarks. This License does not grant permission to use the trade
|
||||||
|
names, trademarks, service marks, or product names of the Licensor,
|
||||||
|
except as required for reasonable and customary use in describing the
|
||||||
|
origin of the Work and reproducing the content of the NOTICE file.
|
||||||
|
|
||||||
|
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||||
|
agreed to in writing, Licensor provides the Work (and each
|
||||||
|
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||||
|
implied, including, without limitation, any warranties or conditions
|
||||||
|
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||||
|
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||||
|
appropriateness of using or redistributing the Work and assume any
|
||||||
|
risks associated with Your exercise of permissions under this License.
|
||||||
|
|
||||||
|
8. Limitation of Liability. In no event and under no legal theory,
|
||||||
|
whether in tort (including negligence), contract, or otherwise,
|
||||||
|
unless required by applicable law (such as deliberate and grossly
|
||||||
|
negligent acts) or agreed to in writing, shall any Contributor be
|
||||||
|
liable to You for damages, including any direct, indirect, special,
|
||||||
|
incidental, or consequential damages of any character arising as a
|
||||||
|
result of this License or out of the use or inability to use the
|
||||||
|
Work (including but not limited to damages for loss of goodwill,
|
||||||
|
work stoppage, computer failure or malfunction, or any and all
|
||||||
|
other commercial damages or losses), even if such Contributor
|
||||||
|
has been advised of the possibility of such damages.
|
||||||
|
|
||||||
|
9. Accepting Warranty or Additional Liability. While redistributing
|
||||||
|
the Work or Derivative Works thereof, You may choose to offer,
|
||||||
|
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||||
|
or other liability obligations and/or rights consistent with this
|
||||||
|
License. However, in accepting such obligations, You may act only
|
||||||
|
on Your own behalf and on Your sole responsibility, not on behalf
|
||||||
|
of any other Contributor, and only if You agree to indemnify,
|
||||||
|
defend, and hold each Contributor harmless for any liability
|
||||||
|
incurred by, or claims asserted against, such Contributor by reason
|
||||||
|
of your accepting any such warranty or additional liability.
|
||||||
|
|
||||||
|
END OF TERMS AND CONDITIONS
|
||||||
|
|
||||||
|
APPENDIX: How to apply the Apache License to your work.
|
||||||
|
|
||||||
|
To apply the Apache License to your work, attach the following
|
||||||
|
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||||
|
replaced with your own identifying information. (Don't include
|
||||||
|
the brackets!) The text should be enclosed in the appropriate
|
||||||
|
comment syntax for the file format. We also recommend that a
|
||||||
|
file or class name and description of purpose be included on the
|
||||||
|
same "printed page" as the copyright notice for easier
|
||||||
|
identification within third-party archives.
|
||||||
|
|
||||||
|
Copyright [yyyy] [name of copyright owner]
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 -960 960 960" width="24" height="24"><path fill="#cac4cf" d="M480-360 280-560h400L480-360Z"/></svg>
|
||||||
|
After Width: | Height: | Size: 151 B |
@@ -0,0 +1 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 -960 960 960" width="24" height="24"><path fill="#49454e" d="M480-360 280-560h400L480-360Z"/></svg>
|
||||||
|
After Width: | Height: | Size: 151 B |
@@ -0,0 +1 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 -960 960 960" width="16" height="16"><path fill="#cac4cf" d="M560-240 320-480l240-240 56 56-184 184 184 184-56 56Z"/></svg>
|
||||||
|
After Width: | Height: | Size: 175 B |
@@ -0,0 +1 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 -960 960 960" width="16" height="16"><path fill="#49454e" d="M560-240 320-480l240-240 56 56-184 184 184 184-56 56Z"/></svg>
|
||||||
|
After Width: | Height: | Size: 175 B |
@@ -0,0 +1 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 -960 960 960" width="16" height="16"><path fill="#cac4cf" d="M504-480 320-664l56-56 240 240-240 240-56-56 184-184Z"/></svg>
|
||||||
|
After Width: | Height: | Size: 175 B |
@@ -0,0 +1 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 -960 960 960" width="16" height="16"><path fill="#49454e" d="M504-480 320-664l56-56 240 240-240 240-56-56 184-184Z"/></svg>
|
||||||
|
After Width: | Height: | Size: 175 B |
@@ -0,0 +1,123 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<!-- Generated by tools/build_icons.rb from tools/icon_map.yml. Do not edit by hand.
|
||||||
|
Icons: Material Symbols Outlined by Google (github.com/google/material-design-icons),
|
||||||
|
Apache License 2.0, see LICENSE-material-symbols.txt. -->
|
||||||
|
<symbol id="icon--3-bullets" viewBox="0 -960 960 960"><path d="M240-400q-33 0-56.5-23.5T160-480q0-33 23.5-56.5T240-560q33 0 56.5 23.5T320-480q0 33-23.5 56.5T240-400Zm240 0q-33 0-56.5-23.5T400-480q0-33 23.5-56.5T480-560q33 0 56.5 23.5T560-480q0 33-23.5 56.5T480-400Zm240 0q-33 0-56.5-23.5T640-480q0-33 23.5-56.5T720-560q33 0 56.5 23.5T800-480q0 33-23.5 56.5T720-400Z" fill="currentColor" stroke="none"/></symbol>
|
||||||
|
<symbol id="icon--add" viewBox="0 -960 960 960"><path d="M440-280h80v-160h160v-80H520v-160h-80v160H280v80h160v160Zm40 200q-83 0-156-31.5T197-197q-54-54-85.5-127T80-480q0-83 31.5-156T197-763q54-54 127-85.5T480-880q83 0 156 31.5T763-763q54 54 85.5 127T880-480q0 83-31.5 156T763-197q-54 54-127 85.5T480-80Zm0-80q134 0 227-93t93-227q0-134-93-227t-227-93q-134 0-227 93t-93 227q0 134 93 227t227 93Zm0-320Z" fill="currentColor" stroke="none"/></symbol>
|
||||||
|
<symbol id="icon--alert-circle" viewBox="0 -960 960 960"><path d="M480-280q17 0 28.5-11.5T520-320q0-17-11.5-28.5T480-360q-17 0-28.5 11.5T440-320q0 17 11.5 28.5T480-280Zm-40-160h80v-240h-80v240Zm40 360q-83 0-156-31.5T197-197q-54-54-85.5-127T80-480q0-83 31.5-156T197-763q54-54 127-85.5T480-880q83 0 156 31.5T763-763q54 54 85.5 127T880-480q0 83-31.5 156T763-197q-54 54-127 85.5T480-80Zm0-80q134 0 227-93t93-227q0-134-93-227t-227-93q-134 0-227 93t-93 227q0 134 93 227t227 93Zm0-320Z" fill="currentColor" stroke="none"/></symbol>
|
||||||
|
<symbol id="icon--angle-down" viewBox="0 -960 960 960"><path d="M480-345 240-585l56-56 184 184 184-184 56 56-240 240Z" fill="currentColor" stroke="none"/></symbol>
|
||||||
|
<symbol id="icon--angle-left" viewBox="0 -960 960 960"><path d="M560-240 320-480l240-240 56 56-184 184 184 184-56 56Z" fill="currentColor" stroke="none"/></symbol>
|
||||||
|
<symbol id="icon--angle-right" viewBox="0 -960 960 960"><path d="M504-480 320-664l56-56 240 240-240 240-56-56 184-184Z" fill="currentColor" stroke="none"/></symbol>
|
||||||
|
<symbol id="icon--angle-up" viewBox="0 -960 960 960"><path d="m296-345-56-56 240-240 240 240-56 56-184-184-184 184Z" fill="currentColor" stroke="none"/></symbol>
|
||||||
|
<symbol id="icon--application-gzip" viewBox="0 -960 960 960"><path d="M640-480v-80h80v80h-80Zm0 80h-80v-80h80v80Zm0 80v-80h80v80h-80ZM447-640l-80-80H160v480h400v-80h80v80h160v-400H640v80h-80v-80H447ZM160-160q-33 0-56.5-23.5T80-240v-480q0-33 23.5-56.5T160-800h240l80 80h320q33 0 56.5 23.5T880-640v400q0 33-23.5 56.5T800-160H160Zm0-80v-480 480Z" fill="currentColor" stroke="none"/></symbol>
|
||||||
|
<symbol id="icon--application-javascript" viewBox="0 -960 960 960"><path d="M300-360q-25 0-42.5-17.5T240-420v-40h60v40h60v-180h60v180q0 25-17.5 42.5T360-360h-60Zm220 0q-17 0-28.5-11.5T480-400v-40h60v20h80v-40H520q-17 0-28.5-11.5T480-500v-60q0-17 11.5-28.5T520-600h120q17 0 28.5 11.5T680-560v40h-60v-20h-80v40h100q17 0 28.5 11.5T680-460v60q0 17-11.5 28.5T640-360H520Z" fill="currentColor" stroke="none"/></symbol>
|
||||||
|
<symbol id="icon--application-pdf" viewBox="0 -960 960 960"><path d="M360-460h40v-80h40q17 0 28.5-11.5T480-580v-40q0-17-11.5-28.5T440-660h-80v200Zm40-120v-40h40v40h-40Zm120 120h80q17 0 28.5-11.5T640-500v-120q0-17-11.5-28.5T600-660h-80v200Zm40-40v-120h40v120h-40Zm120 40h40v-80h40v-40h-40v-40h40v-40h-80v200ZM320-240q-33 0-56.5-23.5T240-320v-480q0-33 23.5-56.5T320-880h480q33 0 56.5 23.5T880-800v480q0 33-23.5 56.5T800-240H320Zm0-80h480v-480H320v480ZM160-80q-33 0-56.5-23.5T80-160v-560h80v560h560v80H160Zm160-720v480-480Z" fill="currentColor" stroke="none"/></symbol>
|
||||||
|
<symbol id="icon--application-zip" viewBox="0 -960 960 960"><path d="M640-480v-80h80v80h-80Zm0 80h-80v-80h80v80Zm0 80v-80h80v80h-80ZM447-640l-80-80H160v480h400v-80h80v80h160v-400H640v80h-80v-80H447ZM160-160q-33 0-56.5-23.5T80-240v-480q0-33 23.5-56.5T160-800h240l80 80h320q33 0 56.5 23.5T880-640v400q0 33-23.5 56.5T800-160H160Zm0-80v-480 480Z" fill="currentColor" stroke="none"/></symbol>
|
||||||
|
<symbol id="icon--apps" viewBox="0 -960 960 960"><path d="M240-160q-33 0-56.5-23.5T160-240q0-33 23.5-56.5T240-320q33 0 56.5 23.5T320-240q0 33-23.5 56.5T240-160Zm240 0q-33 0-56.5-23.5T400-240q0-33 23.5-56.5T480-320q33 0 56.5 23.5T560-240q0 33-23.5 56.5T480-160Zm240 0q-33 0-56.5-23.5T640-240q0-33 23.5-56.5T720-320q33 0 56.5 23.5T800-240q0 33-23.5 56.5T720-160ZM240-400q-33 0-56.5-23.5T160-480q0-33 23.5-56.5T240-560q33 0 56.5 23.5T320-480q0 33-23.5 56.5T240-400Zm240 0q-33 0-56.5-23.5T400-480q0-33 23.5-56.5T480-560q33 0 56.5 23.5T560-480q0 33-23.5 56.5T480-400Zm240 0q-33 0-56.5-23.5T640-480q0-33 23.5-56.5T720-560q33 0 56.5 23.5T800-480q0 33-23.5 56.5T720-400ZM240-640q-33 0-56.5-23.5T160-720q0-33 23.5-56.5T240-800q33 0 56.5 23.5T320-720q0 33-23.5 56.5T240-640Zm240 0q-33 0-56.5-23.5T400-720q0-33 23.5-56.5T480-800q33 0 56.5 23.5T560-720q0 33-23.5 56.5T480-640Zm240 0q-33 0-56.5-23.5T640-720q0-33 23.5-56.5T720-800q33 0 56.5 23.5T800-720q0 33-23.5 56.5T720-640Z" fill="currentColor" stroke="none"/></symbol>
|
||||||
|
<symbol id="icon--arrow-narrow-left" viewBox="0 -960 960 960"><path d="M400-240 160-480l240-240 56 58-142 142h486v80H314l142 142-56 58Z" fill="currentColor" stroke="none"/></symbol>
|
||||||
|
<symbol id="icon--arrow-narrow-right" viewBox="0 -960 960 960"><path d="m560-240-56-58 142-142H160v-80h486L504-662l56-58 240 240-240 240Z" fill="currentColor" stroke="none"/></symbol>
|
||||||
|
<symbol id="icon--arrow-right" viewBox="0 -960 960 960"><path d="M647-440H160v-80h487L423-744l57-56 320 320-320 320-57-56 224-224Z" fill="currentColor" stroke="none"/></symbol>
|
||||||
|
<symbol id="icon--attachment" viewBox="0 -960 960 960"><path d="M720-330q0 104-73 177T470-80q-104 0-177-73t-73-177v-370q0-75 52.5-127.5T400-880q75 0 127.5 52.5T580-700v350q0 46-32 78t-78 32q-46 0-78-32t-32-78v-370h80v370q0 13 8.5 21.5T470-320q13 0 21.5-8.5T500-350v-350q-1-42-29.5-71T400-800q-42 0-71 29t-29 71v370q-1 71 49 120.5T470-160q70 0 119-49.5T640-330v-390h80v390Z" fill="currentColor" stroke="none"/></symbol>
|
||||||
|
<symbol id="icon--bookmark-add" viewBox="0 -960 960 960"><path d="M200-120v-640q0-33 23.5-56.5T280-840h240v80H280v518l200-86 200 86v-278h80v400L480-240 200-120Zm80-640h240-240Zm400 160v-80h-80v-80h80v-80h80v80h80v80h-80v80h-80Z" fill="currentColor" stroke="none"/></symbol>
|
||||||
|
<symbol id="icon--bookmark-delete" viewBox="0 -960 960 960"><path d="M840-680H600v-80h240v80ZM200-120v-640q0-33 23.5-56.5T280-840h240v80H280v518l200-86 200 86v-278h80v400L480-240 200-120Zm80-640h240-240Z" fill="currentColor" stroke="none"/></symbol>
|
||||||
|
<symbol id="icon--bookmarked" viewBox="0 -960 960 960"><path d="M200-120v-640q0-33 23.5-56.5T280-840h400q33 0 56.5 23.5T760-760v640L480-240 200-120Zm80-122 200-86 200 86v-518H280v518Zm0-518h400-400Z" fill="currentColor" stroke="none"/></symbol>
|
||||||
|
<symbol id="icon--bulb" viewBox="0 -960 960 960"><path d="M480-80q-33 0-56.5-23.5T400-160h160q0 33-23.5 56.5T480-80ZM320-200v-80h320v80H320Zm10-120q-69-41-109.5-110T180-580q0-125 87.5-212.5T480-880q125 0 212.5 87.5T780-580q0 81-40.5 150T630-320H330Zm24-80h252q45-32 69.5-79T700-580q0-92-64-156t-156-64q-92 0-156 64t-64 156q0 54 24.5 101t69.5 79Zm126 0Z" fill="currentColor" stroke="none"/></symbol>
|
||||||
|
<symbol id="icon--bullet-end" viewBox="0 -960 960 960"><path d="m480-320 56-56-64-64h168v-80H472l64-64-56-56-160 160 160 160Zm0 240q-83 0-156-31.5T197-197q-54-54-85.5-127T80-480q0-83 31.5-156T197-763q54-54 127-85.5T480-880q83 0 156 31.5T763-763q54 54 85.5 127T880-480q0 83-31.5 156T763-197q-54 54-127 85.5T480-80Zm0-80q134 0 227-93t93-227q0-134-93-227t-227-93q-134 0-227 93t-93 227q0 134 93 227t227 93Zm0-320Z" fill="currentColor" stroke="none"/></symbol>
|
||||||
|
<symbol id="icon--bullet-go" viewBox="0 -960 960 960"><path d="m480-320 160-160-160-160-56 56 64 64H320v80h168l-64 64 56 56Zm0 240q-83 0-156-31.5T197-197q-54-54-85.5-127T80-480q0-83 31.5-156T197-763q54-54 127-85.5T480-880q83 0 156 31.5T763-763q54 54 85.5 127T880-480q0 83-31.5 156T763-197q-54 54-127 85.5T480-80Zm0-80q134 0 227-93t93-227q0-134-93-227t-227-93q-134 0-227 93t-93 227q0 134 93 227t227 93Zm0-320Z" fill="currentColor" stroke="none"/></symbol>
|
||||||
|
<symbol id="icon--bullet-go-end" viewBox="0 -960 960 960"><path d="M480-120 80-600l120-240h560l120 240-400 480Zm-95-520h190l-60-120h-70l-60 120Zm55 347v-267H218l222 267Zm80 0 222-267H520v267Zm144-347h106l-60-120H604l60 120Zm-474 0h106l60-120H250l-60 120Z" fill="currentColor" stroke="none"/></symbol>
|
||||||
|
<symbol id="icon--cancel" viewBox="0 -960 960 960"><path d="M280-200v-80h284q63 0 109.5-40T720-420q0-60-46.5-100T564-560H312l104 104-56 56-200-200 200-200 56 56-104 104h252q97 0 166.5 63T800-420q0 94-69.5 157T564-200H280Z" fill="currentColor" stroke="none"/></symbol>
|
||||||
|
<symbol id="icon--changeset" viewBox="0 -960 960 960"><path d="M320-240 80-480l240-240 57 57-184 184 183 183-56 56Zm320 0-57-57 184-184-183-183 56-56 240 240-240 240Z" fill="currentColor" stroke="none"/></symbol>
|
||||||
|
<symbol id="icon--checked" viewBox="0 -960 960 960"><path d="M382-240 154-468l57-57 171 171 367-367 57 57-424 424Z" fill="currentColor" stroke="none"/></symbol>
|
||||||
|
<symbol id="icon--chevrons-left" viewBox="0 -960 960 960"><path d="M440-240 200-480l240-240 56 56-183 184 183 184-56 56Zm264 0L464-480l240-240 56 56-183 184 183 184-56 56Z" fill="currentColor" stroke="none"/></symbol>
|
||||||
|
<symbol id="icon--chevrons-right" viewBox="0 -960 960 960"><path d="M383-480 200-664l56-56 240 240-240 240-56-56 183-184Zm264 0L464-664l56-56 240 240-240 240-56-56 183-184Z" fill="currentColor" stroke="none"/></symbol>
|
||||||
|
<symbol id="icon--circle-dot-filled" viewBox="0 -960 960 960"><path d="M480-280q83 0 141.5-58.5T680-480q0-83-58.5-141.5T480-680q-83 0-141.5 58.5T280-480q0 83 58.5 141.5T480-280Zm0 200q-83 0-156-31.5T197-197q-54-54-85.5-127T80-480q0-83 31.5-156T197-763q54-54 127-85.5T480-880q83 0 156 31.5T763-763q54 54 85.5 127T880-480q0 83-31.5 156T763-197q-54 54-127 85.5T480-80Z" fill="currentColor" stroke="none"/></symbol>
|
||||||
|
<symbol id="icon--circle-minus" viewBox="0 -960 960 960"><path d="M280-440h400v-80H280v80ZM480-80q-83 0-156-31.5T197-197q-54-54-85.5-127T80-480q0-83 31.5-156T197-763q54-54 127-85.5T480-880q83 0 156 31.5T763-763q54 54 85.5 127T880-480q0 83-31.5 156T763-197q-54 54-127 85.5T480-80Zm0-80q134 0 227-93t93-227q0-134-93-227t-227-93q-134 0-227 93t-93 227q0 134 93 227t227 93Zm0-320Z" fill="currentColor" stroke="none"/></symbol>
|
||||||
|
<symbol id="icon--clear-query" viewBox="0 -960 960 960"><path d="m592-481-57-57 143-182H353l-80-80h487q25 0 36 22t-4 42L592-481ZM791-56 560-287v87q0 17-11.5 28.5T520-160h-80q-17 0-28.5-11.5T400-200v-247L56-791l56-57 736 736-57 56ZM535-538Z" fill="currentColor" stroke="none"/></symbol>
|
||||||
|
<symbol id="icon--close" viewBox="0 -960 960 960"><path d="m256-200-56-56 224-224-224-224 56-56 224 224 224-224 56 56-224 224 224 224-56 56-224-224-224 224Z" fill="currentColor" stroke="none"/></symbol>
|
||||||
|
<symbol id="icon--comment" viewBox="0 -960 960 960"><path d="M240-400h480v-80H240v80Zm0-120h480v-80H240v80Zm0-120h480v-80H240v80ZM880-80 720-240H160q-33 0-56.5-23.5T80-320v-480q0-33 23.5-56.5T160-880h640q33 0 56.5 23.5T880-800v720ZM160-320h594l46 45v-525H160v480Zm0 0v-480 480Z" fill="currentColor" stroke="none"/></symbol>
|
||||||
|
<symbol id="icon--comments" viewBox="0 -960 960 960"><path d="M280-240q-17 0-28.5-11.5T240-280v-80h520v-360h80q17 0 28.5 11.5T880-680v600L720-240H280ZM80-280v-560q0-17 11.5-28.5T120-880h520q17 0 28.5 11.5T680-840v360q0 17-11.5 28.5T640-440H240L80-280Zm520-240v-280H160v280h440Zm-440 0v-280 280Z" fill="currentColor" stroke="none"/></symbol>
|
||||||
|
<symbol id="icon--copy" viewBox="0 -960 960 960"><path d="M360-240q-33 0-56.5-23.5T280-320v-480q0-33 23.5-56.5T360-880h360q33 0 56.5 23.5T800-800v480q0 33-23.5 56.5T720-240H360Zm0-80h360v-480H360v480ZM200-80q-33 0-56.5-23.5T120-160v-560h80v560h440v80H200Zm160-240v-480 480Z" fill="currentColor" stroke="none"/></symbol>
|
||||||
|
<symbol id="icon--copy-link" viewBox="0 -960 960 960"><path d="M440-280H280q-83 0-141.5-58.5T80-480q0-83 58.5-141.5T280-680h160v80H280q-50 0-85 35t-35 85q0 50 35 85t85 35h160v80ZM320-440v-80h320v80H320Zm200 160v-80h160q50 0 85-35t35-85q0-50-35-85t-85-35H520v-80h160q83 0 141.5 58.5T880-480q0 83-58.5 141.5T680-280H520Z" fill="currentColor" stroke="none"/></symbol>
|
||||||
|
<symbol id="icon--copy-pre-content" viewBox="0 -960 960 960"><path d="M200-120q-33 0-56.5-23.5T120-200v-560q0-33 23.5-56.5T200-840h167q11-35 43-57.5t70-22.5q40 0 71.5 22.5T594-840h166q33 0 56.5 23.5T840-760v560q0 33-23.5 56.5T760-120H200Zm0-80h560v-560h-80v120H280v-120h-80v560Zm280-560q17 0 28.5-11.5T520-800q0-17-11.5-28.5T480-840q-17 0-28.5 11.5T440-800q0 17 11.5 28.5T480-760Z" fill="currentColor" stroke="none"/></symbol>
|
||||||
|
<symbol id="icon--custom-fields" viewBox="0 -960 960 960"><path d="M160-520q-33 0-56.5-23.5T80-600v-120q0-33 23.5-56.5T160-800h360v280H160Zm0-80h280v-120H160v120Zm0 440q-33 0-56.5-23.5T80-240v-120q0-33 23.5-56.5T160-440h440v280H160Zm0-80h360v-120H160v120Zm520 80v-360h-80v-280h280l-80 200h80L680-160ZM190-270h60v-60h-60v60Zm0-360h60v-60h-60v60Zm-30 30v-120 120Zm0 360v-120 120Z" fill="currentColor" stroke="none"/></symbol>
|
||||||
|
<symbol id="icon--del" viewBox="0 -960 960 960"><path d="M280-120q-33 0-56.5-23.5T200-200v-520h-40v-80h200v-40h240v40h200v80h-40v520q0 33-23.5 56.5T680-120H280Zm400-600H280v520h400v-520ZM360-280h80v-360h-80v360Zm160 0h80v-360h-80v360ZM280-720v520-520Z" fill="currentColor" stroke="none"/></symbol>
|
||||||
|
<symbol id="icon--document" viewBox="0 -960 960 960"><path d="M320-240h320v-80H320v80Zm0-160h320v-80H320v80ZM240-80q-33 0-56.5-23.5T160-160v-640q0-33 23.5-56.5T240-880h320l240 240v480q0 33-23.5 56.5T720-80H240Zm280-520v-200H240v640h480v-440H520ZM240-800v200-200 640-640Z" fill="currentColor" stroke="none"/></symbol>
|
||||||
|
<symbol id="icon--download" viewBox="0 -960 960 960"><path d="M480-320 280-520l56-58 104 104v-326h80v326l104-104 56 58-200 200ZM240-160q-33 0-56.5-23.5T160-240v-120h80v120h480v-120h80v120q0 33-23.5 56.5T720-160H240Z" fill="currentColor" stroke="none"/></symbol>
|
||||||
|
<symbol id="icon--edit" viewBox="0 -960 960 960"><path d="M200-200h57l391-391-57-57-391 391v57Zm-80 80v-170l528-527q12-11 26.5-17t30.5-6q16 0 31 6t26 18l55 56q12 11 17.5 26t5.5 30q0 16-5.5 30.5T817-647L290-120H120Zm640-584-56-56 56 56Zm-141 85-28-29 57 57-29-28Z" fill="currentColor" stroke="none"/></symbol>
|
||||||
|
<symbol id="icon--email" viewBox="0 -960 960 960"><path d="M160-160q-33 0-56.5-23.5T80-240v-480q0-33 23.5-56.5T160-800h640q33 0 56.5 23.5T880-720v480q0 33-23.5 56.5T800-160H160Zm320-280L160-640v400h640v-400L480-440Zm0-80 320-200H160l320 200ZM160-640v-80 480-400Z" fill="currentColor" stroke="none"/></symbol>
|
||||||
|
<symbol id="icon--email-disabled" viewBox="0 -960 960 960"><path d="M383-463Zm194-34ZM791-55 686-160H160q-33 0-56.5-23.5T80-240v-480q0-33 23.5-56.5T160-800l80 80h-80v480h446L55-791l57-57 736 736-57 57Zm80-148-71-71v-366L575-499l-49-49 274-172H354l-80-80h526q33 0 56.5 23.5T880-720v480q0 10-2 19.5t-7 17.5Z" fill="currentColor" stroke="none"/></symbol>
|
||||||
|
<symbol id="icon--fav" viewBox="0 -960 960 960"><path d="m354-287 126-76 126 77-33-144 111-96-146-13-58-136-58 135-146 13 111 97-33 143ZM233-120l65-281L80-590l288-25 112-265 112 265 288 25-218 189 65 281-247-149-247 149Zm247-350Z" fill="currentColor" stroke="none"/></symbol>
|
||||||
|
<symbol id="icon--file" viewBox="0 -960 960 960"><path d="M240-80q-33 0-56.5-23.5T160-160v-640q0-33 23.5-56.5T240-880h320l240 240v480q0 33-23.5 56.5T720-80H240Zm280-520v-200H240v640h480v-440H520ZM240-800v200-200 640-640Z" fill="currentColor" stroke="none"/></symbol>
|
||||||
|
<symbol id="icon--file-music" viewBox="0 -960 960 960"><path d="M430-200q38 0 64-26t26-64v-150h120v-80H480v155q-11-8-23.5-11.5T430-380q-38 0-64 26t-26 64q0 38 26 64t64 26ZM240-80q-33 0-56.5-23.5T160-160v-640q0-33 23.5-56.5T240-880h320l240 240v480q0 33-23.5 56.5T720-80H240Zm280-520v-200H240v640h480v-440H520ZM240-800v200-200 640-640Z" fill="currentColor" stroke="none"/></symbol>
|
||||||
|
<symbol id="icon--file-type-docx" viewBox="0 -960 960 960"><path d="M320-440h320v-80H320v80Zm0 120h320v-80H320v80Zm0 120h200v-80H320v80ZM240-80q-33 0-56.5-23.5T160-160v-640q0-33 23.5-56.5T240-880h320l240 240v480q0 33-23.5 56.5T720-80H240Zm280-520v-200H240v640h480v-440H520ZM240-800v200-200 640-640Z" fill="currentColor" stroke="none"/></symbol>
|
||||||
|
<symbol id="icon--file-type-ppt" viewBox="0 -960 960 960"><path d="m380-300 280-180-280-180v360ZM200-120q-33 0-56.5-23.5T120-200v-560q0-33 23.5-56.5T200-840h560q33 0 56.5 23.5T840-760v560q0 33-23.5 56.5T760-120H200Zm0-80h560v-560H200v560Zm0-560v560-560Z" fill="currentColor" stroke="none"/></symbol>
|
||||||
|
<symbol id="icon--file-type-xls" viewBox="0 -960 960 960"><path d="M120-200v-560q0-33 23.5-56.5T200-840h560q33 0 56.5 23.5T840-760v560q0 33-23.5 56.5T760-120H200q-33 0-56.5-23.5T120-200Zm80-400h560v-160H200v160Zm213 200h134v-120H413v120Zm0 200h134v-120H413v120ZM200-400h133v-120H200v120Zm427 0h133v-120H627v120ZM200-200h133v-120H200v120Zm427 0h133v-120H627v120Z" fill="currentColor" stroke="none"/></symbol>
|
||||||
|
<symbol id="icon--folder" viewBox="0 -960 960 960"><path d="M160-160q-33 0-56.5-23.5T80-240v-480q0-33 23.5-56.5T160-800h240l80 80h320q33 0 56.5 23.5T880-640v400q0 33-23.5 56.5T800-160H160Zm0-80h640v-400H447l-80-80H160v480Zm0 0v-480 480Z" fill="currentColor" stroke="none"/></symbol>
|
||||||
|
<symbol id="icon--folder-open" viewBox="0 -960 960 960"><path d="M160-160q-33 0-56.5-23.5T80-240v-480q0-33 23.5-56.5T160-800h240l80 80h320q33 0 56.5 23.5T880-640H447l-80-80H160v480l96-320h684L837-217q-8 26-29.5 41.5T760-160H160Zm84-80h516l72-240H316l-72 240Zm0 0 72-240-72 240Zm-84-400v-80 80Z" fill="currentColor" stroke="none"/></symbol>
|
||||||
|
<symbol id="icon--group" viewBox="0 -960 960 960"><path d="M40-160v-112q0-34 17.5-62.5T104-378q62-31 126-46.5T360-440q66 0 130 15.5T616-378q29 15 46.5 43.5T680-272v112H40Zm720 0v-120q0-44-24.5-84.5T666-434q51 6 96 20.5t84 35.5q36 20 55 44.5t19 53.5v120H760ZM360-480q-66 0-113-47t-47-113q0-66 47-113t113-47q66 0 113 47t47 113q0 66-47 113t-113 47Zm400-160q0 66-47 113t-113 47q-11 0-28-2.5t-28-5.5q27-32 41.5-71t14.5-81q0-42-14.5-81T544-792q14-5 28-6.5t28-1.5q66 0 113 47t47 113ZM120-240h480v-32q0-11-5.5-20T580-306q-54-27-109-40.5T360-360q-56 0-111 13.5T140-306q-9 5-14.5 14t-5.5 20v32Zm240-320q33 0 56.5-23.5T440-640q0-33-23.5-56.5T360-720q-33 0-56.5 23.5T280-640q0 33 23.5 56.5T360-560Zm0 320Zm0-400Z" fill="currentColor" stroke="none"/></symbol>
|
||||||
|
<symbol id="icon--help" viewBox="0 -960 960 960"><path d="M440-280h80v-240h-80v240Zm40-320q17 0 28.5-11.5T520-640q0-17-11.5-28.5T480-680q-17 0-28.5 11.5T440-640q0 17 11.5 28.5T480-600Zm0 520q-83 0-156-31.5T197-197q-54-54-85.5-127T80-480q0-83 31.5-156T197-763q54-54 127-85.5T480-880q83 0 156 31.5T763-763q54 54 85.5 127T880-480q0 83-31.5 156T763-197q-54 54-127 85.5T480-80Zm0-80q134 0 227-93t93-227q0-134-93-227t-227-93q-134 0-227 93t-93 227q0 134 93 227t227 93Zm0-320Z" fill="currentColor" stroke="none"/></symbol>
|
||||||
|
<symbol id="icon--history" viewBox="0 -960 960 960"><path d="M480-120q-138 0-240.5-91.5T122-440h82q14 104 92.5 172T480-200q117 0 198.5-81.5T760-480q0-117-81.5-198.5T480-760q-69 0-129 32t-101 88h110v80H120v-240h80v94q51-64 124.5-99T480-840q75 0 140.5 28.5t114 77q48.5 48.5 77 114T840-480q0 75-28.5 140.5t-77 114q-48.5 48.5-114 77T480-120Zm112-192L440-464v-216h80v184l128 128-56 56Z" fill="currentColor" stroke="none"/></symbol>
|
||||||
|
<symbol id="icon--hourglass" viewBox="0 -960 960 960"><path d="M320-160h320v-120q0-66-47-113t-113-47q-66 0-113 47t-47 113v120Zm160-360q66 0 113-47t47-113v-120H320v120q0 66 47 113t113 47ZM160-80v-80h80v-120q0-61 28.5-114.5T348-480q-51-32-79.5-85.5T240-680v-120h-80v-80h640v80h-80v120q0 61-28.5 114.5T612-480q51 32 79.5 85.5T720-280v120h80v80H160Zm320-80Zm0-640Z" fill="currentColor" stroke="none"/></symbol>
|
||||||
|
<symbol id="icon--import" viewBox="0 -960 960 960"><path d="M467-120q-73-1-136-14t-110-34.5q-47-21.5-74-50T120-280q0 33 27 61.5t74 50Q268-147 331-134t136 14Zm-15-200q-38-2-73.5-6.5t-67.5-12q-32-7.5-60-17.5t-51-23q23 13 51 23t60 17.5q32 7.5 67.5 12T452-320Zm28-279q89 0 179-26.5T760-679q-11-29-100.5-55T480-760q-91 0-178.5 25.5T200-679q14 27 101.5 53.5T480-599Zm220 479h40v-164l72 72 28-28-120-120-120 120 28 28 72-72v164Zm20 80q-83 0-141.5-58.5T520-240q0-83 58.5-141.5T720-440q83 0 141.5 58.5T920-240q0 83-58.5 141.5T720-40ZM443-201q3 22 9 42t15 39q-73-1-136-14t-110-34.5q-47-21.5-74-50T120-280v-400q0-66 105.5-113T480-840q149 0 254.5 47T840-680v187q-19-9-39-15t-41-9v-62q-52 29-124 44t-156 15q-85 0-157-15t-123-44v101q51 47 130.5 62.5T480-400h11q-13 18-22.5 38T452-320q-76-4-141-18.5T200-379v99q7 13 30 26.5t56 24q33 10.5 73.5 18T443-201Z" fill="currentColor" stroke="none"/></symbol>
|
||||||
|
<symbol id="icon--issue" viewBox="0 -960 960 960"><path d="M200-200h360v-200h200v-360H200v560Zm0 80q-33 0-56.5-23.5T120-200v-560q0-33 23.5-56.5T200-840h560q33 0 56.5 23.5T840-760v400L600-120H200Zm80-280v-80h200v80H280Zm0-160v-80h400v80H280Zm-80 360v-560 560Z" fill="currentColor" stroke="none"/></symbol>
|
||||||
|
<symbol id="icon--issue-closed" viewBox="0 -960 960 960"><path d="m424-312 282-282-56-56-226 226-114-114-56 56 170 170ZM200-120q-33 0-56.5-23.5T120-200v-560q0-33 23.5-56.5T200-840h560q33 0 56.5 23.5T840-760v560q0 33-23.5 56.5T760-120H200Zm0-80h560v-560H200v560Zm0-560v560-560Z" fill="currentColor" stroke="none"/></symbol>
|
||||||
|
<symbol id="icon--issue-edit" viewBox="0 -960 960 960"><path d="M200-120q-33 0-56.5-23.5T120-200v-560q0-33 23.5-56.5T200-840h357l-80 80H200v560h560v-278l80-80v358q0 33-23.5 56.5T760-120H200Zm280-360ZM360-360v-170l367-367q12-12 27-18t30-6q16 0 30.5 6t26.5 18l56 57q11 12 17 26.5t6 29.5q0 15-5.5 29.5T897-728L530-360H360Zm481-424-56-56 56 56ZM440-440h56l232-232-28-28-29-28-231 231v57Zm260-260-29-28 29 28 28 28-28-28Z" fill="currentColor" stroke="none"/></symbol>
|
||||||
|
<symbol id="icon--issue-note" viewBox="0 -960 960 960"><path d="M440-400h80v-120h120v-80H520v-120h-80v120H320v80h120v120ZM80-80v-720q0-33 23.5-56.5T160-880h640q33 0 56.5 23.5T880-800v480q0 33-23.5 56.5T800-240H240L80-80Zm126-240h594v-480H160v525l46-45Zm-46 0v-480 480Z" fill="currentColor" stroke="none"/></symbol>
|
||||||
|
<symbol id="icon--key" viewBox="0 -960 960 960"><path d="M280-400q-33 0-56.5-23.5T200-480q0-33 23.5-56.5T280-560q33 0 56.5 23.5T360-480q0 33-23.5 56.5T280-400Zm0 160q-100 0-170-70T40-480q0-100 70-170t170-70q67 0 121.5 33t86.5 87h352l120 120-180 180-80-60-80 60-85-60h-47q-32 54-86.5 87T280-240Zm0-80q56 0 98.5-34t56.5-86h125l58 41 82-61 71 55 75-75-40-40H435q-14-52-56.5-86T280-640q-66 0-113 47t-47 113q0 66 47 113t113 47Z" fill="currentColor" stroke="none"/></symbol>
|
||||||
|
<symbol id="icon--link" viewBox="0 -960 960 960"><path d="M440-280H280q-83 0-141.5-58.5T80-480q0-83 58.5-141.5T280-680h160v80H280q-50 0-85 35t-35 85q0 50 35 85t85 35h160v80ZM320-440v-80h320v80H320Zm200 160v-80h160q50 0 85-35t35-85q0-50-35-85t-85-35H520v-80h160q83 0 141.5 58.5T880-480q0 83-58.5 141.5T680-280H520Z" fill="currentColor" stroke="none"/></symbol>
|
||||||
|
<symbol id="icon--link-add" viewBox="0 -960 960 960"><path d="M680-160v-120H560v-80h120v-120h80v120h120v80H760v120h-80ZM440-280H280q-83 0-141.5-58.5T80-480q0-83 58.5-141.5T280-680h160v80H280q-50 0-85 35t-35 85q0 50 35 85t85 35h160v80ZM320-440v-80h320v80H320Zm560-40h-80q0-50-35-85t-85-35H520v-80h160q83 0 141.5 58.5T880-480Z" fill="currentColor" stroke="none"/></symbol>
|
||||||
|
<symbol id="icon--link-break" viewBox="0 -960 960 960"><path d="m770-302-60-62q40-11 65-42.5t25-73.5q0-50-35-85t-85-35H520v-80h160q83 0 141.5 58.5T880-480q0 57-29.5 105T770-302ZM634-440l-80-80h86v80h-6ZM792-56 56-792l56-56 736 736-56 56ZM440-280H280q-83 0-141.5-58.5T80-480q0-69 42-123t108-71l74 74h-24q-50 0-85 35t-35 85q0 50 35 85t85 35h160v80ZM320-440v-80h65l79 80H320Z" fill="currentColor" stroke="none"/></symbol>
|
||||||
|
<symbol id="icon--list" viewBox="0 -960 960 960"><path d="M280-600v-80h560v80H280Zm0 160v-80h560v80H280Zm0 160v-80h560v80H280ZM160-600q-17 0-28.5-11.5T120-640q0-17 11.5-28.5T160-680q17 0 28.5 11.5T200-640q0 17-11.5 28.5T160-600Zm0 160q-17 0-28.5-11.5T120-480q0-17 11.5-28.5T160-520q17 0 28.5 11.5T200-480q0 17-11.5 28.5T160-440Zm0 160q-17 0-28.5-11.5T120-320q0-17 11.5-28.5T160-360q17 0 28.5 11.5T200-320q0 17-11.5 28.5T160-280Z" fill="currentColor" stroke="none"/></symbol>
|
||||||
|
<symbol id="icon--loader" viewBox="0 -960 960 960"><path d="M480-80q-82 0-155-31.5t-127.5-86Q143-252 111.5-325T80-480q0-83 31.5-155.5t86-127Q252-817 325-848.5T480-880q17 0 28.5 11.5T520-840q0 17-11.5 28.5T480-800q-133 0-226.5 93.5T160-480q0 133 93.5 226.5T480-160q133 0 226.5-93.5T800-480q0-17 11.5-28.5T840-520q17 0 28.5 11.5T880-480q0 82-31.5 155t-86 127.5q-54.5 54.5-127 86T480-80Z" fill="currentColor" stroke="none"/></symbol>
|
||||||
|
<symbol id="icon--lock" viewBox="0 -960 960 960"><path d="M240-80q-33 0-56.5-23.5T160-160v-400q0-33 23.5-56.5T240-640h40v-80q0-83 58.5-141.5T480-920q83 0 141.5 58.5T680-720v80h40q33 0 56.5 23.5T800-560v400q0 33-23.5 56.5T720-80H240Zm0-80h480v-400H240v400Zm240-120q33 0 56.5-23.5T560-360q0-33-23.5-56.5T480-440q-33 0-56.5 23.5T400-360q0 33 23.5 56.5T480-280ZM360-640h240v-80q0-50-35-85t-85-35q-50 0-85 35t-35 85v80ZM240-160v-400 400Z" fill="currentColor" stroke="none"/></symbol>
|
||||||
|
<symbol id="icon--maximize" viewBox="0 -960 960 960"><path d="M120-120v-200h80v120h120v80H120Zm520 0v-80h120v-120h80v200H640ZM120-640v-200h200v80H200v120h-80Zm640 0v-120H640v-80h200v200h-80Z" fill="currentColor" stroke="none"/></symbol>
|
||||||
|
<symbol id="icon--message" viewBox="0 -960 960 960"><path d="M80-80v-720q0-33 23.5-56.5T160-880h640q33 0 56.5 23.5T880-800v480q0 33-23.5 56.5T800-240H240L80-80Zm126-240h594v-480H160v525l46-45Zm-46 0v-480 480Z" fill="currentColor" stroke="none"/></symbol>
|
||||||
|
<symbol id="icon--message-report" viewBox="0 -960 960 960"><path d="M480-360q17 0 28.5-11.5T520-400q0-17-11.5-28.5T480-440q-17 0-28.5 11.5T440-400q0 17 11.5 28.5T480-360Zm-40-160h80v-240h-80v240ZM80-80v-720q0-33 23.5-56.5T160-880h640q33 0 56.5 23.5T880-800v480q0 33-23.5 56.5T800-240H240L80-80Zm126-240h594v-480H160v525l46-45Zm-46 0v-480 480Z" fill="currentColor" stroke="none"/></symbol>
|
||||||
|
<symbol id="icon--move" viewBox="0 -960 960 960"><path d="M806-440H320v-80h486l-62-62 56-58 160 160-160 160-56-58 62-62ZM600-600v-160H200v560h400v-160h80v160q0 33-23.5 56.5T600-120H200q-33 0-56.5-23.5T120-200v-560q0-33 23.5-56.5T200-840h400q33 0 56.5 23.5T680-760v160h-80Z" fill="currentColor" stroke="none"/></symbol>
|
||||||
|
<symbol id="icon--movie" viewBox="0 -960 960 960"><path d="m160-800 80 160h120l-80-160h80l80 160h120l-80-160h80l80 160h120l-80-160h120q33 0 56.5 23.5T880-720v480q0 33-23.5 56.5T800-160H160q-33 0-56.5-23.5T80-240v-480q0-33 23.5-56.5T160-800Zm0 240v320h640v-320H160Zm0 0v320-320Z" fill="currentColor" stroke="none"/></symbol>
|
||||||
|
<symbol id="icon--news" viewBox="0 -960 960 960"><path d="M160-120q-33 0-56.5-23.5T80-200v-640l67 67 66-67 67 67 67-67 66 67 67-67 67 67 66-67 67 67 67-67 66 67 67-67v640q0 33-23.5 56.5T800-120H160Zm0-80h280v-240H160v240Zm360 0h280v-80H520v80Zm0-160h280v-80H520v80ZM160-520h640v-120H160v120Z" fill="currentColor" stroke="none"/></symbol>
|
||||||
|
<symbol id="icon--package" viewBox="0 -960 960 960"><path d="M440-183v-274L200-596v274l240 139Zm80 0 240-139v-274L520-457v274Zm-80 92L160-252q-19-11-29.5-29T120-321v-318q0-22 10.5-40t29.5-29l280-161q19-11 40-11t40 11l280 161q19 11 29.5 29t10.5 40v318q0 22-10.5 40T800-252L520-91q-19 11-40 11t-40-11Zm200-528 77-44-237-137-78 45 238 136Zm-160 93 78-45-237-137-78 45 237 137Z" fill="currentColor" stroke="none"/></symbol>
|
||||||
|
<symbol id="icon--photo" viewBox="0 -960 960 960"><path d="M200-120q-33 0-56.5-23.5T120-200v-560q0-33 23.5-56.5T200-840h560q33 0 56.5 23.5T840-760v560q0 33-23.5 56.5T760-120H200Zm0-80h560v-560H200v560Zm40-80h480L570-480 450-320l-90-120-120 160Zm-40 80v-560 560Z" fill="currentColor" stroke="none"/></symbol>
|
||||||
|
<symbol id="icon--plugins" viewBox="0 -960 960 960"><path d="M352-120H200q-33 0-56.5-23.5T120-200v-152q48 0 84-30.5t36-77.5q0-47-36-77.5T120-568v-152q0-33 23.5-56.5T200-800h160q0-42 29-71t71-29q42 0 71 29t29 71h160q33 0 56.5 23.5T800-720v160q42 0 71 29t29 71q0 42-29 71t-71 29v160q0 33-23.5 56.5T720-120H568q0-50-31.5-85T460-240q-45 0-76.5 35T352-120Zm-152-80h85q24-66 77-93t98-27q45 0 98 27t77 93h85v-240h80q8 0 14-6t6-14q0-8-6-14t-14-6h-80v-240H480v-80q0-8-6-14t-14-6q-8 0-14 6t-6 14v80H200v88q54 20 87 67t33 105q0 57-33 104t-87 68v88Zm260-260Z" fill="currentColor" stroke="none"/></symbol>
|
||||||
|
<symbol id="icon--project" viewBox="0 -960 960 960"><path d="M200-80q-33 0-56.5-23.5T120-160v-451q-18-11-29-28.5T80-680v-120q0-33 23.5-56.5T160-880h640q33 0 56.5 23.5T880-800v120q0 23-11 40.5T840-611v451q0 33-23.5 56.5T760-80H200Zm0-520v440h560v-440H200Zm-40-80h640v-120H160v120Zm200 280h240v-80H360v80Zm120 20Z" fill="currentColor" stroke="none"/></symbol>
|
||||||
|
<symbol id="icon--projects" viewBox="0 -960 960 960"><path d="M200-80q-33 0-56.5-23.5T120-160v-451q-18-11-29-28.5T80-680v-120q0-33 23.5-56.5T160-880h640q33 0 56.5 23.5T880-800v120q0 23-11 40.5T840-611v451q0 33-23.5 56.5T760-80H200Zm0-520v440h560v-440H200Zm-40-80h640v-120H160v120Zm200 280h240v-80H360v80Zm120 20Z" fill="currentColor" stroke="none"/></symbol>
|
||||||
|
<symbol id="icon--quote-filled" viewBox="0 -960 960 960"><path d="m228-240 92-160q-66 0-113-47t-47-113q0-66 47-113t113-47q66 0 113 47t47 113q0 23-5.5 42.5T458-480L320-240h-92Zm360 0 92-160q-66 0-113-47t-47-113q0-66 47-113t113-47q66 0 113 47t47 113q0 23-5.5 42.5T818-480L680-240h-92Z" fill="currentColor" stroke="none"/></symbol>
|
||||||
|
<symbol id="icon--reload" viewBox="0 -960 960 960"><path d="M480-160q-134 0-227-93t-93-227q0-134 93-227t227-93q69 0 132 28.5T720-690v-110h80v280H520v-80h168q-32-56-87.5-88T480-720q-100 0-170 70t-70 170q0 100 70 170t170 70q77 0 139-44t87-116h84q-28 106-114 173t-196 67Z" fill="currentColor" stroke="none"/></symbol>
|
||||||
|
<symbol id="icon--reorder" viewBox="0 -960 960 960"><path d="M120-200v-80h720v80H120Zm0-160v-80h720v80H120Zm0-160v-80h720v80H120Zm0-160v-80h720v80H120Z" fill="currentColor" stroke="none"/></symbol>
|
||||||
|
<symbol id="icon--reply" viewBox="0 -960 960 960"><path d="M760-200v-160q0-50-35-85t-85-35H273l144 144-57 56-240-240 240-240 57 56-144 144h367q83 0 141.5 58.5T840-360v160h-80Z" fill="currentColor" stroke="none"/></symbol>
|
||||||
|
<symbol id="icon--roles" viewBox="0 -960 960 960"><path d="M680-280q25 0 42.5-17.5T740-340q0-25-17.5-42.5T680-400q-25 0-42.5 17.5T620-340q0 25 17.5 42.5T680-280Zm0 120q31 0 57-14.5t42-38.5q-22-13-47-20t-52-7q-27 0-52 7t-47 20q16 24 42 38.5t57 14.5ZM480-80q-139-35-229.5-159.5T160-516v-244l320-120 320 120v227q-19-8-39-14.5t-41-9.5v-147l-240-90-240 90v188q0 47 12.5 94t35 89.5Q310-290 342-254t71 60q11 32 29 61t41 52q-1 0-1.5.5t-1.5.5Zm200 0q-83 0-141.5-58.5T480-280q0-83 58.5-141.5T680-480q83 0 141.5 58.5T880-280q0 83-58.5 141.5T680-80ZM480-494Z" fill="currentColor" stroke="none"/></symbol>
|
||||||
|
<symbol id="icon--save" viewBox="0 -960 960 960"><path d="M840-680v480q0 33-23.5 56.5T760-120H200q-33 0-56.5-23.5T120-200v-560q0-33 23.5-56.5T200-840h480l160 160Zm-80 34L646-760H200v560h560v-446ZM480-240q50 0 85-35t35-85q0-50-35-85t-85-35q-50 0-85 35t-35 85q0 50 35 85t85 35ZM240-560h360v-160H240v160Zm-40-86v446-560 114Z" fill="currentColor" stroke="none"/></symbol>
|
||||||
|
<symbol id="icon--search" viewBox="0 -960 960 960"><path d="M784-120 532-372q-30 24-69 38t-83 14q-109 0-184.5-75.5T120-580q0-109 75.5-184.5T380-840q109 0 184.5 75.5T640-580q0 44-14 83t-38 69l252 252-56 56ZM380-400q75 0 127.5-52.5T560-580q0-75-52.5-127.5T380-760q-75 0-127.5 52.5T200-580q0 75 52.5 127.5T380-400Z" fill="currentColor" stroke="none"/></symbol>
|
||||||
|
<symbol id="icon--server-authentication" viewBox="0 -960 960 960"><path d="M300-720q-25 0-42.5 17.5T240-660q0 25 17.5 42.5T300-600q25 0 42.5-17.5T360-660q0-25-17.5-42.5T300-720Zm0 400q-25 0-42.5 17.5T240-260q0 25 17.5 42.5T300-200q25 0 42.5-17.5T360-260q0-25-17.5-42.5T300-320ZM160-840h640q17 0 28.5 11.5T840-800v280q0 17-11.5 28.5T800-480H160q-17 0-28.5-11.5T120-520v-280q0-17 11.5-28.5T160-840Zm40 80v200h560v-200H200Zm-40 320h640q17 0 28.5 11.5T840-400v280q0 17-11.5 28.5T800-80H160q-17 0-28.5-11.5T120-120v-280q0-17 11.5-28.5T160-440Zm40 80v200h560v-200H200Zm0-400v200-200Zm0 400v200-200Z" fill="currentColor" stroke="none"/></symbol>
|
||||||
|
<symbol id="icon--settings" viewBox="0 -960 960 960"><path d="m370-80-16-128q-13-5-24.5-12T307-235l-119 50L78-375l103-78q-1-7-1-13.5v-27q0-6.5 1-13.5L78-585l110-190 119 50q11-8 23-15t24-12l16-128h220l16 128q13 5 24.5 12t22.5 15l119-50 110 190-103 78q1 7 1 13.5v27q0 6.5-2 13.5l103 78-110 190-118-50q-11 8-23 15t-24 12L590-80H370Zm70-80h79l14-106q31-8 57.5-23.5T639-327l99 41 39-68-86-65q5-14 7-29.5t2-31.5q0-16-2-31.5t-7-29.5l86-65-39-68-99 42q-22-23-48.5-38.5T533-694l-13-106h-79l-14 106q-31 8-57.5 23.5T321-633l-99-41-39 68 86 64q-5 15-7 30t-2 32q0 16 2 31t7 30l-86 65 39 68 99-42q22 23 48.5 38.5T427-266l13 106Zm42-180q58 0 99-41t41-99q0-58-41-99t-99-41q-59 0-99.5 41T342-480q0 58 40.5 99t99.5 41Zm-2-140Z" fill="currentColor" stroke="none"/></symbol>
|
||||||
|
<symbol id="icon--shield-check" viewBox="0 -960 960 960"><path d="m438-338 226-226-57-57-169 169-84-84-57 57 141 141Zm42 258q-139-35-229.5-159.5T160-516v-244l320-120 320 120v244q0 152-90.5 276.5T480-80Zm0-84q104-33 172-132t68-220v-189l-240-90-240 90v189q0 121 68 220t172 132Zm0-316Z" fill="currentColor" stroke="none"/></symbol>
|
||||||
|
<symbol id="icon--stats" viewBox="0 -960 960 960"><path d="M640-160v-280h160v280H640Zm-240 0v-640h160v640H400Zm-240 0v-440h160v440H160Z" fill="currentColor" stroke="none"/></symbol>
|
||||||
|
<symbol id="icon--summary" viewBox="0 -960 960 960"><path d="m422-232 207-248H469l29-227-185 267h139l-30 208ZM320-80l40-280H160l360-520h80l-40 320h240L400-80h-80Zm151-390Z" fill="currentColor" stroke="none"/></symbol>
|
||||||
|
<symbol id="icon--table-multiple" viewBox="0 -960 960 960"><path d="M480-160q-134 0-227-93t-93-227q0-134 93-227t227-93q69 0 132 28.5T720-690v-110h80v280H520v-80h168q-32-56-87.5-88T480-720q-100 0-170 70t-70 170q0 100 70 170t170 70q77 0 139-44t87-116h84q-28 106-114 173t-196 67Z" fill="currentColor" stroke="none"/></symbol>
|
||||||
|
<symbol id="icon--text-css" viewBox="0 -960 960 960"><path d="M420-360q-17 0-28.5-11.5T380-400v-40h60v20h80v-40H420q-17 0-28.5-11.5T380-500v-60q0-17 11.5-28.5T420-600h120q17 0 28.5 11.5T580-560v40h-60v-20h-80v40h100q17 0 28.5 11.5T580-460v60q0 17-11.5 28.5T540-360H420Zm260 0q-17 0-28.5-11.5T640-400v-40h60v20h80v-40H680q-17 0-28.5-11.5T640-500v-60q0-17 11.5-28.5T680-600h120q17 0 28.5 11.5T840-560v40h-60v-20h-80v40h100q17 0 28.5 11.5T840-460v60q0 17-11.5 28.5T800-360H680Zm-520 0q-17 0-28.5-11.5T120-400v-160q0-17 11.5-28.5T160-600h120q17 0 28.5 11.5T320-560v40h-60v-20h-80v120h80v-20h60v40q0 17-11.5 28.5T280-360H160Z" fill="currentColor" stroke="none"/></symbol>
|
||||||
|
<symbol id="icon--text-html" viewBox="0 -960 960 960"><path d="M0-360v-240h60v80h80v-80h60v240h-60v-100H60v100H0Zm310 0v-180h-70v-60h200v60h-70v180h-60Zm170 0v-200q0-17 11.5-28.5T520-600h180q17 0 28.5 11.5T740-560v200h-60v-180h-40v140h-60v-140h-40v180h-60Zm320 0v-240h60v180h100v60H800Z" fill="currentColor" stroke="none"/></symbol>
|
||||||
|
<symbol id="icon--text-plain" viewBox="0 -960 960 960"><path d="M320-240h320v-80H320v80Zm0-160h320v-80H320v80ZM240-80q-33 0-56.5-23.5T160-160v-640q0-33 23.5-56.5T240-880h320l240 240v480q0 33-23.5 56.5T720-80H240Zm280-520v-200H240v640h480v-440H520ZM240-800v200-200 640-640Z" fill="currentColor" stroke="none"/></symbol>
|
||||||
|
<symbol id="icon--text-x-c" viewBox="0 -960 960 960"><path d="m384-336 56-57-87-87 87-87-56-57-144 144 144 144Zm192 0 144-144-144-144-56 57 87 87-87 87 56 57ZM200-120q-33 0-56.5-23.5T120-200v-560q0-33 23.5-56.5T200-840h560q33 0 56.5 23.5T840-760v560q0 33-23.5 56.5T760-120H200Zm0-80h560v-560H200v560Zm0-560v560-560Z" fill="currentColor" stroke="none"/></symbol>
|
||||||
|
<symbol id="icon--text-x-csharp" viewBox="0 -960 960 960"><path d="m384-336 56-57-87-87 87-87-56-57-144 144 144 144Zm192 0 144-144-144-144-56 57 87 87-87 87 56 57ZM200-120q-33 0-56.5-23.5T120-200v-560q0-33 23.5-56.5T200-840h560q33 0 56.5 23.5T840-760v560q0 33-23.5 56.5T760-120H200Zm0-80h560v-560H200v560Zm0-560v560-560Z" fill="currentColor" stroke="none"/></symbol>
|
||||||
|
<symbol id="icon--text-x-java" viewBox="0 -960 960 960"><path d="m384-336 56-57-87-87 87-87-56-57-144 144 144 144Zm192 0 144-144-144-144-56 57 87 87-87 87 56 57ZM200-120q-33 0-56.5-23.5T120-200v-560q0-33 23.5-56.5T200-840h560q33 0 56.5 23.5T840-760v560q0 33-23.5 56.5T760-120H200Zm0-80h560v-560H200v560Zm0-560v560-560Z" fill="currentColor" stroke="none"/></symbol>
|
||||||
|
<symbol id="icon--text-x-php" viewBox="0 -960 960 960"><path d="M120-360v-240h140q24 0 42 18t18 42v40q0 24-18 42t-42 18h-80v80h-60Zm260 0v-240h60v80h80v-80h60v240h-60v-100h-80v100h-60Zm280 0v-240h140q24 0 42 18t18 42v40q0 24-18 42t-42 18h-80v80h-60ZM180-500h80v-40h-80v40Zm540 0h80v-40h-80v40Z" fill="currentColor" stroke="none"/></symbol>
|
||||||
|
<symbol id="icon--text-x-ruby" viewBox="0 -960 960 960"><path d="m384-336 56-57-87-87 87-87-56-57-144 144 144 144Zm192 0 144-144-144-144-56 57 87 87-87 87 56 57ZM200-120q-33 0-56.5-23.5T120-200v-560q0-33 23.5-56.5T200-840h560q33 0 56.5 23.5T840-760v560q0 33-23.5 56.5T760-120H200Zm0-80h560v-560H200v560Zm0-560v560-560Z" fill="currentColor" stroke="none"/></symbol>
|
||||||
|
<symbol id="icon--text-xml" viewBox="0 -960 960 960"><path d="M320-240 80-480l240-240 57 57-184 184 183 183-56 56Zm320 0-57-57 184-184-183-183 56-56 240 240-240 240Z" fill="currentColor" stroke="none"/></symbol>
|
||||||
|
<symbol id="icon--thumb-up" viewBox="0 -960 960 960"><path d="M720-120H280v-520l280-280 50 50q7 7 11.5 19t4.5 23v14l-44 174h258q32 0 56 24t24 56v80q0 7-2 15t-4 15L794-168q-9 20-30 34t-44 14Zm-360-80h360l120-280v-80H480l54-220-174 174v406Zm0-406v406-406Zm-80-34v80H160v360h120v80H80v-520h200Z" fill="currentColor" stroke="none"/></symbol>
|
||||||
|
<symbol id="icon--thumb-up-filled" viewBox="0 -960 960 960"><path d="M720-120H320v-520l280-280 50 50q7 7 11.5 19t4.5 23v14l-44 174h218q32 0 56 24t24 56v80q0 7-1.5 15t-4.5 15L794-168q-9 20-30 34t-44 14ZM240-640v520H80v-520h160Z" fill="currentColor" stroke="none"/></symbol>
|
||||||
|
<symbol id="icon--time" viewBox="0 -960 960 960"><path d="m612-292 56-56-148-148v-184h-80v216l172 172ZM480-80q-83 0-156-31.5T197-197q-54-54-85.5-127T80-480q0-83 31.5-156T197-763q54-54 127-85.5T480-880q83 0 156 31.5T763-763q54 54 85.5 127T880-480q0 83-31.5 156T763-197q-54 54-127 85.5T480-80Zm0-400Zm0 320q133 0 226.5-93.5T800-480q0-133-93.5-226.5T480-800q-133 0-226.5 93.5T160-480q0 133 93.5 226.5T480-160Z" fill="currentColor" stroke="none"/></symbol>
|
||||||
|
<symbol id="icon--time-add" viewBox="0 -960 960 960"><path d="M440-120q-75 0-140.5-28T185-225q-49-49-77-114.5T80-480q0-75 28-140.5T185-735q49-49 114.5-77T440-840q21 0 40.5 2.5T520-830v82q-20-6-39.5-9t-40.5-3q-118 0-199 81t-81 199q0 118 81 199t199 81q118 0 199-81t81-199q0-11-1-20t-3-20h82q2 11 2 20v20q0 75-28 140.5T695-225q-49 49-114.5 77T440-120Zm112-192L400-464v-216h80v184l128 128-56 56Zm168-288v-120H600v-80h120v-120h80v120h120v80H800v120h-80Z" fill="currentColor" stroke="none"/></symbol>
|
||||||
|
<symbol id="icon--toggle-minus" viewBox="0 -960 960 960"><path d="M280-440h400v-80H280v80Zm-80 320q-33 0-56.5-23.5T120-200v-560q0-33 23.5-56.5T200-840h560q33 0 56.5 23.5T840-760v560q0 33-23.5 56.5T760-120H200Zm0-80h560v-560H200v560Zm0-560v560-560Z" fill="currentColor" stroke="none"/></symbol>
|
||||||
|
<symbol id="icon--toggle-plus" viewBox="0 -960 960 960"><path d="M440-280h80v-160h160v-80H520v-160h-80v160H280v80h160v160ZM200-120q-33 0-56.5-23.5T120-200v-560q0-33 23.5-56.5T200-840h560q33 0 56.5 23.5T840-760v560q0 33-23.5 56.5T760-120H200Zm0-80h560v-560H200v560Zm0-560v560-560Z" fill="currentColor" stroke="none"/></symbol>
|
||||||
|
<symbol id="icon--unknown" viewBox="0 -960 960 960"><path d="M478-240q21 0 35.5-14.5T528-290q0-21-14.5-35.5T478-340q-21 0-35.5 14.5T428-290q0 21 14.5 35.5T478-240Zm-36-154h74q0-33 7.5-52t42.5-52q26-26 41-49.5t15-56.5q0-56-41-86t-97-30q-57 0-92.5 30T342-618l66 26q5-18 22.5-39t53.5-21q32 0 48 17.5t16 38.5q0 20-12 37.5T506-526q-44 39-54 59t-10 73Zm38 314q-83 0-156-31.5T197-197q-54-54-85.5-127T80-480q0-83 31.5-156T197-763q54-54 127-85.5T480-880q83 0 156 31.5T763-763q54 54 85.5 127T880-480q0 83-31.5 156T763-197q-54 54-127 85.5T480-80Zm0-80q134 0 227-93t93-227q0-134-93-227t-227-93q-134 0-227 93t-93 227q0 134 93 227t227 93Zm0-320Z" fill="currentColor" stroke="none"/></symbol>
|
||||||
|
<symbol id="icon--unlock" viewBox="0 -960 960 960"><path d="M240-640h360v-80q0-50-35-85t-85-35q-50 0-85 35t-35 85h-80q0-83 58.5-141.5T480-920q83 0 141.5 58.5T680-720v80h40q33 0 56.5 23.5T800-560v400q0 33-23.5 56.5T720-80H240q-33 0-56.5-23.5T160-160v-400q0-33 23.5-56.5T240-640Zm0 480h480v-400H240v400Zm240-120q33 0 56.5-23.5T560-360q0-33-23.5-56.5T480-440q-33 0-56.5 23.5T400-360q0 33 23.5 56.5T480-280ZM240-160v-400 400Z" fill="currentColor" stroke="none"/></symbol>
|
||||||
|
<symbol id="icon--unwatch" viewBox="0 -960 960 960"><path d="m644-428-58-58q9-47-27-88t-93-32l-58-58q17-8 34.5-12t37.5-4q75 0 127.5 52.5T660-500q0 20-4 37.5T644-428Zm128 126-58-56q38-29 67.5-63.5T832-500q-50-101-143.5-160.5T480-720q-29 0-57 4t-55 12l-62-62q41-17 84-25.5t90-8.5q151 0 269 83.5T920-500q-23 59-60.5 109.5T772-302Zm20 246L624-222q-35 11-70.5 16.5T480-200q-151 0-269-83.5T40-500q21-53 53-98.5t73-81.5L56-792l56-56 736 736-56 56ZM222-624q-29 26-53 57t-41 67q50 101 143.5 160.5T480-280q20 0 39-2.5t39-5.5l-36-38q-11 3-21 4.5t-21 1.5q-75 0-127.5-52.5T300-500q0-11 1.5-21t4.5-21l-84-82Zm319 93Zm-151 75Z" fill="currentColor" stroke="none"/></symbol>
|
||||||
|
<symbol id="icon--user" viewBox="0 -960 960 960"><path d="M480-480q-66 0-113-47t-47-113q0-66 47-113t113-47q66 0 113 47t47 113q0 66-47 113t-113 47ZM160-160v-112q0-34 17.5-62.5T224-378q62-31 126-46.5T480-440q66 0 130 15.5T736-378q29 15 46.5 43.5T800-272v112H160Zm80-80h480v-32q0-11-5.5-20T700-306q-54-27-109-40.5T480-360q-56 0-111 13.5T260-306q-9 5-14.5 14t-5.5 20v32Zm240-320q33 0 56.5-23.5T560-640q0-33-23.5-56.5T480-720q-33 0-56.5 23.5T400-640q0 33 23.5 56.5T480-560Zm0-80Zm0 400Z" fill="currentColor" stroke="none"/></symbol>
|
||||||
|
<symbol id="icon--warning" viewBox="0 -960 960 960"><path d="m40-120 440-760 440 760H40Zm138-80h604L480-720 178-200Zm302-40q17 0 28.5-11.5T520-280q0-17-11.5-28.5T480-320q-17 0-28.5 11.5T440-280q0 17 11.5 28.5T480-240Zm-40-120h80v-200h-80v200Zm40-100Z" fill="currentColor" stroke="none"/></symbol>
|
||||||
|
<symbol id="icon--watch" viewBox="0 -960 960 960"><path d="M480-320q75 0 127.5-52.5T660-500q0-75-52.5-127.5T480-680q-75 0-127.5 52.5T300-500q0 75 52.5 127.5T480-320Zm0-72q-45 0-76.5-31.5T372-500q0-45 31.5-76.5T480-608q45 0 76.5 31.5T588-500q0 45-31.5 76.5T480-392Zm0 192q-146 0-266-81.5T40-500q54-137 174-218.5T480-800q146 0 266 81.5T920-500q-54 137-174 218.5T480-200Zm0-300Zm0 220q113 0 207.5-59.5T832-500q-50-101-144.5-160.5T480-720q-113 0-207.5 59.5T128-500q50 101 144.5 160.5T480-280Z" fill="currentColor" stroke="none"/></symbol>
|
||||||
|
<symbol id="icon--webhook" viewBox="0 -960 960 960"><path d="M280-120q-83 0-141.5-58.5T80-320q0-73 45.5-127.5T240-516v83q-35 12-57.5 43T160-320q0 50 35 85t85 35q50 0 85-35t35-85v-40h235q8-9 19.5-14.5T680-380q25 0 42.5 17.5T740-320q0 25-17.5 42.5T680-260q-14 0-25.5-5.5T635-280H476q-14 69-68.5 114.5T280-120Zm400 0q-56 0-101.5-27.5T507-220h107q14 10 31 15t35 5q50 0 85-35t35-85q0-50-35-85t-85-35q-20 0-37 5.5T611-418L489-621q-21-4-35-20t-14-39q0-25 17.5-42.5T500-740q25 0 42.5 17.5T560-680v8.5q0 3.5-2 8.5l87 146q8-2 17-2.5t18-.5q83 0 141.5 58.5T880-320q0 83-58.5 141.5T680-120ZM280-260q-25 0-42.5-17.5T220-320q0-22 14-38t34-21l94-156q-29-27-45.5-64.5T300-680q0-83 58.5-141.5T500-880q83 0 141.5 58.5T700-680h-80q0-50-35-85t-85-35q-50 0-85 35t-35 85q0 43 26 75.5t66 41.5L337-338q2 5 2.5 9t.5 9q0 25-17.5 42.5T280-260Z" fill="currentColor" stroke="none"/></symbol>
|
||||||
|
<symbol id="icon--wiki-page" viewBox="0 -960 960 960"><path d="M280-280h280v-80H280v80Zm0-160h400v-80H280v80Zm0-160h400v-80H280v80Zm-80 480q-33 0-56.5-23.5T120-200v-560q0-33 23.5-56.5T200-840h560q33 0 56.5 23.5T840-760v560q0 33-23.5 56.5T760-120H200Zm0-80h560v-560H200v560Zm0-560v560-560Z" fill="currentColor" stroke="none"/></symbol>
|
||||||
|
<symbol id="icon--workflows" viewBox="0 -960 960 960"><path d="M600-120v-120H440v-400h-80v120H80v-320h280v120h240v-120h280v320H600v-120h-80v320h80v-120h280v320H600ZM160-760v160-160Zm520 400v160-160Zm0-400v160-160Zm0 160h120v-160H680v160Zm0 400h120v-160H680v160ZM160-600h120v-160H160v160Z" fill="currentColor" stroke="none"/></symbol>
|
||||||
|
<symbol id="icon--zoom-in" viewBox="0 -960 960 960"><path d="M784-120 532-372q-30 24-69 38t-83 14q-109 0-184.5-75.5T120-580q0-109 75.5-184.5T380-840q109 0 184.5 75.5T640-580q0 44-14 83t-38 69l252 252-56 56ZM380-400q75 0 127.5-52.5T560-580q0-75-52.5-127.5T380-760q-75 0-127.5 52.5T200-580q0 75 52.5 127.5T380-400Zm-40-60v-80h-80v-80h80v-80h80v80h80v80h-80v80h-80Z" fill="currentColor" stroke="none"/></symbol>
|
||||||
|
<symbol id="icon--zoom-out" viewBox="0 -960 960 960"><path d="M784-120 532-372q-30 24-69 38t-83 14q-109 0-184.5-75.5T120-580q0-109 75.5-184.5T380-840q109 0 184.5 75.5T640-580q0 44-14 83t-38 69l252 252-56 56ZM380-400q75 0 127.5-52.5T560-580q0-75-52.5-127.5T380-760q-75 0-127.5 52.5T200-580q0 75 52.5 127.5T380-400ZM280-540v-80h200v80H280Z" fill="currentColor" stroke="none"/></symbol>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 44 KiB |
@@ -0,0 +1 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 -960 960 960" width="24" height="24"><path d="M120-240v-80h720v80H120Zm0-200v-80h720v80H120Zm0-200v-80h720v80H120Z"/></svg>
|
||||||
|
After Width: | Height: | Size: 175 B |
@@ -0,0 +1 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 -960 960 960" width="24" height="24"><path fill="#cac4cf" d="M784-120 532-372q-30 24-69 38t-83 14q-109 0-184.5-75.5T120-580q0-109 75.5-184.5T380-840q109 0 184.5 75.5T640-580q0 44-14 83t-38 69l252 252-56 56ZM380-400q75 0 127.5-52.5T560-580q0-75-52.5-127.5T380-760q-75 0-127.5 52.5T200-580q0 75 52.5 127.5T380-400Z"/></svg>
|
||||||
|
After Width: | Height: | Size: 373 B |
@@ -0,0 +1 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 -960 960 960" width="24" height="24"><path fill="#49454e" d="M784-120 532-372q-30 24-69 38t-83 14q-109 0-184.5-75.5T120-580q0-109 75.5-184.5T380-840q109 0 184.5 75.5T640-580q0 44-14 83t-38 69l252 252-56 56ZM380-400q75 0 127.5-52.5T560-580q0-75-52.5-127.5T380-760q-75 0-127.5 52.5T200-580q0 75 52.5 127.5T380-400Z"/></svg>
|
||||||
|
After Width: | Height: | Size: 373 B |
@@ -0,0 +1,84 @@
|
|||||||
|
/*
|
||||||
|
* tonalmine: per-user appearance (mode + color palette).
|
||||||
|
*
|
||||||
|
* Redmine loads this file in <head>, so the saved choice is applied before the page renders
|
||||||
|
* (no flash of the default colors). The picker is added to the profile menu and the mobile
|
||||||
|
* flyout. The choice is stored per browser in localStorage.
|
||||||
|
*/
|
||||||
|
(function () {
|
||||||
|
// Ids must match PALETTES in tools/palettes/build_palettes.mjs (the build checks this).
|
||||||
|
var PALETTES = [
|
||||||
|
['purple', 'Purple', '#6750A4'],
|
||||||
|
['blue', 'Blue', '#0061A4'],
|
||||||
|
['teal', 'Teal', '#006A6A'],
|
||||||
|
['green', 'Green', '#386A20'],
|
||||||
|
['orange', 'Orange', '#8B5000']
|
||||||
|
];
|
||||||
|
var MODES = [['auto', 'Auto'], ['light', 'Light'], ['dark', 'Dark']];
|
||||||
|
var KEY = 'tonalmine';
|
||||||
|
var root = document.documentElement;
|
||||||
|
|
||||||
|
function load() {
|
||||||
|
try { return JSON.parse(localStorage.getItem(KEY)) || {}; } catch (e) { return {}; }
|
||||||
|
}
|
||||||
|
|
||||||
|
function save(prefs) {
|
||||||
|
try { localStorage.setItem(KEY, JSON.stringify(prefs)); } catch (e) { /* private mode: applies to this page only */ }
|
||||||
|
}
|
||||||
|
|
||||||
|
function apply(prefs) {
|
||||||
|
if (prefs.palette && prefs.palette !== PALETTES[0][0]) root.setAttribute('data-palette', prefs.palette);
|
||||||
|
else root.removeAttribute('data-palette');
|
||||||
|
if (prefs.mode === 'light' || prefs.mode === 'dark') root.setAttribute('data-mode', prefs.mode);
|
||||||
|
else root.removeAttribute('data-mode');
|
||||||
|
}
|
||||||
|
|
||||||
|
var prefs = load();
|
||||||
|
apply(prefs);
|
||||||
|
|
||||||
|
function button(attr, value, label, pressed, extra) {
|
||||||
|
return '<button type="button" ' + attr + '="' + value + '" aria-pressed="' + pressed + '"' + (extra || '') + '>' + label + '</button>';
|
||||||
|
}
|
||||||
|
|
||||||
|
function pickerHtml() {
|
||||||
|
var mode = prefs.mode || 'auto';
|
||||||
|
var palette = prefs.palette || PALETTES[0][0];
|
||||||
|
return '<div class="nm-appearance">' +
|
||||||
|
'<div class="nm-appearance__title">Appearance</div>' +
|
||||||
|
'<div class="nm-segmented" role="group" aria-label="Mode">' +
|
||||||
|
MODES.map(function (m) { return button('data-nm-mode', m[0], m[1], m[0] === mode); }).join('') +
|
||||||
|
'</div>' +
|
||||||
|
'<div class="nm-swatches" role="group" aria-label="Color">' +
|
||||||
|
PALETTES.map(function (p) {
|
||||||
|
return button('data-nm-palette', p[0], '', p[0] === palette,
|
||||||
|
' class="nm-swatch" title="' + p[1] + '" aria-label="' + p[1] + '" style="--nm-swatch: ' + p[2] + '"');
|
||||||
|
}).join('') +
|
||||||
|
'</div></div>';
|
||||||
|
}
|
||||||
|
|
||||||
|
function sync() {
|
||||||
|
document.querySelectorAll('[data-nm-mode]').forEach(function (b) {
|
||||||
|
b.setAttribute('aria-pressed', String(b.getAttribute('data-nm-mode') === (prefs.mode || 'auto')));
|
||||||
|
});
|
||||||
|
document.querySelectorAll('[data-nm-palette]').forEach(function (b) {
|
||||||
|
b.setAttribute('aria-pressed', String(b.getAttribute('data-nm-palette') === (prefs.palette || PALETTES[0][0])));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
document.addEventListener('click', function (event) {
|
||||||
|
var target = event.target.closest('[data-nm-mode], [data-nm-palette]');
|
||||||
|
if (!target) return;
|
||||||
|
if (target.hasAttribute('data-nm-mode')) prefs.mode = target.getAttribute('data-nm-mode');
|
||||||
|
else prefs.palette = target.getAttribute('data-nm-palette');
|
||||||
|
save(prefs);
|
||||||
|
apply(prefs);
|
||||||
|
sync();
|
||||||
|
});
|
||||||
|
|
||||||
|
document.addEventListener('DOMContentLoaded', function () {
|
||||||
|
var menu = document.querySelector('#account .dropdown-content .dropdown-divider');
|
||||||
|
if (menu) menu.insertAdjacentHTML('afterend', pickerHtml() + '<div class="dropdown-divider"></div>');
|
||||||
|
var flyout = document.querySelector('.js-flyout-menu');
|
||||||
|
if (flyout) flyout.insertAdjacentHTML('beforeend', pickerHtml());
|
||||||
|
});
|
||||||
|
})();
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
/* tonalmine: Material Design 3 theme for Redmine 7.0 */
|
||||||
|
@import url(/application.css);
|
||||||
|
@import url(./tokens.css);
|
||||||
|
@import url(./palettes.css);
|
||||||
|
@import url(./bridge.css);
|
||||||
|
@import url(./base.css);
|
||||||
|
@import url(./layout.css);
|
||||||
|
@import url(./components.css);
|
||||||
|
@import url(./tables.css);
|
||||||
|
@import url(./pages.css);
|
||||||
|
@import url(./typography.css);
|
||||||
|
@import url(./mobile.css);
|
||||||
@@ -0,0 +1,47 @@
|
|||||||
|
@font-face {
|
||||||
|
font-family: Roboto;
|
||||||
|
font-style: normal;
|
||||||
|
font-display: swap;
|
||||||
|
font-weight: 100 900;
|
||||||
|
src: url(../fonts/roboto-latin-ext-wght-normal.woff2) format("woff2");
|
||||||
|
unicode-range: U+0100-02BA,U+02BD-02C5,U+02C7-02CC,U+02CE-02D7,U+02DD-02FF,U+0304,U+0308,U+0329,U+1D00-1DBF,U+1E00-1E9F,U+1EF2-1EFF,U+2020,U+20A0-20AB,U+20AD-20C0,U+2113,U+2C60-2C7F,U+A720-A7FF;
|
||||||
|
}
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: Roboto;
|
||||||
|
font-style: normal;
|
||||||
|
font-display: swap;
|
||||||
|
font-weight: 100 900;
|
||||||
|
src: url(../fonts/roboto-latin-wght-normal.woff2) format("woff2");
|
||||||
|
unicode-range: U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD;
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
background-color: var(--md-sys-color-surface);
|
||||||
|
color: var(--md-sys-color-on-surface);
|
||||||
|
font: var(--md-sys-typescale-body-medium);
|
||||||
|
letter-spacing: var(--md-sys-typescale-body-medium-tracking);
|
||||||
|
}
|
||||||
|
|
||||||
|
::selection {
|
||||||
|
background-color: var(--md-sys-color-primary-container);
|
||||||
|
color: var(--md-sys-color-on-primary-container);
|
||||||
|
}
|
||||||
|
|
||||||
|
:focus-visible {
|
||||||
|
outline: 2px solid var(--md-sys-color-primary);
|
||||||
|
outline-offset: 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
a, a:link, a:visited { color: var(--md-sys-color-primary); }
|
||||||
|
a:hover, a:active { color: var(--md-sys-color-primary); text-decoration: underline; }
|
||||||
|
|
||||||
|
h1, h2, h3, h4, h5, h6,
|
||||||
|
#content h1, #content h2, #content h3, #content h4, #content h5, #content h6 {
|
||||||
|
color: var(--md-sys-color-on-surface);
|
||||||
|
font-family: var(--md-ref-typeface-plain);
|
||||||
|
}
|
||||||
|
|
||||||
|
h2, #content h2 { font: var(--md-sys-typescale-headline-small); }
|
||||||
|
h3, #content h3 { font: var(--md-sys-typescale-title-large); }
|
||||||
|
h4, #content h4 { font: var(--md-sys-typescale-title-small); letter-spacing: var(--md-sys-typescale-title-small-tracking); }
|
||||||
@@ -0,0 +1,139 @@
|
|||||||
|
/*
|
||||||
|
* Maps Redmine 7 core variables (open-color --oc-*, --fonts-main, --color-*) to M3 roles.
|
||||||
|
* Core CSS uses these ~330 times, so this file recolors most of Redmine, and because
|
||||||
|
* the roles switch per palette and mode (palettes.css), all of Redmine follows.
|
||||||
|
*
|
||||||
|
* Ramp per color family (index 0-9): 0-2 light containers, 3-5 mid tones for
|
||||||
|
* borders, 6-9 the strong role color used for text and icons.
|
||||||
|
* --oc-white is used both as background and as text on strong colors; both work with
|
||||||
|
* surface-container-lowest because strong colors are light in dark mode.
|
||||||
|
*/
|
||||||
|
|
||||||
|
:root {
|
||||||
|
--fonts-main: var(--md-ref-typeface-plain);
|
||||||
|
--color-current-marker: var(--md-sys-color-primary);
|
||||||
|
|
||||||
|
--oc-white: var(--md-sys-color-surface-container-lowest);
|
||||||
|
--oc-black: var(--md-sys-color-inverse-surface);
|
||||||
|
|
||||||
|
--oc-gray-0: var(--md-sys-color-surface-container-low);
|
||||||
|
--oc-gray-1: var(--md-sys-color-surface-container);
|
||||||
|
--oc-gray-2: var(--md-sys-color-surface-container-high);
|
||||||
|
--oc-gray-3: var(--md-sys-color-surface-container-highest);
|
||||||
|
--oc-gray-4: var(--md-sys-color-outline-variant);
|
||||||
|
--oc-gray-5: var(--md-sys-color-outline);
|
||||||
|
--oc-gray-6: var(--md-sys-color-on-surface-variant);
|
||||||
|
--oc-gray-7: var(--md-sys-color-on-surface-variant);
|
||||||
|
--oc-gray-8: var(--md-sys-color-on-surface);
|
||||||
|
--oc-gray-9: var(--md-sys-color-on-surface);
|
||||||
|
|
||||||
|
--oc-blue-0: color-mix(in srgb, var(--md-sys-color-primary-container) 35%, var(--md-sys-color-surface));
|
||||||
|
--oc-blue-1: color-mix(in srgb, var(--md-sys-color-primary-container) 65%, var(--md-sys-color-surface));
|
||||||
|
--oc-blue-2: var(--md-sys-color-primary-container);
|
||||||
|
--oc-blue-3: color-mix(in srgb, var(--md-sys-color-primary) 35%, var(--md-sys-color-primary-container));
|
||||||
|
--oc-blue-4: color-mix(in srgb, var(--md-sys-color-primary) 60%, var(--md-sys-color-primary-container));
|
||||||
|
--oc-blue-5: color-mix(in srgb, var(--md-sys-color-primary) 80%, var(--md-sys-color-primary-container));
|
||||||
|
--oc-blue-6: var(--md-sys-color-primary);
|
||||||
|
--oc-blue-7: var(--md-sys-color-primary);
|
||||||
|
--oc-blue-8: var(--md-sys-color-primary);
|
||||||
|
--oc-blue-9: var(--md-sys-color-primary);
|
||||||
|
|
||||||
|
--oc-indigo-0: color-mix(in srgb, var(--md-sys-color-primary-container) 35%, var(--md-sys-color-surface));
|
||||||
|
--oc-indigo-1: color-mix(in srgb, var(--md-sys-color-primary-container) 65%, var(--md-sys-color-surface));
|
||||||
|
--oc-indigo-2: var(--md-sys-color-primary-container);
|
||||||
|
--oc-indigo-3: color-mix(in srgb, var(--md-sys-color-primary) 35%, var(--md-sys-color-primary-container));
|
||||||
|
--oc-indigo-4: color-mix(in srgb, var(--md-sys-color-primary) 60%, var(--md-sys-color-primary-container));
|
||||||
|
--oc-indigo-5: color-mix(in srgb, var(--md-sys-color-primary) 80%, var(--md-sys-color-primary-container));
|
||||||
|
--oc-indigo-6: var(--md-sys-color-primary);
|
||||||
|
--oc-indigo-7: var(--md-sys-color-primary);
|
||||||
|
--oc-indigo-8: var(--md-sys-color-primary);
|
||||||
|
--oc-indigo-9: var(--md-sys-color-primary);
|
||||||
|
|
||||||
|
--oc-cyan-0: color-mix(in srgb, var(--md-sys-color-primary-container) 35%, var(--md-sys-color-surface));
|
||||||
|
--oc-cyan-1: color-mix(in srgb, var(--md-sys-color-primary-container) 65%, var(--md-sys-color-surface));
|
||||||
|
--oc-cyan-2: var(--md-sys-color-primary-container);
|
||||||
|
--oc-cyan-3: color-mix(in srgb, var(--md-sys-color-primary) 35%, var(--md-sys-color-primary-container));
|
||||||
|
--oc-cyan-4: color-mix(in srgb, var(--md-sys-color-primary) 60%, var(--md-sys-color-primary-container));
|
||||||
|
--oc-cyan-5: color-mix(in srgb, var(--md-sys-color-primary) 80%, var(--md-sys-color-primary-container));
|
||||||
|
--oc-cyan-6: var(--md-sys-color-primary);
|
||||||
|
--oc-cyan-7: var(--md-sys-color-primary);
|
||||||
|
--oc-cyan-8: var(--md-sys-color-primary);
|
||||||
|
--oc-cyan-9: var(--md-sys-color-primary);
|
||||||
|
|
||||||
|
--oc-violet-0: color-mix(in srgb, var(--md-sys-color-primary-container) 35%, var(--md-sys-color-surface));
|
||||||
|
--oc-violet-1: color-mix(in srgb, var(--md-sys-color-primary-container) 65%, var(--md-sys-color-surface));
|
||||||
|
--oc-violet-2: var(--md-sys-color-primary-container);
|
||||||
|
--oc-violet-3: color-mix(in srgb, var(--md-sys-color-primary) 35%, var(--md-sys-color-primary-container));
|
||||||
|
--oc-violet-4: color-mix(in srgb, var(--md-sys-color-primary) 60%, var(--md-sys-color-primary-container));
|
||||||
|
--oc-violet-5: color-mix(in srgb, var(--md-sys-color-primary) 80%, var(--md-sys-color-primary-container));
|
||||||
|
--oc-violet-6: var(--md-sys-color-primary);
|
||||||
|
--oc-violet-7: var(--md-sys-color-primary);
|
||||||
|
--oc-violet-8: var(--md-sys-color-primary);
|
||||||
|
--oc-violet-9: var(--md-sys-color-primary);
|
||||||
|
|
||||||
|
--oc-grape-0: color-mix(in srgb, var(--md-sys-color-primary-container) 35%, var(--md-sys-color-surface));
|
||||||
|
--oc-grape-1: color-mix(in srgb, var(--md-sys-color-primary-container) 65%, var(--md-sys-color-surface));
|
||||||
|
--oc-grape-2: var(--md-sys-color-primary-container);
|
||||||
|
--oc-grape-3: color-mix(in srgb, var(--md-sys-color-primary) 35%, var(--md-sys-color-primary-container));
|
||||||
|
--oc-grape-4: color-mix(in srgb, var(--md-sys-color-primary) 60%, var(--md-sys-color-primary-container));
|
||||||
|
--oc-grape-5: color-mix(in srgb, var(--md-sys-color-primary) 80%, var(--md-sys-color-primary-container));
|
||||||
|
--oc-grape-6: var(--md-sys-color-primary);
|
||||||
|
--oc-grape-7: var(--md-sys-color-primary);
|
||||||
|
--oc-grape-8: var(--md-sys-color-primary);
|
||||||
|
--oc-grape-9: var(--md-sys-color-primary);
|
||||||
|
|
||||||
|
--oc-pink-0: color-mix(in srgb, var(--md-sys-color-tertiary-container) 35%, var(--md-sys-color-surface));
|
||||||
|
--oc-pink-1: color-mix(in srgb, var(--md-sys-color-tertiary-container) 65%, var(--md-sys-color-surface));
|
||||||
|
--oc-pink-2: var(--md-sys-color-tertiary-container);
|
||||||
|
--oc-pink-3: color-mix(in srgb, var(--md-sys-color-tertiary) 35%, var(--md-sys-color-tertiary-container));
|
||||||
|
--oc-pink-4: color-mix(in srgb, var(--md-sys-color-tertiary) 60%, var(--md-sys-color-tertiary-container));
|
||||||
|
--oc-pink-5: color-mix(in srgb, var(--md-sys-color-tertiary) 80%, var(--md-sys-color-tertiary-container));
|
||||||
|
--oc-pink-6: var(--md-sys-color-tertiary);
|
||||||
|
--oc-pink-7: var(--md-sys-color-tertiary);
|
||||||
|
--oc-pink-8: var(--md-sys-color-tertiary);
|
||||||
|
--oc-pink-9: var(--md-sys-color-tertiary);
|
||||||
|
|
||||||
|
--oc-red-0: color-mix(in srgb, var(--md-sys-color-error-container) 35%, var(--md-sys-color-surface));
|
||||||
|
--oc-red-1: color-mix(in srgb, var(--md-sys-color-error-container) 65%, var(--md-sys-color-surface));
|
||||||
|
--oc-red-2: var(--md-sys-color-error-container);
|
||||||
|
--oc-red-3: color-mix(in srgb, var(--md-sys-color-error) 35%, var(--md-sys-color-error-container));
|
||||||
|
--oc-red-4: color-mix(in srgb, var(--md-sys-color-error) 60%, var(--md-sys-color-error-container));
|
||||||
|
--oc-red-5: color-mix(in srgb, var(--md-sys-color-error) 80%, var(--md-sys-color-error-container));
|
||||||
|
--oc-red-6: var(--md-sys-color-error);
|
||||||
|
--oc-red-7: var(--md-sys-color-error);
|
||||||
|
--oc-red-8: var(--md-sys-color-error);
|
||||||
|
--oc-red-9: var(--md-sys-color-error);
|
||||||
|
|
||||||
|
--oc-green-0: color-mix(in srgb, var(--md-sys-color-success-container) 35%, var(--md-sys-color-surface));
|
||||||
|
--oc-green-1: color-mix(in srgb, var(--md-sys-color-success-container) 65%, var(--md-sys-color-surface));
|
||||||
|
--oc-green-2: var(--md-sys-color-success-container);
|
||||||
|
--oc-green-3: color-mix(in srgb, var(--md-sys-color-success) 35%, var(--md-sys-color-success-container));
|
||||||
|
--oc-green-4: color-mix(in srgb, var(--md-sys-color-success) 60%, var(--md-sys-color-success-container));
|
||||||
|
--oc-green-5: color-mix(in srgb, var(--md-sys-color-success) 80%, var(--md-sys-color-success-container));
|
||||||
|
--oc-green-6: var(--md-sys-color-success);
|
||||||
|
--oc-green-7: var(--md-sys-color-success);
|
||||||
|
--oc-green-8: var(--md-sys-color-success);
|
||||||
|
--oc-green-9: var(--md-sys-color-success);
|
||||||
|
|
||||||
|
--oc-yellow-0: color-mix(in srgb, var(--md-sys-color-warning-container) 35%, var(--md-sys-color-surface));
|
||||||
|
--oc-yellow-1: color-mix(in srgb, var(--md-sys-color-warning-container) 65%, var(--md-sys-color-surface));
|
||||||
|
--oc-yellow-2: var(--md-sys-color-warning-container);
|
||||||
|
--oc-yellow-3: color-mix(in srgb, var(--md-sys-color-warning) 35%, var(--md-sys-color-warning-container));
|
||||||
|
--oc-yellow-4: color-mix(in srgb, var(--md-sys-color-warning) 60%, var(--md-sys-color-warning-container));
|
||||||
|
--oc-yellow-5: color-mix(in srgb, var(--md-sys-color-warning) 80%, var(--md-sys-color-warning-container));
|
||||||
|
--oc-yellow-6: var(--md-sys-color-warning);
|
||||||
|
--oc-yellow-7: var(--md-sys-color-warning);
|
||||||
|
--oc-yellow-8: var(--md-sys-color-warning);
|
||||||
|
--oc-yellow-9: var(--md-sys-color-warning);
|
||||||
|
|
||||||
|
--oc-orange-0: color-mix(in srgb, var(--md-sys-color-warning-container) 35%, var(--md-sys-color-surface));
|
||||||
|
--oc-orange-1: color-mix(in srgb, var(--md-sys-color-warning-container) 65%, var(--md-sys-color-surface));
|
||||||
|
--oc-orange-2: var(--md-sys-color-warning-container);
|
||||||
|
--oc-orange-3: color-mix(in srgb, var(--md-sys-color-warning) 35%, var(--md-sys-color-warning-container));
|
||||||
|
--oc-orange-4: color-mix(in srgb, var(--md-sys-color-warning) 60%, var(--md-sys-color-warning-container));
|
||||||
|
--oc-orange-5: color-mix(in srgb, var(--md-sys-color-warning) 80%, var(--md-sys-color-warning-container));
|
||||||
|
--oc-orange-6: var(--md-sys-color-warning);
|
||||||
|
--oc-orange-7: var(--md-sys-color-warning);
|
||||||
|
--oc-orange-8: var(--md-sys-color-warning);
|
||||||
|
--oc-orange-9: var(--md-sys-color-warning);
|
||||||
|
}
|
||||||
@@ -0,0 +1,557 @@
|
|||||||
|
/*
|
||||||
|
* Components: buttons, text fields, cards/boxes, banners, tabs, badges,
|
||||||
|
* pagination, progress, tooltips, dialogs, date picker, autocomplete.
|
||||||
|
* Uses --nm-state-* from layout.css.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/***** Buttons *****/
|
||||||
|
input[type="submit"], input[type="button"], input[type="reset"], button[type="submit"] {
|
||||||
|
block-size: 40px;
|
||||||
|
padding-block: 0;
|
||||||
|
padding-inline: 24px;
|
||||||
|
margin-block: 4px;
|
||||||
|
border: 1px solid var(--md-sys-color-outline);
|
||||||
|
border-radius: var(--md-sys-shape-corner-full);
|
||||||
|
background-color: transparent;
|
||||||
|
color: var(--md-sys-color-primary);
|
||||||
|
font: var(--md-sys-typescale-label-large);
|
||||||
|
letter-spacing: var(--md-sys-typescale-label-large-tracking);
|
||||||
|
cursor: pointer;
|
||||||
|
transition: var(--nm-transition), box-shadow var(--md-sys-motion-duration-short4) var(--md-sys-motion-easing-standard);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Filled: the main action of a form */
|
||||||
|
input[type="submit"], button[type="submit"] {
|
||||||
|
border-color: transparent;
|
||||||
|
background-color: var(--md-sys-color-primary);
|
||||||
|
color: var(--md-sys-color-on-primary);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Tonal: "Create and continue" and similar secondary submits */
|
||||||
|
input[type="submit"][name="continue"], input[type="submit"][name="follow"] {
|
||||||
|
background-color: var(--md-sys-color-secondary-container);
|
||||||
|
color: var(--md-sys-color-on-secondary-container);
|
||||||
|
}
|
||||||
|
|
||||||
|
input[type="submit"]:hover, input[type="button"]:hover, input[type="reset"]:hover, button[type="submit"]:hover {
|
||||||
|
background-image: var(--nm-state-hover);
|
||||||
|
}
|
||||||
|
input[type="submit"]:hover, button[type="submit"]:hover { background-color: var(--md-sys-color-primary); box-shadow: var(--md-sys-elevation-level1); }
|
||||||
|
input[type="submit"][name="continue"]:hover, input[type="submit"][name="follow"]:hover { background-color: var(--md-sys-color-secondary-container); }
|
||||||
|
input[type="submit"]:active, input[type="button"]:active, button[type="submit"]:active { background-image: var(--nm-state-pressed); box-shadow: none; }
|
||||||
|
|
||||||
|
input[type="submit"]:disabled, input[type="button"]:disabled, button:disabled {
|
||||||
|
background-color: color-mix(in srgb, var(--md-sys-color-on-surface) var(--md-sys-state-disabled-container-opacity), transparent);
|
||||||
|
border-color: transparent;
|
||||||
|
color: color-mix(in srgb, var(--md-sys-color-on-surface) var(--md-sys-state-disabled-content-opacity), transparent);
|
||||||
|
box-shadow: none;
|
||||||
|
cursor: default;
|
||||||
|
}
|
||||||
|
|
||||||
|
/***** Text fields (outlined) *****/
|
||||||
|
input[type="text"], input[type="password"], input[type="email"], input[type="url"], input[type="number"],
|
||||||
|
input[type="date"], input[type="search"], input[type="tel"], input:not([type]), select, textarea {
|
||||||
|
min-block-size: 40px;
|
||||||
|
padding-block: 8px;
|
||||||
|
padding-inline: 12px;
|
||||||
|
border: 1px solid var(--md-sys-color-outline);
|
||||||
|
border-radius: var(--md-sys-shape-corner-extra-small);
|
||||||
|
background-color: transparent;
|
||||||
|
color: var(--md-sys-color-on-surface);
|
||||||
|
font: var(--md-sys-typescale-body-medium);
|
||||||
|
letter-spacing: var(--md-sys-typescale-body-medium-tracking);
|
||||||
|
transition: border-color var(--md-sys-motion-duration-short4) var(--md-sys-motion-easing-standard);
|
||||||
|
}
|
||||||
|
input[type="text"]:hover, input[type="password"]:hover, input[type="email"]:hover, input[type="url"]:hover,
|
||||||
|
input[type="number"]:hover, input[type="date"]:hover, input[type="search"]:hover, select:hover, textarea:hover {
|
||||||
|
border-color: var(--md-sys-color-on-surface);
|
||||||
|
}
|
||||||
|
input[type="text"]:focus, input[type="text"]:active,
|
||||||
|
input[type="password"]:focus, input[type="password"]:active,
|
||||||
|
input[type="email"]:focus, input[type="url"]:focus, input[type="search"]:focus,
|
||||||
|
input[type="date"]:focus, input[type="date"]:active,
|
||||||
|
input[type="number"]:focus, input[type="number"]:active,
|
||||||
|
select:focus, select:active,
|
||||||
|
textarea:focus, textarea:active {
|
||||||
|
border-color: var(--md-sys-color-primary);
|
||||||
|
outline: 1px solid var(--md-sys-color-primary); /* 1px border + 1px outline = M3's 2px focused outline without layout shift */
|
||||||
|
outline-offset: -2px;
|
||||||
|
}
|
||||||
|
select {
|
||||||
|
background-color: transparent;
|
||||||
|
background-image: url(../images/arrow-drop-down.svg);
|
||||||
|
background-position: calc(100% - 6px) 50%;
|
||||||
|
background-size: 24px;
|
||||||
|
padding-inline-end: 32px;
|
||||||
|
}
|
||||||
|
[dir="rtl"] select { background-position: 6px 50%; }
|
||||||
|
/* The chevron is an image, so it cannot use color roles: one file per mode */
|
||||||
|
:root[data-mode="dark"] select { background-image: url(../images/arrow-drop-down-dark.svg); }
|
||||||
|
@media (prefers-color-scheme: dark) { :root:not([data-mode="light"]) select { background-image: url(../images/arrow-drop-down-dark.svg); } }
|
||||||
|
/* Autocomplete fields (parent task, watchers): M3 leading search icon, same per-mode files */
|
||||||
|
input.autocomplete {
|
||||||
|
background: transparent url(../images/search.svg) no-repeat 12px 50% / 20px;
|
||||||
|
padding-inline-start: 40px !important; /* core sets 20px with !important */
|
||||||
|
}
|
||||||
|
[dir="rtl"] input.autocomplete { background-position: calc(100% - 12px) 50%; }
|
||||||
|
/* :where() keeps the mode swap at the base rule's specificity, so core's own cases still win:
|
||||||
|
the jump box search (own icon, no background) and the ajax-loading spinner */
|
||||||
|
:where(:root[data-mode="dark"]) input.autocomplete { background-image: url(../images/search-dark.svg); }
|
||||||
|
@media (prefers-color-scheme: dark) { :where(:root:not([data-mode="light"])) input.autocomplete { background-image: url(../images/search-dark.svg); } }
|
||||||
|
select[multiple] { background-image: none; padding-inline-end: 12px; }
|
||||||
|
input::placeholder, textarea::placeholder { color: var(--md-sys-color-on-surface-variant); opacity: 1; }
|
||||||
|
input[type="checkbox"], input[type="radio"] { accent-color: var(--md-sys-color-primary); }
|
||||||
|
input[type="file"] { color: var(--md-sys-color-on-surface-variant); }
|
||||||
|
input[type="file"]::file-selector-button {
|
||||||
|
block-size: 40px;
|
||||||
|
margin-inline-end: 12px;
|
||||||
|
padding-inline: 24px;
|
||||||
|
border: 0;
|
||||||
|
border-radius: var(--md-sys-shape-corner-full);
|
||||||
|
background-color: var(--md-sys-color-secondary-container);
|
||||||
|
color: var(--md-sys-color-on-secondary-container);
|
||||||
|
font: var(--md-sys-typescale-label-large);
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
input:disabled, select:disabled, textarea:disabled {
|
||||||
|
border-color: color-mix(in srgb, var(--md-sys-color-on-surface) var(--md-sys-state-disabled-container-opacity), transparent);
|
||||||
|
color: color-mix(in srgb, var(--md-sys-color-on-surface) var(--md-sys-state-disabled-content-opacity), transparent);
|
||||||
|
}
|
||||||
|
|
||||||
|
/***** Cards: .box, tabular forms, fieldsets *****/
|
||||||
|
.box {
|
||||||
|
padding: 16px;
|
||||||
|
margin-block-end: 16px;
|
||||||
|
background-color: var(--md-sys-color-surface-container-low);
|
||||||
|
color: var(--md-sys-color-on-surface);
|
||||||
|
border: 0;
|
||||||
|
border-radius: var(--md-sys-shape-corner-medium);
|
||||||
|
line-height: 1.5;
|
||||||
|
}
|
||||||
|
/* M3 has no legend notched into a border. A fieldset on its own is a filled card with the
|
||||||
|
legend as headline inside. A fieldset inside a card or form, and a collapsible one, is a
|
||||||
|
section: a full-width divider with the legend as subheader below it (M3 divider guidance). */
|
||||||
|
fieldset {
|
||||||
|
padding: 16px;
|
||||||
|
margin-block-end: 16px;
|
||||||
|
border: 0;
|
||||||
|
border-radius: var(--md-sys-shape-corner-medium);
|
||||||
|
background-color: var(--md-sys-color-surface-container-low);
|
||||||
|
}
|
||||||
|
:is(.box, fieldset) fieldset, fieldset.collapsible:not(.box) {
|
||||||
|
padding: 8px 0 0;
|
||||||
|
margin-block: 8px;
|
||||||
|
border: 0;
|
||||||
|
border-block-start: 1px solid var(--md-sys-color-outline-variant);
|
||||||
|
border-radius: 0;
|
||||||
|
background-color: transparent;
|
||||||
|
}
|
||||||
|
/* A section that opens its card needs no divider: the card edge already separates it */
|
||||||
|
:is(.box, fieldset) > fieldset:first-child { margin-block-start: 0; padding-block-start: 0; border-block-start: 0; }
|
||||||
|
/* Floated, the legend leaves the border and flows as the first line of the fieldset */
|
||||||
|
fieldset > legend {
|
||||||
|
float: inline-start;
|
||||||
|
inline-size: 100%;
|
||||||
|
padding: 0 0 8px;
|
||||||
|
color: var(--md-sys-color-on-surface-variant);
|
||||||
|
font: var(--md-sys-typescale-title-small);
|
||||||
|
letter-spacing: var(--md-sys-typescale-title-small-tracking);
|
||||||
|
}
|
||||||
|
fieldset > legend ~ * { clear: inline-start; }
|
||||||
|
fieldset.collapsed > legend { padding-block-end: 0; }
|
||||||
|
/* The chevron stays with a label that wraps */
|
||||||
|
fieldset.collapsible > legend { display: flex; align-items: center; gap: 4px; }
|
||||||
|
.tabular label { color: var(--md-sys-color-on-surface-variant); font-weight: 500; }
|
||||||
|
.tabular p { padding-block: 4px; }
|
||||||
|
/* Center the 24px label line on the 40px fields next to it */
|
||||||
|
.tabular label:not(.floating):not(.block):not(.inline):not(.no-css) { padding-block-start: 8px; }
|
||||||
|
/* Checkboxes and radios placed directly in a row align with that label line too */
|
||||||
|
/* Checkboxes and radios next to such a label align with its text line */
|
||||||
|
.tabular p:has(> label:not(.floating):not(.block):not(.inline):not(.no-css)) > input:is([type="checkbox"], [type="radio"]) { margin-block: 13px 0; }
|
||||||
|
/* Rows without a field at the label's height start at the top: checkbox lists (watchers)
|
||||||
|
and the issue description, whose editor stays hidden until "Edit" is clicked */
|
||||||
|
.tabular p:is(:has(label.floating), :has(> #issue_description_and_toolbar[style*="none"])) > label:not(.floating):not(.block):not(.inline):not(.no-css) { padding-block-start: 0; }
|
||||||
|
hr { background: var(--md-sys-color-outline-variant); }
|
||||||
|
blockquote { border-inline-start: 4px solid var(--md-sys-color-outline-variant); color: var(--md-sys-color-on-surface-variant); }
|
||||||
|
|
||||||
|
/* Core gives wide form fields 90%, 95% or 99% and caps .tabular fields at 95%. They all
|
||||||
|
run to the content edge, so the right edges in a form line up */
|
||||||
|
.tabular :is(input, select) { max-inline-size: 100%; }
|
||||||
|
#user_login, #user_firstname, #user_lastname, #user_mail, #my_account_form select, #user_form select { inline-size: 100%; }
|
||||||
|
.tabular textarea, textarea.wiki-edit, textarea.text_cf, input.string_cf, input.link_cf,
|
||||||
|
textarea#custom_field_possible_values, textarea#custom_field_default_value,
|
||||||
|
input#issue_subject, input#document_title, input#content_comments, input#time_entry_comments,
|
||||||
|
.tabular .jstTabs, .tabular .wiki-preview, .jstBlock .jstTabs, .jstBlock .wiki-preview { inline-size: 100%; box-sizing: border-box; }
|
||||||
|
/* An invalid field keeps the error colour while focused */
|
||||||
|
.tabular label.error + :is(input, select, textarea):focus {
|
||||||
|
border-color: var(--md-sys-color-error);
|
||||||
|
outline-color: var(--md-sys-color-error);
|
||||||
|
}
|
||||||
|
/* Rows without a field start at the top, like a row with only links (two-factor auth) */
|
||||||
|
.tabular p:not(:has(input:not([type=hidden]), select, textarea)) > label:not(.floating):not(.block):not(.inline):not(.no-css) { padding-block-start: 0; }
|
||||||
|
/* Cancel next to a submit button */
|
||||||
|
input[type="submit"] + a { margin-inline-start: 8px; }
|
||||||
|
|
||||||
|
/* Checkbox lists in forms (custom field values, notified projects) */
|
||||||
|
.check_box_group {
|
||||||
|
padding-block: 4px;
|
||||||
|
padding-inline: 8px;
|
||||||
|
border-color: var(--md-sys-color-outline);
|
||||||
|
border-radius: var(--md-sys-shape-corner-extra-small);
|
||||||
|
background-color: transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
/***** Banners: flash messages, errors, warnings, empty states *****/
|
||||||
|
#errorExplanation, div.flash, .nodata, .warning, .conflict {
|
||||||
|
border: 0;
|
||||||
|
border-radius: var(--md-sys-shape-corner-medium);
|
||||||
|
padding-block: 14px;
|
||||||
|
padding-inline: 48px 16px;
|
||||||
|
font: var(--md-sys-typescale-body-large);
|
||||||
|
letter-spacing: var(--md-sys-typescale-body-large-tracking);
|
||||||
|
}
|
||||||
|
div.flash svg.icon-svg, #errorExplanation svg.icon-svg, .conflict svg.icon-svg { margin-inline: -32px 8px; }
|
||||||
|
div.flash.error, #errorExplanation {
|
||||||
|
background-color: var(--md-sys-color-error-container);
|
||||||
|
color: var(--md-sys-color-on-error-container);
|
||||||
|
}
|
||||||
|
div.flash.notice {
|
||||||
|
background-color: var(--md-sys-color-success-container);
|
||||||
|
color: var(--md-sys-color-on-success-container);
|
||||||
|
}
|
||||||
|
div.flash.warning, .conflict {
|
||||||
|
background-color: var(--md-sys-color-warning-container);
|
||||||
|
color: var(--md-sys-color-on-warning-container);
|
||||||
|
}
|
||||||
|
.nodata, .warning {
|
||||||
|
padding-inline: 16px;
|
||||||
|
background-color: var(--md-sys-color-surface-container);
|
||||||
|
color: var(--md-sys-color-on-surface-variant);
|
||||||
|
}
|
||||||
|
div.flash.error svg.icon-svg, #errorExplanation svg.icon-svg,
|
||||||
|
div.flash.notice svg.icon-svg, div.flash.warning svg.icon-svg, .conflict svg.icon-svg { stroke: currentColor; }
|
||||||
|
|
||||||
|
/***** Secondary tabs (settings, history, admin) *****/
|
||||||
|
#content .tabs { block-size: 48px; margin-block-end: 16px; }
|
||||||
|
#content .tabs ul { padding-inline-start: 0; border-block-end: 1px solid var(--md-sys-color-outline-variant); }
|
||||||
|
#content .tabs ul li { margin-inline-end: 0; margin-block-end: 0; }
|
||||||
|
#content .tabs ul li a, #content .tabs ul li a:hover {
|
||||||
|
position: relative;
|
||||||
|
padding-block: 14px;
|
||||||
|
padding-inline: 16px;
|
||||||
|
border: 0;
|
||||||
|
border-radius: 0;
|
||||||
|
background-color: transparent;
|
||||||
|
box-shadow: none;
|
||||||
|
color: var(--md-sys-color-on-surface-variant);
|
||||||
|
font: var(--md-sys-typescale-title-small);
|
||||||
|
letter-spacing: var(--md-sys-typescale-title-small-tracking);
|
||||||
|
}
|
||||||
|
#content .tabs ul li a:hover { background-image: var(--nm-state-hover); color: var(--md-sys-color-on-surface); }
|
||||||
|
#content .tabs ul li a.selected, #content .tabs ul li a.selected:hover {
|
||||||
|
background-color: transparent;
|
||||||
|
border: 0;
|
||||||
|
box-shadow: inset 0 -2px 0 var(--md-sys-color-primary);
|
||||||
|
color: var(--md-sys-color-on-surface);
|
||||||
|
}
|
||||||
|
/* Scroll arrows for tabs that overflow: standard icon buttons at the end of the tab row */
|
||||||
|
#content .tabs div.tabs-buttons {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: end;
|
||||||
|
gap: 4px;
|
||||||
|
inline-size: auto;
|
||||||
|
block-size: 48px;
|
||||||
|
padding-inline-start: 8px;
|
||||||
|
box-sizing: border-box;
|
||||||
|
background: var(--md-sys-color-surface);
|
||||||
|
border-block-end: 1px solid var(--md-sys-color-outline-variant);
|
||||||
|
}
|
||||||
|
#content .tabs button.tab-left, #content .tabs button.tab-right,
|
||||||
|
#main-menu button.tab-left, #main-menu button.tab-right {
|
||||||
|
position: static;
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
inline-size: 40px;
|
||||||
|
block-size: 40px;
|
||||||
|
padding: 0;
|
||||||
|
border: 0;
|
||||||
|
border-radius: var(--md-sys-shape-corner-full);
|
||||||
|
background-color: transparent;
|
||||||
|
color: var(--md-sys-color-on-surface-variant);
|
||||||
|
}
|
||||||
|
:is(#content .tabs, #main-menu) button:is(.tab-left, .tab-right) svg.icon-svg { stroke: currentColor; }
|
||||||
|
:is(#content .tabs, #main-menu) button:is(.tab-left, .tab-right):hover { background-image: var(--nm-state-hover); }
|
||||||
|
:is(#content .tabs, #main-menu) button:is(.tab-left, .tab-right).disabled {
|
||||||
|
background: transparent;
|
||||||
|
color: color-mix(in srgb, var(--md-sys-color-on-surface) var(--md-sys-state-disabled-content-opacity), transparent);
|
||||||
|
}
|
||||||
|
|
||||||
|
/***** Badges *****/
|
||||||
|
.badge {
|
||||||
|
inset-block-end: 2px;
|
||||||
|
padding-block: 2px;
|
||||||
|
padding-inline: 6px;
|
||||||
|
border-radius: var(--md-sys-shape-corner-small);
|
||||||
|
font: var(--md-sys-typescale-label-small);
|
||||||
|
letter-spacing: var(--md-sys-typescale-label-small-tracking);
|
||||||
|
}
|
||||||
|
.badge-private { background: var(--md-sys-color-error); border-color: var(--md-sys-color-error); color: var(--md-sys-color-on-error); }
|
||||||
|
.badge-count, .badge-issues-count {
|
||||||
|
border-radius: var(--md-sys-shape-corner-full);
|
||||||
|
background: var(--md-sys-color-secondary-container);
|
||||||
|
color: var(--md-sys-color-on-secondary-container);
|
||||||
|
}
|
||||||
|
.badge-status-open { border-color: var(--md-sys-color-primary); color: var(--md-sys-color-primary); }
|
||||||
|
.badge-status-closed { border-color: var(--md-sys-color-success); color: var(--md-sys-color-success); }
|
||||||
|
.badge-status-locked { border-color: var(--md-sys-color-outline); color: var(--md-sys-color-on-surface-variant); }
|
||||||
|
|
||||||
|
/***** Pagination *****/
|
||||||
|
span.pagination { margin-inline-start: 0; color: var(--md-sys-color-on-surface-variant); }
|
||||||
|
.pagination ul.pages { margin-inline: 0 8px; }
|
||||||
|
.pagination ul.pages li,
|
||||||
|
.pagination ul.pages li:first-child,
|
||||||
|
.pagination ul.pages li:last-child {
|
||||||
|
margin-inline-end: 4px;
|
||||||
|
border: 0;
|
||||||
|
border-radius: var(--md-sys-shape-corner-full);
|
||||||
|
line-height: 40px;
|
||||||
|
min-inline-size: 40px;
|
||||||
|
}
|
||||||
|
.pagination ul.pages li a, .pagination ul.pages li span {
|
||||||
|
display: block;
|
||||||
|
padding-block: 0;
|
||||||
|
padding-inline: 12px;
|
||||||
|
border-radius: var(--md-sys-shape-corner-full);
|
||||||
|
color: var(--md-sys-color-on-surface-variant);
|
||||||
|
}
|
||||||
|
.pagination ul.pages li.page:hover { background-color: transparent; background-image: var(--nm-state-hover); }
|
||||||
|
.pagination ul.pages li.page a:hover { color: var(--md-sys-color-on-surface); text-decoration: none; }
|
||||||
|
.pagination ul.pages li.current {
|
||||||
|
background-color: var(--md-sys-color-secondary-container);
|
||||||
|
color: var(--md-sys-color-on-secondary-container);
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
.pagination ul.pages li.current span { color: inherit; }
|
||||||
|
|
||||||
|
/***** Linear progress *****/
|
||||||
|
table.progress { border-radius: var(--md-sys-shape-corner-full); overflow: hidden; }
|
||||||
|
table.progress td { block-size: 4px; padding: 0; }
|
||||||
|
.version-overview table.progress td { block-size: 8px; }
|
||||||
|
table.progress td.closed { background: var(--md-sys-color-primary); }
|
||||||
|
table.progress td.done { background: color-mix(in srgb, var(--md-sys-color-primary) 55%, var(--md-sys-color-secondary-container)); }
|
||||||
|
table.progress td.todo { background: var(--md-sys-color-secondary-container); }
|
||||||
|
|
||||||
|
/***** Tooltips (plain) *****/
|
||||||
|
.ui-tooltip {
|
||||||
|
background: var(--md-sys-color-inverse-surface);
|
||||||
|
color: var(--md-sys-color-inverse-on-surface);
|
||||||
|
border-radius: var(--md-sys-shape-corner-extra-small);
|
||||||
|
font: var(--md-sys-typescale-body-small);
|
||||||
|
letter-spacing: var(--md-sys-typescale-body-small-tracking);
|
||||||
|
padding-block: 4px;
|
||||||
|
padding-inline: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/***** jQuery UI: dialogs, date picker, menus *****/
|
||||||
|
.ui-widget, .ui-widget input, .ui-widget select, .ui-widget textarea, .ui-widget button { font-family: var(--md-ref-typeface-plain); }
|
||||||
|
.ui-widget.ui-widget-content, .ui-widget-content {
|
||||||
|
background: var(--md-sys-color-surface-container-high);
|
||||||
|
border-color: var(--md-sys-color-outline-variant);
|
||||||
|
color: var(--md-sys-color-on-surface);
|
||||||
|
}
|
||||||
|
.ui-widget-content a { color: var(--md-sys-color-primary); }
|
||||||
|
.ui-dialog.ui-widget.ui-widget-content {
|
||||||
|
padding: 8px;
|
||||||
|
border: 0;
|
||||||
|
border-radius: var(--md-sys-shape-corner-extra-large);
|
||||||
|
box-shadow: var(--md-sys-elevation-level3);
|
||||||
|
}
|
||||||
|
.ui-widget-header {
|
||||||
|
background: transparent;
|
||||||
|
border: 0;
|
||||||
|
color: var(--md-sys-color-on-surface);
|
||||||
|
}
|
||||||
|
.ui-dialog .ui-dialog-titlebar { padding-block: 16px 8px; padding-inline: 16px; }
|
||||||
|
.ui-dialog .ui-dialog-title { font: var(--md-sys-typescale-headline-small); }
|
||||||
|
.ui-dialog .ui-dialog-content { padding-inline: 16px; }
|
||||||
|
.ui-dialog .ui-dialog-titlebar-close {
|
||||||
|
inline-size: 40px;
|
||||||
|
block-size: 40px;
|
||||||
|
margin-block-start: -20px;
|
||||||
|
border: 0;
|
||||||
|
border-radius: var(--md-sys-shape-corner-full);
|
||||||
|
background: transparent;
|
||||||
|
}
|
||||||
|
.ui-widget-overlay { background: var(--md-sys-color-scrim); opacity: 32%; }
|
||||||
|
|
||||||
|
.ui-state-default, .ui-widget-content .ui-state-default, .ui-widget-header .ui-state-default {
|
||||||
|
background: transparent;
|
||||||
|
border-color: transparent;
|
||||||
|
color: var(--md-sys-color-on-surface);
|
||||||
|
border-radius: var(--md-sys-shape-corner-full);
|
||||||
|
}
|
||||||
|
.ui-state-hover, .ui-widget-content .ui-state-hover, .ui-state-focus, .ui-widget-content .ui-state-focus {
|
||||||
|
background: color-mix(in srgb, var(--md-sys-color-on-surface) var(--md-sys-state-hover-state-layer-opacity), transparent);
|
||||||
|
border-color: transparent;
|
||||||
|
color: var(--md-sys-color-on-surface);
|
||||||
|
}
|
||||||
|
.ui-state-highlight, .ui-widget-content .ui-state-highlight {
|
||||||
|
background: transparent;
|
||||||
|
border: 1px solid var(--md-sys-color-primary);
|
||||||
|
color: var(--md-sys-color-primary);
|
||||||
|
}
|
||||||
|
.ui-state-active, .ui-widget-content .ui-state-active, .ui-widget-header .ui-state-active {
|
||||||
|
background: var(--md-sys-color-primary);
|
||||||
|
border-color: var(--md-sys-color-primary);
|
||||||
|
color: var(--md-sys-color-on-primary);
|
||||||
|
}
|
||||||
|
.ui-datepicker { padding: 12px; border-radius: var(--md-sys-shape-corner-large); box-shadow: var(--md-sys-elevation-level3); }
|
||||||
|
.ui-datepicker th { color: var(--md-sys-color-on-surface-variant); font: var(--md-sys-typescale-body-small); }
|
||||||
|
.ui-datepicker td a, .ui-datepicker td span { text-align: center; padding: 6px; }
|
||||||
|
|
||||||
|
.ui-autocomplete, .ui-menu, .tribute-container ul {
|
||||||
|
background: var(--md-sys-color-surface-container);
|
||||||
|
border: 0;
|
||||||
|
border-radius: var(--md-sys-shape-corner-extra-small);
|
||||||
|
box-shadow: var(--md-sys-elevation-level2);
|
||||||
|
color: var(--md-sys-color-on-surface);
|
||||||
|
padding-block: 8px;
|
||||||
|
}
|
||||||
|
.ui-menu .ui-menu-item-wrapper.ui-state-active, .tribute-container li.highlight {
|
||||||
|
margin: 0;
|
||||||
|
background: var(--md-sys-color-secondary-container);
|
||||||
|
border-color: transparent;
|
||||||
|
color: var(--md-sys-color-on-secondary-container);
|
||||||
|
}
|
||||||
|
|
||||||
|
/***** Icons *****/
|
||||||
|
/* The theme sprite (images/icons.svg) draws Material Symbols with fill="currentColor",
|
||||||
|
so icon color comes from `color`. Core's `stroke` rules still style plugin icons. */
|
||||||
|
svg.icon-svg { color: var(--md-sys-color-on-surface-variant); }
|
||||||
|
a.icon .icon-svg, a.icon-only .icon-svg, span.icon-actions .icon-svg, a .icon-svg { color: var(--md-sys-color-primary); }
|
||||||
|
a.icon:hover .icon-svg, a.icon-only:hover .icon-svg, span.icon-actions:hover .icon-svg { color: var(--md-sys-color-on-surface); }
|
||||||
|
.icon-ok svg.icon-svg { color: var(--md-sys-color-success); }
|
||||||
|
.icon-error svg.icon-svg { color: var(--md-sys-color-error); }
|
||||||
|
.icon-warning svg.icon-svg { color: var(--md-sys-color-warning); }
|
||||||
|
div.flash svg.icon-svg, #errorExplanation svg.icon-svg, .conflict svg.icon-svg,
|
||||||
|
.top-menu__links svg.icon-svg, #account .dropdown-trigger .icon-svg,
|
||||||
|
#main-menu svg.icon-svg, #sidebar a.selected svg.icon-svg, .drdn-items svg.icon-svg { color: inherit; }
|
||||||
|
html .context-menu-selection svg.icon-svg { color: var(--md-sys-color-on-secondary-container) !important; }
|
||||||
|
|
||||||
|
/***** Wiki toolbar (jstoolbar.css loads after the theme) *****/
|
||||||
|
/* Core draws the buttons as fixed-color background images, unreadable in dark mode.
|
||||||
|
The same SVGs are used as masks here, filled with currentColor. */
|
||||||
|
html .jstElements { block-size: auto; padding-block-end: 4px; }
|
||||||
|
html .jstElements button {
|
||||||
|
position: relative;
|
||||||
|
inline-size: 32px;
|
||||||
|
block-size: 32px;
|
||||||
|
margin-inline-end: 0;
|
||||||
|
padding: 0;
|
||||||
|
border: 0;
|
||||||
|
border-radius: var(--md-sys-shape-corner-full);
|
||||||
|
background-color: transparent;
|
||||||
|
background-image: none;
|
||||||
|
color: var(--md-sys-color-on-surface-variant);
|
||||||
|
opacity: 1;
|
||||||
|
vertical-align: middle;
|
||||||
|
}
|
||||||
|
html .jstElements button:hover { background-color: color-mix(in srgb, currentColor var(--md-sys-state-hover-state-layer-opacity), transparent); color: var(--md-sys-color-on-surface); }
|
||||||
|
html .jstElements button::after {
|
||||||
|
content: "";
|
||||||
|
position: absolute;
|
||||||
|
inset: 7px;
|
||||||
|
background-color: currentColor;
|
||||||
|
mask: var(--nm-jst-icon) center / contain no-repeat;
|
||||||
|
}
|
||||||
|
html .jstElements button.jstb_pre::after { display: none; }
|
||||||
|
html .jstb_pre::before { color: currentColor; font: var(--md-sys-typescale-label-small); }
|
||||||
|
html .jstSpacer { margin-inline-end: 8px; }
|
||||||
|
html .jstb_strong { --nm-jst-icon: url(/jstoolbar/bold.svg); }
|
||||||
|
html .jstb_em { --nm-jst-icon: url(/jstoolbar/italic.svg); }
|
||||||
|
html .jstb_ins { --nm-jst-icon: url(/jstoolbar/underline.svg); }
|
||||||
|
html .jstb_del { --nm-jst-icon: url(/jstoolbar/strikethrough.svg); }
|
||||||
|
html .jstb_code { --nm-jst-icon: url(/jstoolbar/letter-c.svg); }
|
||||||
|
html .jstb_h1 { --nm-jst-icon: url(/jstoolbar/h1.svg); }
|
||||||
|
html .jstb_h2 { --nm-jst-icon: url(/jstoolbar/h2.svg); }
|
||||||
|
html .jstb_h3 { --nm-jst-icon: url(/jstoolbar/h3.svg); }
|
||||||
|
html .jstb_ul { --nm-jst-icon: url(/jstoolbar/list.svg); }
|
||||||
|
html .jstb_ol { --nm-jst-icon: url(/jstoolbar/list-numbers.svg); }
|
||||||
|
html .jstb_tl { --nm-jst-icon: url(/jstoolbar/list-check.svg); }
|
||||||
|
html .jstb_bq { --nm-jst-icon: url(/jstoolbar/indent-increase.svg); }
|
||||||
|
html .jstb_unbq { --nm-jst-icon: url(/jstoolbar/indent-decrease.svg); }
|
||||||
|
html .jstb_precode { --nm-jst-icon: url(/jstoolbar/code.svg); }
|
||||||
|
html .jstb_link { --nm-jst-icon: url(/jstoolbar/wiki_link.svg); }
|
||||||
|
html .jstb_img { --nm-jst-icon: url(/jstoolbar/image.svg); }
|
||||||
|
html .jstb_table { --nm-jst-icon: url(/jstoolbar/table.svg); }
|
||||||
|
html .jstb_help { --nm-jst-icon: url(/jstoolbar/help.svg); }
|
||||||
|
html .wiki-preview { background-color: transparent; color: var(--md-sys-color-on-surface); border-color: var(--md-sys-color-outline-variant); border-radius: var(--md-sys-shape-corner-extra-small); }
|
||||||
|
html .table-generator td { background-color: var(--md-sys-color-surface-container-high); border-color: var(--md-sys-color-outline); }
|
||||||
|
html .table-generator td.selected-cell, html .table-generator td:hover { background-color: var(--md-sys-color-primary-container); }
|
||||||
|
|
||||||
|
/***** Appearance picker (added by javascripts/theme.js to the profile menu and mobile flyout) *****/
|
||||||
|
.nm-appearance { padding-block: 8px 12px; padding-inline: 12px; }
|
||||||
|
.nm-appearance__title {
|
||||||
|
margin-block-end: 8px;
|
||||||
|
color: var(--md-sys-color-on-surface-variant);
|
||||||
|
font: var(--md-sys-typescale-label-medium);
|
||||||
|
letter-spacing: var(--md-sys-typescale-label-medium-tracking);
|
||||||
|
}
|
||||||
|
/* M3 segmented button */
|
||||||
|
.nm-segmented { display: flex; margin-block-end: 12px; }
|
||||||
|
.nm-segmented button {
|
||||||
|
flex: 1;
|
||||||
|
border-radius: 0;
|
||||||
|
block-size: 32px;
|
||||||
|
padding-inline: 12px;
|
||||||
|
border: 1px solid var(--md-sys-color-outline);
|
||||||
|
background: transparent;
|
||||||
|
color: var(--md-sys-color-on-surface);
|
||||||
|
font: var(--md-sys-typescale-label-large);
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
.nm-segmented button + button { margin-inline-start: -1px; }
|
||||||
|
.nm-segmented button:first-child { border-start-start-radius: var(--md-sys-shape-corner-full); border-end-start-radius: var(--md-sys-shape-corner-full); }
|
||||||
|
.nm-segmented button:last-child { border-start-end-radius: var(--md-sys-shape-corner-full); border-end-end-radius: var(--md-sys-shape-corner-full); }
|
||||||
|
.nm-segmented button:hover { background-image: var(--nm-state-hover); }
|
||||||
|
.nm-segmented button[aria-pressed="true"] { background-color: var(--md-sys-color-secondary-container); color: var(--md-sys-color-on-secondary-container); }
|
||||||
|
/* Color swatches: the selected one gets a ring */
|
||||||
|
.nm-swatches { display: flex; gap: 8px; }
|
||||||
|
.nm-swatch {
|
||||||
|
inline-size: 28px;
|
||||||
|
block-size: 28px;
|
||||||
|
padding: 0;
|
||||||
|
border: 0;
|
||||||
|
border-radius: var(--md-sys-shape-corner-full);
|
||||||
|
background: var(--nm-swatch);
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
.nm-swatch[aria-pressed="true"] { box-shadow: 0 0 0 2px var(--md-sys-color-surface-container), 0 0 0 4px var(--md-sys-color-on-surface); }
|
||||||
|
html .flyout-menu .nm-appearance { padding-inline: 16px; }
|
||||||
|
html .flyout-menu .nm-appearance__title { color: var(--md-sys-color-on-surface-variant); }
|
||||||
|
|
||||||
|
/***** Loading indicator: an M3 snackbar-style chip on inverse surface *****/
|
||||||
|
#ajax-indicator {
|
||||||
|
inline-size: auto;
|
||||||
|
padding-block: 12px;
|
||||||
|
padding-inline: 16px;
|
||||||
|
border: 0;
|
||||||
|
border-radius: var(--md-sys-shape-corner-extra-small);
|
||||||
|
background-color: var(--md-sys-color-inverse-surface);
|
||||||
|
color: var(--md-sys-color-inverse-on-surface);
|
||||||
|
box-shadow: var(--md-sys-elevation-level3);
|
||||||
|
font: var(--md-sys-typescale-body-medium);
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/***** Code block copy button and dragged table rows *****/
|
||||||
|
div.pre-wrapper a.copy-pre-content-link {
|
||||||
|
padding: 4px;
|
||||||
|
border: 0;
|
||||||
|
border-radius: var(--md-sys-shape-corner-full);
|
||||||
|
background-color: var(--md-sys-color-surface-container-high);
|
||||||
|
color: var(--md-sys-color-on-surface-variant);
|
||||||
|
}
|
||||||
|
tr.ui-sortable-helper { border-color: var(--md-sys-color-outline-variant); box-shadow: var(--md-sys-elevation-level2); }
|
||||||
@@ -0,0 +1,332 @@
|
|||||||
|
/*
|
||||||
|
* Page layout: top app bar (top menu + header), primary tabs (project menu),
|
||||||
|
* sidebar card, content, footer, menus.
|
||||||
|
*
|
||||||
|
* State layers: M3 draws hover/focus/press as a translucent layer of the content
|
||||||
|
* color. Here that is a background-image of currentColor mixed at the state opacity,
|
||||||
|
* so it works on top of any background color.
|
||||||
|
*/
|
||||||
|
|
||||||
|
:root {
|
||||||
|
--nm-state-hover: linear-gradient(color-mix(in srgb, currentColor var(--md-sys-state-hover-state-layer-opacity), transparent) 0 0);
|
||||||
|
--nm-state-pressed: linear-gradient(color-mix(in srgb, currentColor var(--md-sys-state-pressed-state-layer-opacity), transparent) 0 0);
|
||||||
|
--nm-transition: background-color var(--md-sys-motion-duration-short4) var(--md-sys-motion-easing-standard),
|
||||||
|
color var(--md-sys-motion-duration-short4) var(--md-sys-motion-easing-standard);
|
||||||
|
}
|
||||||
|
|
||||||
|
#wrapper { background: var(--md-sys-color-surface); }
|
||||||
|
|
||||||
|
/***** Top app bar *****/
|
||||||
|
nav.top-menu {
|
||||||
|
background: var(--md-sys-color-surface-container);
|
||||||
|
color: var(--md-sys-color-on-surface-variant);
|
||||||
|
font: var(--md-sys-typescale-label-large);
|
||||||
|
letter-spacing: var(--md-sys-typescale-label-large-tracking);
|
||||||
|
padding-block: 4px;
|
||||||
|
padding-inline: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.top-menu__links a, .top-menu__links a:link, .top-menu__links a:visited, #account .dropdown-trigger {
|
||||||
|
color: var(--md-sys-color-on-surface-variant);
|
||||||
|
border-radius: var(--md-sys-shape-corner-full);
|
||||||
|
padding-block: 6px;
|
||||||
|
padding-inline: 12px;
|
||||||
|
transition: var(--nm-transition);
|
||||||
|
}
|
||||||
|
|
||||||
|
.top-menu__links a:hover, #account .dropdown-trigger:hover {
|
||||||
|
color: var(--md-sys-color-on-surface);
|
||||||
|
background-color: transparent;
|
||||||
|
background-image: var(--nm-state-hover);
|
||||||
|
}
|
||||||
|
|
||||||
|
.top-menu__links svg.icon-svg, #account .dropdown-trigger .icon-svg,
|
||||||
|
.top-menu__links a:hover svg.icon-svg, #account .dropdown-trigger:hover .icon-svg {
|
||||||
|
stroke: currentColor;
|
||||||
|
}
|
||||||
|
|
||||||
|
#header {
|
||||||
|
background: var(--md-sys-color-surface-container);
|
||||||
|
color: var(--md-sys-color-on-surface);
|
||||||
|
padding-block: 4px 0;
|
||||||
|
padding-inline: 24px;
|
||||||
|
}
|
||||||
|
body.has-main-menu #header { padding-block-end: 48px; }
|
||||||
|
#header a, #header a:hover { color: var(--md-sys-color-on-surface); }
|
||||||
|
|
||||||
|
#header h1 {
|
||||||
|
font: var(--md-sys-typescale-title-large);
|
||||||
|
min-block-size: 3rem;
|
||||||
|
}
|
||||||
|
#header h1 .breadcrumbs {
|
||||||
|
font: var(--md-sys-typescale-label-medium);
|
||||||
|
letter-spacing: var(--md-sys-typescale-label-medium-tracking);
|
||||||
|
color: var(--md-sys-color-on-surface-variant);
|
||||||
|
}
|
||||||
|
#header h1 .breadcrumbs a { color: var(--md-sys-color-on-surface-variant); }
|
||||||
|
|
||||||
|
#quick-search { min-block-size: 3rem; color: var(--md-sys-color-on-surface-variant); }
|
||||||
|
#quick-search #q {
|
||||||
|
inline-size: 220px;
|
||||||
|
block-size: 40px;
|
||||||
|
padding-inline: 16px;
|
||||||
|
border: 0;
|
||||||
|
border-radius: var(--md-sys-shape-corner-full);
|
||||||
|
background-color: var(--md-sys-color-surface-container-highest);
|
||||||
|
color: var(--md-sys-color-on-surface);
|
||||||
|
font: var(--md-sys-typescale-body-large);
|
||||||
|
}
|
||||||
|
#quick-search #q:focus { outline: 2px solid var(--md-sys-color-primary); outline-offset: 0; }
|
||||||
|
#quick-search form label { font: var(--md-sys-typescale-label-large); }
|
||||||
|
|
||||||
|
#project-jump.drdn { margin-inline-start: 8px; }
|
||||||
|
#project-jump .drdn-trigger {
|
||||||
|
block-size: 40px;
|
||||||
|
padding-inline: 16px 36px;
|
||||||
|
border: 1px solid var(--md-sys-color-outline-variant);
|
||||||
|
border-radius: var(--md-sys-shape-corner-full);
|
||||||
|
background-color: transparent;
|
||||||
|
color: var(--md-sys-color-on-surface);
|
||||||
|
font: var(--md-sys-typescale-label-large);
|
||||||
|
line-height: 38px;
|
||||||
|
}
|
||||||
|
#project-jump .drdn-trigger:hover { background-image: var(--nm-state-hover); }
|
||||||
|
|
||||||
|
/***** Primary tabs (project menu) *****/
|
||||||
|
#main-menu {
|
||||||
|
background: var(--md-sys-color-surface-container);
|
||||||
|
border-block-end: 1px solid var(--md-sys-color-outline-variant);
|
||||||
|
padding-block: 0;
|
||||||
|
padding-inline: 16px;
|
||||||
|
}
|
||||||
|
#main-menu ul { min-block-size: 48px; }
|
||||||
|
#main-menu li a {
|
||||||
|
position: relative;
|
||||||
|
color: var(--md-sys-color-on-surface-variant);
|
||||||
|
font: var(--md-sys-typescale-title-small);
|
||||||
|
letter-spacing: var(--md-sys-typescale-title-small-tracking);
|
||||||
|
padding-block: 14px;
|
||||||
|
padding-inline: 16px;
|
||||||
|
line-height: 20px;
|
||||||
|
transition: var(--nm-transition);
|
||||||
|
}
|
||||||
|
#main-menu li a:hover {
|
||||||
|
background-color: transparent;
|
||||||
|
background-image: var(--nm-state-hover);
|
||||||
|
color: var(--md-sys-color-on-surface);
|
||||||
|
}
|
||||||
|
#main-menu li a.selected, #main-menu li a.selected:hover {
|
||||||
|
background-color: transparent;
|
||||||
|
color: var(--md-sys-color-primary);
|
||||||
|
font-weight: 500;
|
||||||
|
box-shadow: none;
|
||||||
|
}
|
||||||
|
#main-menu li a.selected::after {
|
||||||
|
content: "";
|
||||||
|
position: absolute;
|
||||||
|
inset-inline: 16px;
|
||||||
|
inset-block-end: 0;
|
||||||
|
block-size: 3px;
|
||||||
|
border-radius: 3px 3px 0 0;
|
||||||
|
background: var(--md-sys-color-primary);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* "+" new object: tonal icon button */
|
||||||
|
#main-menu li a.new-object {
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
inline-size: 40px;
|
||||||
|
block-size: 40px;
|
||||||
|
padding: 0;
|
||||||
|
margin-block: 0;
|
||||||
|
border: 0;
|
||||||
|
border-radius: var(--md-sys-shape-corner-medium);
|
||||||
|
background-color: var(--md-sys-color-secondary-container);
|
||||||
|
color: var(--md-sys-color-on-secondary-container);
|
||||||
|
}
|
||||||
|
#main-menu li a.new-object:hover {
|
||||||
|
background-color: var(--md-sys-color-secondary-container);
|
||||||
|
background-image: var(--nm-state-hover);
|
||||||
|
color: var(--md-sys-color-on-secondary-container);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Scroll arrows when the menu overflows: icon buttons on the bar's colour, so menu items
|
||||||
|
slide under them instead of showing through (button styles in components.css) */
|
||||||
|
#main-menu div.tabs-buttons {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 4px;
|
||||||
|
inline-size: auto;
|
||||||
|
block-size: 48px;
|
||||||
|
inset-inline-end: 0;
|
||||||
|
padding-inline: 8px;
|
||||||
|
border: 0;
|
||||||
|
background-color: var(--md-sys-color-surface-container);
|
||||||
|
}
|
||||||
|
|
||||||
|
/***** Menus: project menu children, dropdowns, profile menu *****/
|
||||||
|
#main-menu .menu-children,
|
||||||
|
html .drdn-content,
|
||||||
|
html .dropdown-content {
|
||||||
|
background-color: var(--md-sys-color-surface-container);
|
||||||
|
border: 0;
|
||||||
|
border-radius: var(--md-sys-shape-corner-extra-small);
|
||||||
|
box-shadow: var(--md-sys-elevation-level2);
|
||||||
|
color: var(--md-sys-color-on-surface);
|
||||||
|
padding-block: 8px;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
#main-menu .menu-children li a,
|
||||||
|
html .dropdown-content li a,
|
||||||
|
html .dropdown-content .dropdown-items a,
|
||||||
|
.drdn-items > * {
|
||||||
|
background-color: transparent;
|
||||||
|
border: 0;
|
||||||
|
border-radius: 0;
|
||||||
|
color: var(--md-sys-color-on-surface);
|
||||||
|
font: var(--md-sys-typescale-label-large);
|
||||||
|
letter-spacing: var(--md-sys-typescale-label-large-tracking);
|
||||||
|
padding-block: 10px;
|
||||||
|
padding-inline: 12px;
|
||||||
|
}
|
||||||
|
#main-menu .menu-children li a:hover,
|
||||||
|
html .dropdown-content li a:hover,
|
||||||
|
html .dropdown-content .dropdown-items a:hover,
|
||||||
|
.drdn-items > a:hover,
|
||||||
|
.drdn-items > a:focus {
|
||||||
|
background-color: transparent;
|
||||||
|
background-image: var(--nm-state-hover);
|
||||||
|
color: var(--md-sys-color-on-surface);
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
#main-menu .menu-children li a:hover::after { display: none; }
|
||||||
|
.drdn-items > .selected { background-color: var(--md-sys-color-secondary-container); color: var(--md-sys-color-on-secondary-container); }
|
||||||
|
#project-jump .drdn-items > a:hover { background-color: transparent; color: var(--md-sys-color-on-surface) !important; }
|
||||||
|
div + .drdn-items, .dropdown-divider, #account .dropdown-content .logout { border-color: var(--md-sys-color-outline-variant); }
|
||||||
|
#account .dropdown-content .user-info { color: var(--md-sys-color-on-surface-variant); font: var(--md-sys-typescale-body-medium); }
|
||||||
|
#account .dropdown-content .user-info .user-name { color: var(--md-sys-color-on-surface); font: var(--md-sys-typescale-title-small); }
|
||||||
|
|
||||||
|
/***** Content and sidebar *****/
|
||||||
|
#main { background: var(--md-sys-color-surface); }
|
||||||
|
|
||||||
|
#content {
|
||||||
|
background-color: var(--md-sys-color-surface);
|
||||||
|
padding-block: 24px 16px;
|
||||||
|
padding-inline: 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#sidebar {
|
||||||
|
background: var(--md-sys-color-surface-container-low);
|
||||||
|
border: 0;
|
||||||
|
border-radius: var(--md-sys-shape-corner-large);
|
||||||
|
margin-block: 16px;
|
||||||
|
margin-inline-end: 16px;
|
||||||
|
padding-block: 16px;
|
||||||
|
padding-inline: 16px;
|
||||||
|
box-sizing: border-box;
|
||||||
|
align-self: flex-start;
|
||||||
|
}
|
||||||
|
/* Collapsed: only the switch button remains, in a small rounded surface */
|
||||||
|
#main.collapsedsidebar #sidebar { inline-size: auto; margin-block: 16px; margin-inline-end: 16px; padding: 4px; }
|
||||||
|
#main.collapsedsidebar #sidebar-switch-panel { float: none; margin: 0; }
|
||||||
|
#sidebar h3 {
|
||||||
|
color: var(--md-sys-color-on-surface-variant);
|
||||||
|
font: var(--md-sys-typescale-title-small);
|
||||||
|
letter-spacing: var(--md-sys-typescale-title-small-tracking);
|
||||||
|
margin-block: 16px 8px;
|
||||||
|
}
|
||||||
|
#sidebar hr { background: var(--md-sys-color-outline-variant); margin-block: 12px; }
|
||||||
|
|
||||||
|
/* Collapse button: 32px icon button in the top corner, level with the first heading */
|
||||||
|
#sidebar-switch-panel { float: inline-end; inline-size: auto; margin-block: -6px 0; margin-inline: 8px -6px; padding: 0; }
|
||||||
|
#sidebar-switch-button {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
inline-size: 32px;
|
||||||
|
block-size: 32px;
|
||||||
|
padding: 0;
|
||||||
|
border-radius: var(--md-sys-shape-corner-full);
|
||||||
|
color: var(--md-sys-color-on-surface-variant);
|
||||||
|
}
|
||||||
|
#sidebar-switch-button svg { stroke: var(--md-sys-color-on-surface-variant); color: inherit; }
|
||||||
|
#sidebar-switch-button:hover { background-color: transparent; background-image: var(--nm-state-hover); }
|
||||||
|
|
||||||
|
/* Sidebar forms (activity, roadmap, …): label above a full-width field */
|
||||||
|
#sidebar form > p:has(> input:not([type="submit"], [type="hidden"], [type="checkbox"]), > select) {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 4px;
|
||||||
|
margin-block: 0 12px;
|
||||||
|
color: var(--md-sys-color-on-surface-variant);
|
||||||
|
font: var(--md-sys-typescale-label-medium);
|
||||||
|
letter-spacing: var(--md-sys-typescale-label-medium-tracking);
|
||||||
|
}
|
||||||
|
#sidebar form > p > :is(input:not([type="submit"], [type="checkbox"]), select) { inline-size: 100%; max-inline-size: none; margin: 0; }
|
||||||
|
/* First heading sits level with the collapse button, also after hidden form inputs */
|
||||||
|
#sidebar-wrapper > form:first-child > h3:first-of-type,
|
||||||
|
#sidebar-wrapper > .contextual:first-child + h3 { margin-block-start: 0; }
|
||||||
|
#sidebar-wrapper > .contextual:first-child { margin-block: 0; }
|
||||||
|
/* Watchers opening the sidebar: "Add" sits next to the collapse button, heading level with it */
|
||||||
|
#sidebar-wrapper > #watchers:first-child > .contextual { margin-block: 0; margin-inline-end: 0; }
|
||||||
|
#sidebar-wrapper > #watchers:first-child > .contextual + h3 { margin-block-start: 0; }
|
||||||
|
#sidebar form > p:empty { display: none; }
|
||||||
|
|
||||||
|
/* Checkbox lists: even 32px rows, text-colored labels */
|
||||||
|
#sidebar li:has(input[type="checkbox"]),
|
||||||
|
#sidebar :is(li, form > p) > label:has(input[type="checkbox"]),
|
||||||
|
#sidebar form > p:has(> input[type="checkbox"]) {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 12px;
|
||||||
|
min-block-size: 32px;
|
||||||
|
}
|
||||||
|
#sidebar :is(li, form > p) > label:has(input[type="checkbox"]) { flex: 1; }
|
||||||
|
#sidebar input[type="checkbox"] { inline-size: 18px; block-size: 18px; margin: 0; flex-shrink: 0; }
|
||||||
|
#sidebar li label, #sidebar li label a, #sidebar form > p > label { color: var(--md-sys-color-on-surface); font: var(--md-sys-typescale-body-medium); }
|
||||||
|
#sidebar ul + ul, #sidebar ul + p { margin-block-start: 12px; }
|
||||||
|
|
||||||
|
/* Navigation-drawer style items for plain link lists in the sidebar (queries, sort order,
|
||||||
|
versions, wiki index, …): a link that is alone in its list item */
|
||||||
|
#sidebar li > a:only-child, #admin-menu li a {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
min-block-size: 36px;
|
||||||
|
padding-inline: 12px;
|
||||||
|
border-radius: var(--md-sys-shape-corner-full);
|
||||||
|
color: var(--md-sys-color-on-surface-variant);
|
||||||
|
font: var(--md-sys-typescale-label-large);
|
||||||
|
letter-spacing: var(--md-sys-typescale-label-large-tracking);
|
||||||
|
transition: var(--nm-transition);
|
||||||
|
}
|
||||||
|
#sidebar li > a:only-child:hover, #admin-menu li a:hover { background-image: var(--nm-state-hover); text-decoration: none; }
|
||||||
|
#sidebar li > a.selected:only-child, #admin-menu li a.selected {
|
||||||
|
margin-inline-start: 0; /* core: -6px, inset marker bar */
|
||||||
|
padding-block: 0;
|
||||||
|
box-shadow: none;
|
||||||
|
line-height: normal;
|
||||||
|
background-color: var(--md-sys-color-secondary-container);
|
||||||
|
color: var(--md-sys-color-on-secondary-container);
|
||||||
|
}
|
||||||
|
#admin-menu li { padding-block-end: 2px; }
|
||||||
|
|
||||||
|
/***** Footer *****/
|
||||||
|
#footer {
|
||||||
|
background: var(--md-sys-color-surface);
|
||||||
|
border: 0;
|
||||||
|
color: var(--md-sys-color-on-surface-variant);
|
||||||
|
font: var(--md-sys-typescale-label-small);
|
||||||
|
letter-spacing: var(--md-sys-typescale-label-small-tracking);
|
||||||
|
padding: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/***** Login *****/
|
||||||
|
#login-form {
|
||||||
|
inline-size: 400px;
|
||||||
|
padding: 24px;
|
||||||
|
background-color: var(--md-sys-color-surface-container-low);
|
||||||
|
border-radius: var(--md-sys-shape-corner-extra-large);
|
||||||
|
}
|
||||||
|
#login-form label { font: var(--md-sys-typescale-label-large); color: var(--md-sys-color-on-surface-variant); }
|
||||||
|
#login-form input { block-size: 40px; }
|
||||||
@@ -0,0 +1,156 @@
|
|||||||
|
/*
|
||||||
|
* Mobile overrides at core's responsive.css breakpoint. The core file stays in place
|
||||||
|
* (a theme file named responsive.css would replace it); it loads after the theme,
|
||||||
|
* hence the `html` prefix on conflicting selectors.
|
||||||
|
*/
|
||||||
|
|
||||||
|
@media screen and (max-width: 899px) {
|
||||||
|
/* Top app bar */
|
||||||
|
html #header { background-color: var(--md-sys-color-surface-container); color: var(--md-sys-color-on-surface); }
|
||||||
|
html #header a.mobile-toggle-button { color: var(--md-sys-color-on-surface-variant); border-inline-start: 0; }
|
||||||
|
html #project-jump .drdn-trigger {
|
||||||
|
border: 0;
|
||||||
|
color: var(--md-sys-color-on-surface);
|
||||||
|
font: var(--md-sys-typescale-title-large);
|
||||||
|
line-height: 50px;
|
||||||
|
}
|
||||||
|
html #project-jump.drdn { padding-inline-start: 8px; }
|
||||||
|
/* Header icons: Material Symbols masks instead of core's scaled "^" and "≡" text glyphs */
|
||||||
|
html #project-jump .drdn-trigger:before {
|
||||||
|
content: '';
|
||||||
|
inset-block: 0;
|
||||||
|
margin-block: auto;
|
||||||
|
inline-size: 24px;
|
||||||
|
block-size: 24px;
|
||||||
|
padding: 0;
|
||||||
|
transform: none;
|
||||||
|
opacity: 1;
|
||||||
|
background-color: var(--md-sys-color-on-surface-variant);
|
||||||
|
mask: url(../images/arrow-drop-down.svg) center / 24px no-repeat;
|
||||||
|
}
|
||||||
|
html #header a.mobile-toggle-button {
|
||||||
|
inline-size: 48px;
|
||||||
|
block-size: 48px;
|
||||||
|
margin-block-start: 8px;
|
||||||
|
margin-inline-end: 8px;
|
||||||
|
border-radius: var(--md-sys-shape-corner-full);
|
||||||
|
line-height: normal;
|
||||||
|
}
|
||||||
|
html #header a.mobile-toggle-button:hover { background-image: var(--nm-state-hover); }
|
||||||
|
html .mobile-toggle-button:after {
|
||||||
|
content: '';
|
||||||
|
inline-size: 24px;
|
||||||
|
block-size: 24px;
|
||||||
|
margin: 12px;
|
||||||
|
background-color: currentColor;
|
||||||
|
mask: url(../images/menu.svg) center / 24px no-repeat;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Flyout: navigation drawer */
|
||||||
|
html .flyout-menu {
|
||||||
|
background-color: var(--md-sys-color-surface-container-low);
|
||||||
|
color: var(--md-sys-color-on-surface);
|
||||||
|
padding-inline: 12px;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
html .flyout-menu h3 {
|
||||||
|
block-size: auto;
|
||||||
|
margin-block: 16px 4px;
|
||||||
|
padding-inline: 16px;
|
||||||
|
border: 0;
|
||||||
|
background-color: transparent;
|
||||||
|
color: var(--md-sys-color-on-surface-variant);
|
||||||
|
font: var(--md-sys-typescale-title-small);
|
||||||
|
letter-spacing: var(--md-sys-typescale-title-small-tracking);
|
||||||
|
text-transform: none;
|
||||||
|
}
|
||||||
|
html .flyout-menu h4 { color: var(--md-sys-color-on-surface); }
|
||||||
|
html .flyout-menu a { color: var(--md-sys-color-on-surface-variant); }
|
||||||
|
html .flyout-menu ul li a, html .flyout-menu ul li:first-child a {
|
||||||
|
block-size: 48px;
|
||||||
|
line-height: 48px;
|
||||||
|
margin-inline-start: 0;
|
||||||
|
padding-inline: 16px;
|
||||||
|
border: 0;
|
||||||
|
border-radius: var(--md-sys-shape-corner-full);
|
||||||
|
font: var(--md-sys-typescale-label-large);
|
||||||
|
line-height: 48px;
|
||||||
|
}
|
||||||
|
html .flyout-menu ul li a:hover { background-image: var(--nm-state-hover); }
|
||||||
|
html .flyout-menu ul li a.selected {
|
||||||
|
background-color: var(--md-sys-color-secondary-container);
|
||||||
|
color: var(--md-sys-color-on-secondary-container);
|
||||||
|
}
|
||||||
|
html .flyout-menu #watchers ul li, html .flyout-menu ul.queries li, html .flyout-menu__avatar { border-block-start: 0; }
|
||||||
|
html .flyout-menu .icon svg, html .flyout-menu .icon-only svg { color: inherit; stroke: currentColor; }
|
||||||
|
html .flyout-menu__search input[type='text'] {
|
||||||
|
block-size: 48px;
|
||||||
|
border-radius: var(--md-sys-shape-corner-full);
|
||||||
|
background-color: var(--md-sys-color-surface-container-highest);
|
||||||
|
color: var(--md-sys-color-on-surface);
|
||||||
|
padding-inline-start: 52px;
|
||||||
|
}
|
||||||
|
/* Search pill, avatar row and nav labels share one inline start: the icon and the
|
||||||
|
avatar sit where the nav labels begin (drawer padding 12px + item padding 16px) */
|
||||||
|
html .flyout-menu .flyout-menu__search { padding-inline: 0; }
|
||||||
|
html .search-magnifier--flyout { inset-inline-start: 28px; }
|
||||||
|
html .flyout-menu .flyout-menu__avatar { padding-inline-start: 16px; }
|
||||||
|
|
||||||
|
html .cal .week-number { background-color: var(--md-sys-color-surface-container); border-color: var(--md-sys-color-outline-variant); }
|
||||||
|
/* Page actions become M3 outlined buttons, like Apply / Clear. The forum topic wraps its
|
||||||
|
actions in a quote-reply controller, so core's #content > .contextual misses them. */
|
||||||
|
html #content > [data-controller="quote-reply"] > .contextual {
|
||||||
|
inline-size: 100%;
|
||||||
|
margin-block-end: 8px;
|
||||||
|
padding-inline-start: 0;
|
||||||
|
white-space: normal;
|
||||||
|
}
|
||||||
|
html :is(#content > .contextual > a, #content > .contextual .drdn, #content > [data-controller="quote-reply"] > .contextual > a, p.buttons a) {
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
block-size: 40px;
|
||||||
|
margin-block: 4px;
|
||||||
|
margin-inline: 0 4px;
|
||||||
|
padding-block: 0;
|
||||||
|
padding-inline: 16px;
|
||||||
|
border: 1px solid var(--md-sys-color-outline);
|
||||||
|
border-radius: var(--md-sys-shape-corner-full);
|
||||||
|
box-sizing: border-box;
|
||||||
|
font: var(--md-sys-typescale-label-large);
|
||||||
|
letter-spacing: var(--md-sys-typescale-label-large-tracking);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* A scrolling table takes its natural width instead of squeezing text columns to a
|
||||||
|
word per line; it scrolls inside its card */
|
||||||
|
html .autoscroll > table.list { inline-size: max-content; min-inline-size: 100%; }
|
||||||
|
/* Tables core does not wrap scroll themselves, so they no longer push the whole content
|
||||||
|
area sideways; thead and tbody share one anonymous table, so columns stay aligned.
|
||||||
|
ponytail: a table narrower than the screen would leave a gap inside its border, so small
|
||||||
|
summary tables are excluded by class; add others here if one shows a gap */
|
||||||
|
html #content table.list:not(.autoscroll > table, .issue-report) { display: block; overflow-x: auto; max-inline-size: 100%; }
|
||||||
|
|
||||||
|
/* Form fields run full width; a select keeps room for the icon button after it */
|
||||||
|
html form .attributes select { inline-size: 100%; }
|
||||||
|
html form .attributes select:has(+ .icon-only) { inline-size: calc(100% - 36px); }
|
||||||
|
html .tabular input[type="radio"] { inline-size: auto; }
|
||||||
|
|
||||||
|
/* Wiki toolbar: buttons wrap instead of being cut off */
|
||||||
|
html #content .jstTabs.tabs { clear: both; block-size: auto; overflow: visible; } /* below the floated field label */
|
||||||
|
html #content .jstTabs.tabs ul { position: static; display: flex; flex-wrap: wrap; inline-size: auto; min-inline-size: 0; }
|
||||||
|
html #content .jstTabs.tabs li.tab-elements { flex: 1 1 auto; min-inline-size: 0; block-size: auto; }
|
||||||
|
html #content .jstTabs .jstElements { display: flex; flex-wrap: wrap; white-space: normal; }
|
||||||
|
html #content .jstTabs.tabs li.tab-elements::before { display: none; } /* core's full-height strut for vertical centring */
|
||||||
|
|
||||||
|
/* Subtasks and related issues: the progress bar fits its cell, the subject leaves room
|
||||||
|
for both icon buttons */
|
||||||
|
html :is(#issue_tree, #relations) td.done_ratio table.progress { inline-size: 100%; }
|
||||||
|
html :is(#issue_tree, #relations):not(.with-related-issues-table-headers) .issue:has(.buttons a) > td.subject { padding-inline-end: 72px; }
|
||||||
|
|
||||||
|
html div#version-summary { margin-block-start: 16px; }
|
||||||
|
|
||||||
|
/* Core gives the current, previous and next page a third of the row each */
|
||||||
|
html .pagination ul.pages li:is(.current, .previous, .next) { inline-size: auto; overflow: visible; }
|
||||||
|
|
||||||
|
/* The desktop sidebar card has no place on mobile; its content moves into the flyout */
|
||||||
|
#sidebar { margin: 0; border-radius: 0; }
|
||||||
|
}
|
||||||
@@ -0,0 +1,493 @@
|
|||||||
|
/*
|
||||||
|
* Page-specific styles: issue view, journals, wiki content and code,
|
||||||
|
* activity, roadmap, calendar, Gantt.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/***** Issue view *****/
|
||||||
|
/* .details: calendar entries are div.issue too */
|
||||||
|
div.issue.details {
|
||||||
|
background: var(--md-sys-color-surface-container-low);
|
||||||
|
border-radius: var(--md-sys-shape-corner-medium);
|
||||||
|
padding: 24px;
|
||||||
|
margin-block-end: 16px;
|
||||||
|
}
|
||||||
|
div.issue div.subject h3 { font: var(--md-sys-typescale-headline-small); }
|
||||||
|
div.issue p.author { color: var(--md-sys-color-on-surface-variant); }
|
||||||
|
div.issue .attributes .attribute .label { color: var(--md-sys-color-on-surface-variant); font-weight: 500; }
|
||||||
|
div.issue hr { background: var(--md-sys-color-outline-variant); }
|
||||||
|
div.issue.overdue .due-date .value { color: var(--md-sys-color-error); }
|
||||||
|
div.issue table.list { background: var(--md-sys-color-surface); }
|
||||||
|
|
||||||
|
/* Sticky issue header while scrolling: an M3 top app bar in its scrolled state
|
||||||
|
(surface-container, no shadow). Core hard-codes a white background. */
|
||||||
|
div#sticky-issue-header {
|
||||||
|
padding-block: 12px;
|
||||||
|
padding-inline: 24px;
|
||||||
|
border-block-end: 1px solid var(--md-sys-color-outline-variant);
|
||||||
|
background-color: var(--md-sys-color-surface-container);
|
||||||
|
box-shadow: none;
|
||||||
|
color: var(--md-sys-color-on-surface-variant);
|
||||||
|
font: var(--md-sys-typescale-title-medium);
|
||||||
|
}
|
||||||
|
div#sticky-issue-header .subject { color: var(--md-sys-color-on-surface); font-weight: 500; }
|
||||||
|
|
||||||
|
/* Progress bars inside list rows must not take the row padding and height */
|
||||||
|
table.list table.progress td, table.list table.progress td:first-child {
|
||||||
|
block-size: 4px;
|
||||||
|
padding: 0;
|
||||||
|
border: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/***** Journals: each change is an outlined card, its header a band on top *****/
|
||||||
|
.journals .journal {
|
||||||
|
margin-block-end: 12px;
|
||||||
|
background-color: var(--md-sys-color-surface-container-low);
|
||||||
|
border: 1px solid var(--md-sys-color-outline-variant);
|
||||||
|
border-radius: var(--md-sys-shape-corner-medium);
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
.journals h4.journal-header {
|
||||||
|
margin: 0;
|
||||||
|
background-color: var(--md-sys-color-surface-container-high);
|
||||||
|
border-block-end: 1px solid var(--md-sys-color-outline-variant);
|
||||||
|
border-radius: 0;
|
||||||
|
padding-block: 8px;
|
||||||
|
padding-inline: 16px;
|
||||||
|
font: var(--md-sys-typescale-title-small);
|
||||||
|
}
|
||||||
|
.journals h4.journal-header .update-info { color: var(--md-sys-color-on-surface-variant); font: var(--md-sys-typescale-body-small); }
|
||||||
|
.journals div:target h4.journal-header { background-color: var(--md-sys-color-secondary-container); color: var(--md-sys-color-on-secondary-container); }
|
||||||
|
.journals div.journal:has(div:target), .journals div.journal:target { border-color: var(--md-sys-color-primary); }
|
||||||
|
.journals .journal-content { margin-block-end: 0; padding-block: 4px 12px; padding-inline: 16px; }
|
||||||
|
.journals .journal-content :is(.journal-details, .wiki):last-child, .journals .journal-content .wiki > :last-child { margin-block-end: 0; }
|
||||||
|
.journals .private-notes { border-inline-start: 4px solid var(--md-sys-color-error); }
|
||||||
|
.journals .journal-details, ul.revision-info { color: var(--md-sys-color-on-surface-variant); }
|
||||||
|
|
||||||
|
/***** Reading pages: the main content sits in one filled card, like the issue details *****/
|
||||||
|
#content > div.wiki.wiki-page,
|
||||||
|
#content > div.news,
|
||||||
|
.controller-documents.action-show #content > div.wiki,
|
||||||
|
#content > [data-controller="quote-reply"] > div.message {
|
||||||
|
margin-block-end: 16px;
|
||||||
|
padding: 24px;
|
||||||
|
border-radius: var(--md-sys-shape-corner-medium);
|
||||||
|
background-color: var(--md-sys-color-surface-container-low);
|
||||||
|
}
|
||||||
|
/* The card's padding is the gap: no paragraph margin on top of it (news and messages
|
||||||
|
open with a floated reaction button) */
|
||||||
|
:is(#content > div.wiki.wiki-page, #content > div.news, .controller-documents.action-show #content > div.wiki,
|
||||||
|
#content > [data-controller="quote-reply"] > div.message) {
|
||||||
|
& > :first-child, & > .reaction + * { margin-block-start: 0; }
|
||||||
|
& > :last-child, & > .wiki:last-child > :last-child { margin-block-end: 0; }
|
||||||
|
}
|
||||||
|
/* The wiki page's actions sit above its card, not on its edge */
|
||||||
|
#content > div.wiki.wiki-page { clear: both; }
|
||||||
|
|
||||||
|
/***** Wiki content *****/
|
||||||
|
div.wiki table { padding: 0; border-collapse: separate; border-spacing: 0; border: 1px solid var(--md-sys-color-outline-variant); border-radius: var(--md-sys-shape-corner-medium); overflow: hidden; }
|
||||||
|
div.wiki td, div.wiki th { border: 0; border-block-start: 1px solid var(--md-sys-color-outline-variant); padding-block: 8px; padding-inline: 12px; }
|
||||||
|
div.wiki tr:first-child td, div.wiki tr:first-child th { border-block-start: 0; }
|
||||||
|
div.wiki th { background: var(--md-sys-color-surface-container); color: var(--md-sys-color-on-surface-variant); font: var(--md-sys-typescale-title-small); }
|
||||||
|
div.wiki a.new { color: var(--md-sys-color-error); }
|
||||||
|
/* Wiki text mostly sits in a card, so the TOC steps one tone up from it */
|
||||||
|
div.wiki ul.toc {
|
||||||
|
background-color: var(--md-sys-color-surface-container);
|
||||||
|
border: 0;
|
||||||
|
border-radius: var(--md-sys-shape-corner-medium);
|
||||||
|
padding: 12px 16px;
|
||||||
|
}
|
||||||
|
div.wiki ul.toc li.heading { color: var(--md-sys-color-on-surface-variant); font: var(--md-sys-typescale-title-small); }
|
||||||
|
|
||||||
|
div.wiki pre {
|
||||||
|
margin-inline: 0;
|
||||||
|
padding: 16px;
|
||||||
|
background-color: var(--md-sys-color-surface-container);
|
||||||
|
border: 0;
|
||||||
|
border-radius: var(--md-sys-shape-corner-medium);
|
||||||
|
}
|
||||||
|
div.wiki pre .syntaxhl, .syntaxhl { background: transparent; }
|
||||||
|
div.wiki *:not(pre) > code, div.wiki > code {
|
||||||
|
background: var(--md-sys-color-surface-container-high);
|
||||||
|
border-radius: var(--md-sys-shape-corner-extra-small);
|
||||||
|
padding-block: 0.1em;
|
||||||
|
padding-inline: 0.3em;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Syntax highlighting: core Rouge colors are fixed hex values, regrouped here onto roles */
|
||||||
|
.syntaxhl :is(.c, .ch, .cm, .cpf, .c1, .cs, .cp, .go, .w) { color: var(--md-sys-color-on-surface-variant); font-weight: normal; font-style: italic; }
|
||||||
|
.syntaxhl :is(.k, .kc, .kd, .kn, .kp, .kr, .ow) { color: var(--md-sys-color-primary); font-weight: 500; }
|
||||||
|
.syntaxhl :is(.nf, .fm, .na, .nt, .nb, .bp, .nd, .gh, .gu) { color: var(--md-sys-color-primary); font-weight: normal; }
|
||||||
|
.syntaxhl :is(.kt, .nc, .nn, .no, .m, .mb, .mf, .mh, .mi, .mo, .il) { color: var(--md-sys-color-tertiary); font-weight: normal; }
|
||||||
|
.syntaxhl :is(.s, .sa, .sb, .sc, .dl, .sd, .s2, .se, .sh, .si, .sx, .sr, .s1, .ss, .gi) { color: var(--md-sys-color-success); background-color: transparent; }
|
||||||
|
.syntaxhl :is(.nv, .vc, .vg, .vi, .vm, .nl, .ni) { color: var(--md-sys-color-warning); font-weight: normal; }
|
||||||
|
.syntaxhl :is(.err, .gd, .gr, .ne, .gt) { color: var(--md-sys-color-error); background-color: transparent; }
|
||||||
|
.syntaxhl :is(.o) { color: var(--md-sys-color-on-surface); }
|
||||||
|
.syntaxhl .hll { background-color: var(--md-sys-color-secondary-container); }
|
||||||
|
|
||||||
|
/***** Activity *****/
|
||||||
|
/* One card per day (the <dl>), entries are M3 list rows. Each entry is a <dt> + <dd> pair:
|
||||||
|
dt is a grid (type icon | headline | time, project below), dd holds the clamped
|
||||||
|
description and the author. Follow-up events on the same item hang off a thread rail. */
|
||||||
|
div#activity h3 {
|
||||||
|
position: sticky;
|
||||||
|
inset-block-start: 0;
|
||||||
|
z-index: 1;
|
||||||
|
margin-block: 24px 8px;
|
||||||
|
padding-block: 8px;
|
||||||
|
padding-inline: 0;
|
||||||
|
background-color: var(--md-sys-color-surface);
|
||||||
|
color: var(--md-sys-color-on-surface);
|
||||||
|
font: var(--md-sys-typescale-title-medium);
|
||||||
|
}
|
||||||
|
div#activity h3:first-child { margin-block-start: 0; }
|
||||||
|
div#activity dl {
|
||||||
|
margin-inline-start: 0;
|
||||||
|
background-color: var(--md-sys-color-surface-container-low);
|
||||||
|
border: 1px solid var(--md-sys-color-outline-variant);
|
||||||
|
border-radius: var(--md-sys-shape-corner-medium);
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
div#activity dt, div#activity dl dt:first-child {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: 40px minmax(0, 1fr) auto;
|
||||||
|
grid-template-areas: "icon title time" "icon project time";
|
||||||
|
column-gap: 16px;
|
||||||
|
align-items: center;
|
||||||
|
inline-size: auto;
|
||||||
|
margin: 0;
|
||||||
|
padding-block: 12px 0;
|
||||||
|
padding-inline: 16px;
|
||||||
|
background: none;
|
||||||
|
border: 0;
|
||||||
|
border-block-start: 1px solid var(--md-sys-color-outline-variant);
|
||||||
|
border-radius: 0;
|
||||||
|
}
|
||||||
|
div#activity dl dt:first-child { border-block-start: 0; }
|
||||||
|
|
||||||
|
/* Leading element: type icon in a tonal circle, author avatar as a badge on it */
|
||||||
|
div#activity dt > svg.icon-svg {
|
||||||
|
grid-area: icon;
|
||||||
|
box-sizing: content-box;
|
||||||
|
padding: 11px;
|
||||||
|
margin: 0;
|
||||||
|
border-radius: var(--md-sys-shape-corner-full);
|
||||||
|
background-color: var(--md-sys-color-secondary-container);
|
||||||
|
color: var(--md-sys-color-on-secondary-container);
|
||||||
|
}
|
||||||
|
div#activity dt.issue > svg.icon-svg { background-color: var(--md-sys-color-primary-container); color: var(--md-sys-color-on-primary-container); }
|
||||||
|
div#activity dt.issue-closed > svg.icon-svg { background-color: var(--md-sys-color-success-container); color: var(--md-sys-color-on-success-container); }
|
||||||
|
div#activity dt:is(.wiki-page, .document, .news, .message, .attachment) > svg.icon-svg { background-color: var(--md-sys-color-tertiary-container); color: var(--md-sys-color-on-tertiary-container); }
|
||||||
|
div#activity dt > .avatar {
|
||||||
|
grid-area: icon;
|
||||||
|
align-self: end;
|
||||||
|
justify-self: end;
|
||||||
|
inline-size: 18px;
|
||||||
|
block-size: 18px;
|
||||||
|
margin: 0 -6px -4px 0;
|
||||||
|
font-size: 7px;
|
||||||
|
line-height: 18px;
|
||||||
|
box-shadow: 0 0 0 2px var(--md-sys-color-surface-container-low);
|
||||||
|
}
|
||||||
|
|
||||||
|
div#activity dt > a { grid-area: title; display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 2; overflow: hidden; font: var(--md-sys-typescale-title-small); }
|
||||||
|
div#activity dt .time { grid-area: time; align-self: start; margin: 0; color: var(--md-sys-color-on-surface-variant); font: var(--md-sys-typescale-label-medium); }
|
||||||
|
div#activity dt.me .time { border-block-end: 0; }
|
||||||
|
div#activity span.project { grid-area: project; color: var(--md-sys-color-on-surface-variant); font: var(--md-sys-typescale-body-small); }
|
||||||
|
div#activity span.project::after { content: none; }
|
||||||
|
|
||||||
|
div#activity dd {
|
||||||
|
margin: 0;
|
||||||
|
padding-block: 2px 12px;
|
||||||
|
padding-inline: 72px 16px; /* 16 padding + 40 icon + 16 gap: under the headline */
|
||||||
|
background: none;
|
||||||
|
border: 0;
|
||||||
|
border-radius: 0;
|
||||||
|
font: var(--md-sys-typescale-body-medium);
|
||||||
|
}
|
||||||
|
div#activity dd span.description {
|
||||||
|
display: -webkit-box;
|
||||||
|
-webkit-box-orient: vertical;
|
||||||
|
-webkit-line-clamp: 2;
|
||||||
|
overflow: hidden;
|
||||||
|
margin-block: 0 2px; /* a top margin would collapse through dd */
|
||||||
|
color: var(--md-sys-color-on-surface);
|
||||||
|
font-style: normal;
|
||||||
|
}
|
||||||
|
div#activity dd span.description:empty { display: none; }
|
||||||
|
div#activity dd .author { font: var(--md-sys-typescale-label-medium); }
|
||||||
|
/* No project line (entry from the current project): the icon still spans two rows, so pull the details up */
|
||||||
|
div#activity dt:not(:has(> .project)) + dd { margin-block-start: -20px; }
|
||||||
|
|
||||||
|
/* Thread: follow-up events hang off a rail starting under the first event's icon */
|
||||||
|
div#activity dt.grouped, div#activity dd.grouped {
|
||||||
|
margin-inline-start: 36px;
|
||||||
|
box-shadow: inset 2px 0 0 var(--md-sys-color-outline-variant);
|
||||||
|
}
|
||||||
|
div#activity dt.grouped {
|
||||||
|
grid-template-columns: 32px minmax(0, 1fr) auto;
|
||||||
|
padding-inline-start: 18px;
|
||||||
|
border-block-start: 0;
|
||||||
|
}
|
||||||
|
div#activity dt.grouped > svg.icon-svg { padding: 7px; }
|
||||||
|
div#activity dd.grouped { padding-inline-start: 66px; } /* 18 + 32 + 16 */
|
||||||
|
|
||||||
|
/***** My page: each block is a card like .box; drop zones show only while dragging *****/
|
||||||
|
.mypage-box {
|
||||||
|
padding: 16px;
|
||||||
|
background-color: var(--md-sys-color-surface-container-low);
|
||||||
|
color: var(--md-sys-color-on-surface);
|
||||||
|
border: 0;
|
||||||
|
border-radius: var(--md-sys-shape-corner-medium);
|
||||||
|
box-shadow: none;
|
||||||
|
}
|
||||||
|
.mypage-box .autoscroll { margin-block-end: 0; }
|
||||||
|
.block-receiver { border-color: transparent; border-radius: var(--md-sys-shape-corner-medium); }
|
||||||
|
.dragging .block-receiver { border-color: var(--md-sys-color-outline-variant); }
|
||||||
|
|
||||||
|
/***** Search results *****/
|
||||||
|
/* The type checkboxes' legend is only a "check all" icon: it leads their row */
|
||||||
|
#search-form fieldset.box > legend { inline-size: auto; padding: 0; margin-inline-end: 8px; }
|
||||||
|
#search-form fieldset.box > legend ~ * { clear: none; }
|
||||||
|
/* A checkbox stays with its label when the row wraps */
|
||||||
|
#search-form label { display: inline-block; white-space: nowrap; }
|
||||||
|
/* Results start at the content edge; the title wraps under its project, not beside it */
|
||||||
|
#search-results { margin-inline-start: 0; }
|
||||||
|
#search-results dt { display: block; }
|
||||||
|
div#activity dt .time, #search-results dt .time { color: var(--md-sys-color-on-surface-variant); }
|
||||||
|
#search-results dd span.description { color: var(--md-sys-color-on-surface-variant); }
|
||||||
|
|
||||||
|
/***** Projects board: each root project is a filled card *****/
|
||||||
|
#projects-index ul.projects li.root {
|
||||||
|
padding: 16px;
|
||||||
|
border: 0;
|
||||||
|
border-radius: var(--md-sys-shape-corner-medium);
|
||||||
|
background-color: var(--md-sys-color-surface-container-low);
|
||||||
|
box-shadow: none;
|
||||||
|
}
|
||||||
|
#projects-index li.root ul.projects { border-inline-start: 1px solid var(--md-sys-color-outline-variant); }
|
||||||
|
|
||||||
|
/***** Documents: one filled card per category, documents are list rows inside *****/
|
||||||
|
#document-list .document-group {
|
||||||
|
margin-block-end: 16px;
|
||||||
|
padding-block: 8px;
|
||||||
|
padding-inline: 16px;
|
||||||
|
border-radius: var(--md-sys-shape-corner-medium);
|
||||||
|
background-color: var(--md-sys-color-surface-container-low);
|
||||||
|
}
|
||||||
|
#document-list .document-group h3 {
|
||||||
|
margin: 0;
|
||||||
|
padding-block: 8px;
|
||||||
|
padding-inline: 0;
|
||||||
|
background-color: transparent;
|
||||||
|
color: var(--md-sys-color-on-surface);
|
||||||
|
font: var(--md-sys-typescale-title-medium);
|
||||||
|
}
|
||||||
|
#document-list .document-item { padding-block: 12px; }
|
||||||
|
#document-list .document-item + .document-item { border-block-start: 1px solid var(--md-sys-color-outline-variant); }
|
||||||
|
#document-list .document-group h3 + .document-item { padding-block-start: 4px; }
|
||||||
|
|
||||||
|
/***** News list: each article is a filled card *****/
|
||||||
|
#news-list article.news-article {
|
||||||
|
margin-block-end: 12px;
|
||||||
|
padding: 16px;
|
||||||
|
border-radius: var(--md-sys-shape-corner-medium);
|
||||||
|
background-color: var(--md-sys-color-surface-container-low);
|
||||||
|
}
|
||||||
|
/* Hanging indent: a wrapped title and the comment count line up past the avatar */
|
||||||
|
#news-list article.news-article header h3 {
|
||||||
|
margin-block: 0 4px;
|
||||||
|
padding-inline-start: 32px;
|
||||||
|
text-indent: -32px;
|
||||||
|
font: var(--md-sys-typescale-title-medium);
|
||||||
|
}
|
||||||
|
#news-list article.news-article header h3 .avatar { margin-inline-end: 4px; vertical-align: middle; text-indent: 0; } /* + the space after it = 8px */
|
||||||
|
/* Author and text line up with the title, past the 24px avatar and its gap */
|
||||||
|
#news-list article.news-article header p.author,
|
||||||
|
#news-list article.news-article .wiki { margin-inline-start: 32px; }
|
||||||
|
#news-list article.news-article header p.author { margin-block: 0 8px; color: var(--md-sys-color-on-surface-variant); }
|
||||||
|
#news-list article.news-article .wiki > :last-child { margin-block-end: 0; }
|
||||||
|
|
||||||
|
/***** Workflow: allowed transitions use the selected state *****/
|
||||||
|
table.transitions td.enabled { background-color: var(--md-sys-color-secondary-container); color: var(--md-sys-color-on-secondary-container); }
|
||||||
|
table.fields_permissions td.readonly { background-color: var(--md-sys-color-surface-container-highest); }
|
||||||
|
table.fields_permissions td.required { background-color: var(--md-sys-color-error-container); color: var(--md-sys-color-on-error-container); }
|
||||||
|
|
||||||
|
/***** Attachments, diffs, imports, headings *****/
|
||||||
|
div.thumbnail {
|
||||||
|
overflow: hidden;
|
||||||
|
border: 1px solid var(--md-sys-color-outline-variant);
|
||||||
|
border-radius: var(--md-sys-shape-corner-small);
|
||||||
|
background: transparent;
|
||||||
|
}
|
||||||
|
div.thumbnail img { margin: 0; }
|
||||||
|
pre.text-diff {
|
||||||
|
padding: 16px;
|
||||||
|
border-color: var(--md-sys-color-outline-variant);
|
||||||
|
border-radius: var(--md-sys-shape-corner-medium);
|
||||||
|
}
|
||||||
|
h2 .avatar, h3 .avatar { margin-inline-end: 8px; }
|
||||||
|
/* "Replies (2)": the icon heading is a flex row, which drops the space before the count */
|
||||||
|
h3.comments .icon-label { margin-inline-end: 0.25em; }
|
||||||
|
#wiki_page_parent_id { min-inline-size: 240px; }
|
||||||
|
select#columns, select#criterias { margin-inline: 8px 16px; }
|
||||||
|
input#months { inline-size: 72px; }
|
||||||
|
/* Tabs start below the floated page actions, so their divider spans the page */
|
||||||
|
#content > .tabs { clear: both; }
|
||||||
|
|
||||||
|
/***** Roadmap *****/
|
||||||
|
div#roadmap .version-article {
|
||||||
|
padding: 16px;
|
||||||
|
margin-block-end: 16px;
|
||||||
|
border: 1px solid var(--md-sys-color-outline-variant);
|
||||||
|
border-radius: var(--md-sys-shape-corner-medium);
|
||||||
|
}
|
||||||
|
div#roadmap header:target { background-color: var(--md-sys-color-secondary-container); }
|
||||||
|
div#version-summary { background-color: transparent; }
|
||||||
|
|
||||||
|
/* Overview and issue table share one left edge (core indents the overview by 1.5rem) */
|
||||||
|
div#roadmap article.version-article .version-overview,
|
||||||
|
div#roadmap article.version-article .wiki,
|
||||||
|
div#roadmap article.version-article form { padding-inline-start: 0; }
|
||||||
|
div#roadmap .related-issues td.assigned_to { padding-inline: 12px 4px; }
|
||||||
|
div#roadmap .related-issues caption { padding-block-end: 8px; color: var(--md-sys-color-on-surface-variant); font: var(--md-sys-typescale-title-small); }
|
||||||
|
|
||||||
|
/* Progress bar spans the width of the issue table below it; the percentage sits at its end */
|
||||||
|
.version-overview table.progress { inline-size: calc(100% - 56px); margin-block: 6px; }
|
||||||
|
.version-overview p.percent { font: var(--md-sys-typescale-label-large); line-height: 20px; text-align: end; }
|
||||||
|
.version-overview p.progress-info { margin-block: 4px 0; color: var(--md-sys-color-on-surface-variant); font: var(--md-sys-typescale-body-small); }
|
||||||
|
/* Version page: the issue table is 70% wide next to the summary */
|
||||||
|
body.controller-versions.action-show .version-overview table.progress { inline-size: calc(70% - 56px); }
|
||||||
|
body.controller-versions.action-show .version-overview p.percent { inline-size: 70%; }
|
||||||
|
|
||||||
|
/***** Calendar *****/
|
||||||
|
ul.cal {
|
||||||
|
overflow: hidden;
|
||||||
|
border-color: var(--md-sys-color-outline-variant);
|
||||||
|
border-radius: var(--md-sys-shape-corner-medium);
|
||||||
|
box-shadow: none;
|
||||||
|
}
|
||||||
|
.cal .calbody { box-shadow: none; }
|
||||||
|
.cal .calhead, .cal .week-number { background-color: var(--md-sys-color-surface-container); color: var(--md-sys-color-on-surface-variant); }
|
||||||
|
.cal .calbody { border-color: var(--md-sys-color-outline-variant); }
|
||||||
|
.cal .calbody.this-month { background-color: var(--md-sys-color-surface); }
|
||||||
|
.cal .calbody.other-month, .cal .calbody.nwday:not(.other-month) { background-color: var(--md-sys-color-surface-container-low); }
|
||||||
|
.cal .calbody.today .day-value { color: var(--md-sys-color-on-primary); }
|
||||||
|
|
||||||
|
/***** Gantt (gantt.css loads after the theme, hence the `html` prefix) *****/
|
||||||
|
/*
|
||||||
|
* Geometry is set inline by Redmine: rows every 20px, each with a 16px text line whose top is
|
||||||
|
* `header height + 8 + 20n` in the subjects column and `7 + 20n` inside #gantt_draw_area.
|
||||||
|
* Bars are centered on that 16px line; row bands run from 2px above to 2px below it.
|
||||||
|
*/
|
||||||
|
:root {
|
||||||
|
--nm-gantt-band: color-mix(in srgb, var(--md-sys-color-on-surface) 4%, transparent);
|
||||||
|
--nm-gantt-rows: repeating-linear-gradient(to bottom, var(--nm-gantt-band) 0 20px, transparent 20px 40px);
|
||||||
|
--nm-gantt-track: color-mix(in srgb, var(--md-sys-color-primary) 25%, var(--md-sys-color-surface-container-highest));
|
||||||
|
--nm-gantt-subjects-offset: 2px; /* (header height + 6) mod 20; the header has one 18px row per zoom level */
|
||||||
|
}
|
||||||
|
:root:has(#zoom[value="1"]) { --nm-gantt-subjects-offset: 4px; }
|
||||||
|
:root:has(#zoom[value="3"]) { --nm-gantt-subjects-offset: 0px; }
|
||||||
|
:root:has(#zoom[value="4"]) { --nm-gantt-subjects-offset: 18px; }
|
||||||
|
|
||||||
|
/* Redmine's geometry is fixed at 20px rows; `zoom` scales rows, bars, text and positions together.
|
||||||
|
The relation/progress SVG is drawn by JS from on-screen (already zoomed) positions, so it must
|
||||||
|
not be zoomed a second time. */
|
||||||
|
:root { --nm-gantt-zoom: 1.3; }
|
||||||
|
html table.gantt-table { zoom: var(--nm-gantt-zoom); }
|
||||||
|
html #gantt_draw_area svg { zoom: calc(1 / var(--nm-gantt-zoom)); overflow: visible; }
|
||||||
|
|
||||||
|
html #gantt_draw_area { background: var(--nm-gantt-rows) 0 5px; }
|
||||||
|
html .gantt_subjects_container { background: var(--nm-gantt-rows) 0 var(--nm-gantt-subjects-offset); }
|
||||||
|
|
||||||
|
/* Header: months / weeks / days */
|
||||||
|
html .gantt_hdr { border-color: var(--md-sys-color-outline-variant); color: var(--md-sys-color-on-surface-variant); font: var(--md-sys-typescale-label-medium); line-height: 18px; }
|
||||||
|
html .gantt_hdr[style*="background"] { background: var(--md-sys-color-surface-container) !important; }
|
||||||
|
html .gantt_hdr.nwday { background-color: color-mix(in srgb, var(--md-sys-color-on-surface) 5%, transparent); color: var(--md-sys-color-on-surface-variant); }
|
||||||
|
html .gantt_hdr a { color: var(--md-sys-color-on-surface-variant); }
|
||||||
|
|
||||||
|
/* Subjects */
|
||||||
|
html .gantt_subjects, html .gantt_selected_column_content.gantt_hdr { font: var(--md-sys-typescale-body-small); letter-spacing: var(--md-sys-typescale-body-small-tracking); }
|
||||||
|
html .gantt_subjects div { line-height: 16px; }
|
||||||
|
html .gantt_subjects div.issue-subject:hover { background-color: color-mix(in srgb, var(--md-sys-color-on-surface) var(--md-sys-state-hover-state-layer-opacity), transparent); }
|
||||||
|
html .gantt_subjects div.project-name, html .gantt_subjects div.version-name { font-weight: 500; }
|
||||||
|
|
||||||
|
/* Issue bars: 10px pills centered on the text line (core: 8px at the top of it) */
|
||||||
|
html .task_todo, html .task_done, html .task_late {
|
||||||
|
block-size: 10px;
|
||||||
|
margin-block-start: 3px;
|
||||||
|
box-sizing: border-box;
|
||||||
|
border-radius: var(--md-sys-shape-corner-full);
|
||||||
|
background-image: none;
|
||||||
|
}
|
||||||
|
html .task_todo { background-color: var(--nm-gantt-track); border-color: var(--nm-gantt-track); }
|
||||||
|
html .task_done { background-color: var(--md-sys-color-primary); border-color: var(--md-sys-color-primary); }
|
||||||
|
html .task_late { background-color: var(--md-sys-color-error); border-color: var(--md-sys-color-error); }
|
||||||
|
|
||||||
|
/* Parent issues: thin bar with triangles at both ends */
|
||||||
|
html .task_todo.parent, html .task_done.parent, html .task_late.parent { block-size: 4px; margin-block-start: 6px; border-radius: 0; }
|
||||||
|
html .task_todo.parent { background-color: var(--md-sys-color-on-surface-variant); border-color: var(--md-sys-color-on-surface-variant); }
|
||||||
|
html .task.parent.marker.starting, html .task.parent.marker.ending {
|
||||||
|
background: var(--md-sys-color-on-surface-variant);
|
||||||
|
clip-path: polygon(0 7px, 8px 7px, 4px 14px);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Project and version milestones: 2px line with a diamond marker */
|
||||||
|
html .project.task_todo, html .project.task_done, html .project.task_late,
|
||||||
|
html .version.task_todo, html .version.task_done, html .version.task_late {
|
||||||
|
block-size: 2px;
|
||||||
|
margin-block-start: 7px;
|
||||||
|
border: 0;
|
||||||
|
border-radius: 0;
|
||||||
|
}
|
||||||
|
html :is(.project, .version):is(.task_todo, .task_done, .task_late) { background-image: none; }
|
||||||
|
html :is(.project, .version).task_todo { background-color: var(--md-sys-color-outline); }
|
||||||
|
html :is(.project, .version).task_done { background-color: var(--md-sys-color-primary); }
|
||||||
|
html :is(.project, .version).task_late { background-color: var(--md-sys-color-error); }
|
||||||
|
html .version.marker, html .project.marker {
|
||||||
|
block-size: 10px;
|
||||||
|
margin-block-start: 3px;
|
||||||
|
background: var(--md-sys-color-tertiary);
|
||||||
|
clip-path: polygon(4px 0, 8px 5px, 4px 10px, 0 5px);
|
||||||
|
}
|
||||||
|
html .project.marker { background: var(--md-sys-color-primary); }
|
||||||
|
|
||||||
|
/* Labels next to bars ("New 80%") */
|
||||||
|
html .task { color: var(--md-sys-color-on-surface-variant); font: var(--md-sys-typescale-label-small); line-height: 16px; }
|
||||||
|
html .task.label.project, html .task.label.version { color: var(--md-sys-color-on-surface); font-weight: 500; }
|
||||||
|
html .version-behind-schedule a, html .issue-behind-schedule a { color: var(--md-sys-color-warning); }
|
||||||
|
html .version-overdue a, html .issue-overdue a, html .project-overdue a { color: var(--md-sys-color-error); }
|
||||||
|
|
||||||
|
/* Today line (inline style); the progress line takes its color from it */
|
||||||
|
html #today_line { border-inline-start: 2px solid var(--md-sys-color-error) !important; }
|
||||||
|
|
||||||
|
/* Relation arrows are drawn with fixed colors per relation type */
|
||||||
|
html #gantt_draw_area path[stroke="#228be6"] { stroke: var(--md-sys-color-primary); }
|
||||||
|
html #gantt_draw_area path[fill="#228be6"] { fill: var(--md-sys-color-primary); }
|
||||||
|
html #gantt_draw_area path[stroke="#fa5252"] { stroke: var(--md-sys-color-error); }
|
||||||
|
html #gantt_draw_area path[fill="#fa5252"] { fill: var(--md-sys-color-error); }
|
||||||
|
|
||||||
|
/***** Issue context menu (context_menu.css loads after the theme) *****/
|
||||||
|
html #context-menu { font: var(--md-sys-typescale-label-large); }
|
||||||
|
html #context-menu ul {
|
||||||
|
background: var(--md-sys-color-surface-container);
|
||||||
|
border: 0;
|
||||||
|
border-radius: var(--md-sys-shape-corner-extra-small);
|
||||||
|
box-shadow: var(--md-sys-elevation-level2);
|
||||||
|
padding-block: 8px;
|
||||||
|
}
|
||||||
|
html #context-menu li { border: 0; border-radius: 0; }
|
||||||
|
html #context-menu li:hover { border: 0; border-radius: 0; background-color: color-mix(in srgb, var(--md-sys-color-on-surface) var(--md-sys-state-hover-state-layer-opacity), transparent); }
|
||||||
|
html #context-menu a { color: var(--md-sys-color-on-surface); padding-block: 8px; }
|
||||||
|
html #context-menu a:hover { color: var(--md-sys-color-on-surface); text-decoration: none; }
|
||||||
|
html #context-menu a.disabled, html #context-menu a.disabled:hover { color: color-mix(in srgb, var(--md-sys-color-on-surface) var(--md-sys-state-disabled-content-opacity), transparent); }
|
||||||
|
html #context-menu a.disabled svg.icon-svg { color: inherit; }
|
||||||
|
|
||||||
|
.cal .calbody div.issue {
|
||||||
|
margin-block: 4px;
|
||||||
|
padding-block: 4px;
|
||||||
|
padding-inline: 8px;
|
||||||
|
background-color: var(--md-sys-color-surface-container);
|
||||||
|
border-radius: var(--md-sys-shape-corner-small);
|
||||||
|
font: var(--md-sys-typescale-body-small);
|
||||||
|
}
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
/*
|
||||||
|
* Generated by tools/palettes/build_palettes.mjs; do not edit by hand.
|
||||||
|
* M3 color roles (TonalSpot, contrast 0) per palette, light and dark.
|
||||||
|
* <html data-palette="..."> picks the palette, <html data-mode="light|dark"> forces a mode;
|
||||||
|
* without data-mode the OS setting (prefers-color-scheme) decides.
|
||||||
|
*/
|
||||||
|
|
||||||
|
:root { color-scheme: light; }
|
||||||
|
:root[data-mode="dark"] { color-scheme: dark; }
|
||||||
|
@media (prefers-color-scheme: dark) { :root:not([data-mode="light"]) { color-scheme: dark; } }
|
||||||
|
|
||||||
|
/* purple (seed #6750A4) */
|
||||||
|
:root { --md-sys-color-primary: #65558f; --md-sys-color-on-primary: #ffffff; --md-sys-color-primary-container: #e9ddff; --md-sys-color-on-primary-container: #4d3d75; --md-sys-color-inverse-primary: #cfbdfe; --md-sys-color-secondary: #625b71; --md-sys-color-on-secondary: #ffffff; --md-sys-color-secondary-container: #e8def8; --md-sys-color-on-secondary-container: #4a4458; --md-sys-color-tertiary: #7e5260; --md-sys-color-on-tertiary: #ffffff; --md-sys-color-tertiary-container: #ffd9e3; --md-sys-color-on-tertiary-container: #633b48; --md-sys-color-error: #ba1a1a; --md-sys-color-on-error: #ffffff; --md-sys-color-error-container: #ffdad6; --md-sys-color-on-error-container: #93000a; --md-sys-color-background: #fdf7ff; --md-sys-color-on-background: #1d1b20; --md-sys-color-surface: #fdf7ff; --md-sys-color-surface-dim: #ded8e0; --md-sys-color-surface-bright: #fdf7ff; --md-sys-color-surface-container-lowest: #ffffff; --md-sys-color-surface-container-low: #f8f2fa; --md-sys-color-surface-container: #f2ecf4; --md-sys-color-surface-container-high: #ece6ee; --md-sys-color-surface-container-highest: #e6e0e9; --md-sys-color-on-surface: #1d1b20; --md-sys-color-surface-variant: #e7e0eb; --md-sys-color-on-surface-variant: #49454e; --md-sys-color-inverse-surface: #322f35; --md-sys-color-inverse-on-surface: #f5eff7; --md-sys-color-outline: #7a757f; --md-sys-color-outline-variant: #cac4cf; --md-sys-color-shadow: #000000; --md-sys-color-scrim: #000000; --md-sys-color-surface-tint: #65558f; --md-sys-color-success: #0a6d36; --md-sys-color-on-success: #ffffff; --md-sys-color-success-container: #9ef6b0; --md-sys-color-on-success-container: #00210b; --md-sys-color-warning: #885200; --md-sys-color-on-warning: #ffffff; --md-sys-color-warning-container: #ffddbb; --md-sys-color-on-warning-container: #2b1700; }
|
||||||
|
:root[data-mode="dark"] { --md-sys-color-primary: #cfbdfe; --md-sys-color-on-primary: #36275d; --md-sys-color-primary-container: #4d3d75; --md-sys-color-on-primary-container: #e9ddff; --md-sys-color-inverse-primary: #65558f; --md-sys-color-secondary: #cbc2db; --md-sys-color-on-secondary: #332d41; --md-sys-color-secondary-container: #4a4458; --md-sys-color-on-secondary-container: #e8def8; --md-sys-color-tertiary: #efb8c8; --md-sys-color-on-tertiary: #4a2532; --md-sys-color-tertiary-container: #633b48; --md-sys-color-on-tertiary-container: #ffd9e3; --md-sys-color-error: #ffb4ab; --md-sys-color-on-error: #690005; --md-sys-color-error-container: #93000a; --md-sys-color-on-error-container: #ffdad6; --md-sys-color-background: #141218; --md-sys-color-on-background: #e6e0e9; --md-sys-color-surface: #141218; --md-sys-color-surface-dim: #141218; --md-sys-color-surface-bright: #3b383e; --md-sys-color-surface-container-lowest: #0f0d13; --md-sys-color-surface-container-low: #1d1b20; --md-sys-color-surface-container: #211f24; --md-sys-color-surface-container-high: #2b292f; --md-sys-color-surface-container-highest: #36343a; --md-sys-color-on-surface: #e6e0e9; --md-sys-color-surface-variant: #49454e; --md-sys-color-on-surface-variant: #cac4cf; --md-sys-color-inverse-surface: #e6e0e9; --md-sys-color-inverse-on-surface: #322f35; --md-sys-color-outline: #948f99; --md-sys-color-outline-variant: #49454e; --md-sys-color-shadow: #000000; --md-sys-color-scrim: #000000; --md-sys-color-surface-tint: #cfbdfe; --md-sys-color-success: #82d996; --md-sys-color-on-success: #003918; --md-sys-color-success-container: #005226; --md-sys-color-on-success-container: #9ef6b0; --md-sys-color-warning: #ffb869; --md-sys-color-on-warning: #482900; --md-sys-color-warning-container: #673d00; --md-sys-color-on-warning-container: #ffddbb; }
|
||||||
|
@media (prefers-color-scheme: dark) { :root:not([data-mode="light"]) { --md-sys-color-primary: #cfbdfe; --md-sys-color-on-primary: #36275d; --md-sys-color-primary-container: #4d3d75; --md-sys-color-on-primary-container: #e9ddff; --md-sys-color-inverse-primary: #65558f; --md-sys-color-secondary: #cbc2db; --md-sys-color-on-secondary: #332d41; --md-sys-color-secondary-container: #4a4458; --md-sys-color-on-secondary-container: #e8def8; --md-sys-color-tertiary: #efb8c8; --md-sys-color-on-tertiary: #4a2532; --md-sys-color-tertiary-container: #633b48; --md-sys-color-on-tertiary-container: #ffd9e3; --md-sys-color-error: #ffb4ab; --md-sys-color-on-error: #690005; --md-sys-color-error-container: #93000a; --md-sys-color-on-error-container: #ffdad6; --md-sys-color-background: #141218; --md-sys-color-on-background: #e6e0e9; --md-sys-color-surface: #141218; --md-sys-color-surface-dim: #141218; --md-sys-color-surface-bright: #3b383e; --md-sys-color-surface-container-lowest: #0f0d13; --md-sys-color-surface-container-low: #1d1b20; --md-sys-color-surface-container: #211f24; --md-sys-color-surface-container-high: #2b292f; --md-sys-color-surface-container-highest: #36343a; --md-sys-color-on-surface: #e6e0e9; --md-sys-color-surface-variant: #49454e; --md-sys-color-on-surface-variant: #cac4cf; --md-sys-color-inverse-surface: #e6e0e9; --md-sys-color-inverse-on-surface: #322f35; --md-sys-color-outline: #948f99; --md-sys-color-outline-variant: #49454e; --md-sys-color-shadow: #000000; --md-sys-color-scrim: #000000; --md-sys-color-surface-tint: #cfbdfe; --md-sys-color-success: #82d996; --md-sys-color-on-success: #003918; --md-sys-color-success-container: #005226; --md-sys-color-on-success-container: #9ef6b0; --md-sys-color-warning: #ffb869; --md-sys-color-on-warning: #482900; --md-sys-color-warning-container: #673d00; --md-sys-color-on-warning-container: #ffddbb; } }
|
||||||
|
|
||||||
|
/* blue (seed #0061A4) */
|
||||||
|
:root[data-palette="blue"] { --md-sys-color-primary: #36618e; --md-sys-color-on-primary: #ffffff; --md-sys-color-primary-container: #d1e4ff; --md-sys-color-on-primary-container: #1a4975; --md-sys-color-inverse-primary: #a0cafd; --md-sys-color-secondary: #535f70; --md-sys-color-on-secondary: #ffffff; --md-sys-color-secondary-container: #d7e3f8; --md-sys-color-on-secondary-container: #3b4858; --md-sys-color-tertiary: #6b5778; --md-sys-color-on-tertiary: #ffffff; --md-sys-color-tertiary-container: #f3daff; --md-sys-color-on-tertiary-container: #523f5f; --md-sys-color-error: #ba1a1a; --md-sys-color-on-error: #ffffff; --md-sys-color-error-container: #ffdad6; --md-sys-color-on-error-container: #93000a; --md-sys-color-background: #f8f9ff; --md-sys-color-on-background: #191c20; --md-sys-color-surface: #f8f9ff; --md-sys-color-surface-dim: #d8dae0; --md-sys-color-surface-bright: #f8f9ff; --md-sys-color-surface-container-lowest: #ffffff; --md-sys-color-surface-container-low: #f2f3fa; --md-sys-color-surface-container: #eceef4; --md-sys-color-surface-container-high: #e6e8ee; --md-sys-color-surface-container-highest: #e1e2e8; --md-sys-color-on-surface: #191c20; --md-sys-color-surface-variant: #dfe2eb; --md-sys-color-on-surface-variant: #43474e; --md-sys-color-inverse-surface: #2e3135; --md-sys-color-inverse-on-surface: #eff0f7; --md-sys-color-outline: #73777f; --md-sys-color-outline-variant: #c3c6cf; --md-sys-color-shadow: #000000; --md-sys-color-scrim: #000000; --md-sys-color-surface-tint: #36618e; --md-sys-color-success: #0a6d36; --md-sys-color-on-success: #ffffff; --md-sys-color-success-container: #9ef6b0; --md-sys-color-on-success-container: #00210b; --md-sys-color-warning: #6f5d00; --md-sys-color-on-warning: #ffffff; --md-sys-color-warning-container: #ffe16a; --md-sys-color-on-warning-container: #221b00; }
|
||||||
|
:root[data-palette="blue"][data-mode="dark"] { --md-sys-color-primary: #a0cafd; --md-sys-color-on-primary: #003258; --md-sys-color-primary-container: #1a4975; --md-sys-color-on-primary-container: #d1e4ff; --md-sys-color-inverse-primary: #36618e; --md-sys-color-secondary: #bbc7db; --md-sys-color-on-secondary: #253140; --md-sys-color-secondary-container: #3b4858; --md-sys-color-on-secondary-container: #d7e3f8; --md-sys-color-tertiary: #d7bee4; --md-sys-color-on-tertiary: #3b2948; --md-sys-color-tertiary-container: #523f5f; --md-sys-color-on-tertiary-container: #f3daff; --md-sys-color-error: #ffb4ab; --md-sys-color-on-error: #690005; --md-sys-color-error-container: #93000a; --md-sys-color-on-error-container: #ffdad6; --md-sys-color-background: #111418; --md-sys-color-on-background: #e1e2e8; --md-sys-color-surface: #111418; --md-sys-color-surface-dim: #111418; --md-sys-color-surface-bright: #36393e; --md-sys-color-surface-container-lowest: #0b0e13; --md-sys-color-surface-container-low: #191c20; --md-sys-color-surface-container: #1d2024; --md-sys-color-surface-container-high: #272a2f; --md-sys-color-surface-container-highest: #32353a; --md-sys-color-on-surface: #e1e2e8; --md-sys-color-surface-variant: #43474e; --md-sys-color-on-surface-variant: #c3c6cf; --md-sys-color-inverse-surface: #e1e2e8; --md-sys-color-inverse-on-surface: #2e3135; --md-sys-color-outline: #8d9199; --md-sys-color-outline-variant: #43474e; --md-sys-color-shadow: #000000; --md-sys-color-scrim: #000000; --md-sys-color-surface-tint: #a0cafd; --md-sys-color-success: #82d996; --md-sys-color-on-success: #003918; --md-sys-color-success-container: #005226; --md-sys-color-on-success-container: #9ef6b0; --md-sys-color-warning: #e2c54a; --md-sys-color-on-warning: #3a3000; --md-sys-color-warning-container: #544600; --md-sys-color-on-warning-container: #ffe16a; }
|
||||||
|
@media (prefers-color-scheme: dark) { :root[data-palette="blue"]:not([data-mode="light"]) { --md-sys-color-primary: #a0cafd; --md-sys-color-on-primary: #003258; --md-sys-color-primary-container: #1a4975; --md-sys-color-on-primary-container: #d1e4ff; --md-sys-color-inverse-primary: #36618e; --md-sys-color-secondary: #bbc7db; --md-sys-color-on-secondary: #253140; --md-sys-color-secondary-container: #3b4858; --md-sys-color-on-secondary-container: #d7e3f8; --md-sys-color-tertiary: #d7bee4; --md-sys-color-on-tertiary: #3b2948; --md-sys-color-tertiary-container: #523f5f; --md-sys-color-on-tertiary-container: #f3daff; --md-sys-color-error: #ffb4ab; --md-sys-color-on-error: #690005; --md-sys-color-error-container: #93000a; --md-sys-color-on-error-container: #ffdad6; --md-sys-color-background: #111418; --md-sys-color-on-background: #e1e2e8; --md-sys-color-surface: #111418; --md-sys-color-surface-dim: #111418; --md-sys-color-surface-bright: #36393e; --md-sys-color-surface-container-lowest: #0b0e13; --md-sys-color-surface-container-low: #191c20; --md-sys-color-surface-container: #1d2024; --md-sys-color-surface-container-high: #272a2f; --md-sys-color-surface-container-highest: #32353a; --md-sys-color-on-surface: #e1e2e8; --md-sys-color-surface-variant: #43474e; --md-sys-color-on-surface-variant: #c3c6cf; --md-sys-color-inverse-surface: #e1e2e8; --md-sys-color-inverse-on-surface: #2e3135; --md-sys-color-outline: #8d9199; --md-sys-color-outline-variant: #43474e; --md-sys-color-shadow: #000000; --md-sys-color-scrim: #000000; --md-sys-color-surface-tint: #a0cafd; --md-sys-color-success: #82d996; --md-sys-color-on-success: #003918; --md-sys-color-success-container: #005226; --md-sys-color-on-success-container: #9ef6b0; --md-sys-color-warning: #e2c54a; --md-sys-color-on-warning: #3a3000; --md-sys-color-warning-container: #544600; --md-sys-color-on-warning-container: #ffe16a; } }
|
||||||
|
|
||||||
|
/* teal (seed #006A6A) */
|
||||||
|
:root[data-palette="teal"] { --md-sys-color-primary: #006a6a; --md-sys-color-on-primary: #ffffff; --md-sys-color-primary-container: #9cf1f0; --md-sys-color-on-primary-container: #004f4f; --md-sys-color-inverse-primary: #80d5d4; --md-sys-color-secondary: #4a6363; --md-sys-color-on-secondary: #ffffff; --md-sys-color-secondary-container: #cce8e7; --md-sys-color-on-secondary-container: #324b4b; --md-sys-color-tertiary: #4b607c; --md-sys-color-on-tertiary: #ffffff; --md-sys-color-tertiary-container: #d3e4ff; --md-sys-color-on-tertiary-container: #334863; --md-sys-color-error: #ba1a1a; --md-sys-color-on-error: #ffffff; --md-sys-color-error-container: #ffdad6; --md-sys-color-on-error-container: #93000a; --md-sys-color-background: #f4fbfa; --md-sys-color-on-background: #161d1d; --md-sys-color-surface: #f4fbfa; --md-sys-color-surface-dim: #d5dbda; --md-sys-color-surface-bright: #f4fbfa; --md-sys-color-surface-container-lowest: #ffffff; --md-sys-color-surface-container-low: #eff5f4; --md-sys-color-surface-container: #e9efee; --md-sys-color-surface-container-high: #e3e9e9; --md-sys-color-surface-container-highest: #dde4e3; --md-sys-color-on-surface: #161d1d; --md-sys-color-surface-variant: #dae5e4; --md-sys-color-on-surface-variant: #3f4948; --md-sys-color-inverse-surface: #2b3231; --md-sys-color-inverse-on-surface: #ecf2f1; --md-sys-color-outline: #6f7979; --md-sys-color-outline-variant: #bec9c8; --md-sys-color-shadow: #000000; --md-sys-color-scrim: #000000; --md-sys-color-surface-tint: #006a6a; --md-sys-color-success: #0a6d36; --md-sys-color-on-success: #ffffff; --md-sys-color-success-container: #9ef6b0; --md-sys-color-on-success-container: #00210b; --md-sys-color-warning: #6f5d00; --md-sys-color-on-warning: #ffffff; --md-sys-color-warning-container: #ffe16a; --md-sys-color-on-warning-container: #221b00; }
|
||||||
|
:root[data-palette="teal"][data-mode="dark"] { --md-sys-color-primary: #80d5d4; --md-sys-color-on-primary: #003737; --md-sys-color-primary-container: #004f4f; --md-sys-color-on-primary-container: #9cf1f0; --md-sys-color-inverse-primary: #006a6a; --md-sys-color-secondary: #b0cccb; --md-sys-color-on-secondary: #1b3534; --md-sys-color-secondary-container: #324b4b; --md-sys-color-on-secondary-container: #cce8e7; --md-sys-color-tertiary: #b3c8e8; --md-sys-color-on-tertiary: #1c314b; --md-sys-color-tertiary-container: #334863; --md-sys-color-on-tertiary-container: #d3e4ff; --md-sys-color-error: #ffb4ab; --md-sys-color-on-error: #690005; --md-sys-color-error-container: #93000a; --md-sys-color-on-error-container: #ffdad6; --md-sys-color-background: #0e1514; --md-sys-color-on-background: #dde4e3; --md-sys-color-surface: #0e1514; --md-sys-color-surface-dim: #0e1514; --md-sys-color-surface-bright: #343a3a; --md-sys-color-surface-container-lowest: #090f0f; --md-sys-color-surface-container-low: #161d1d; --md-sys-color-surface-container: #1a2121; --md-sys-color-surface-container-high: #252b2b; --md-sys-color-surface-container-highest: #2f3636; --md-sys-color-on-surface: #dde4e3; --md-sys-color-surface-variant: #3f4948; --md-sys-color-on-surface-variant: #bec9c8; --md-sys-color-inverse-surface: #dde4e3; --md-sys-color-inverse-on-surface: #2b3231; --md-sys-color-outline: #889392; --md-sys-color-outline-variant: #3f4948; --md-sys-color-shadow: #000000; --md-sys-color-scrim: #000000; --md-sys-color-surface-tint: #80d5d4; --md-sys-color-success: #82d996; --md-sys-color-on-success: #003918; --md-sys-color-success-container: #005226; --md-sys-color-on-success-container: #9ef6b0; --md-sys-color-warning: #e2c54a; --md-sys-color-on-warning: #3a3000; --md-sys-color-warning-container: #544600; --md-sys-color-on-warning-container: #ffe16a; }
|
||||||
|
@media (prefers-color-scheme: dark) { :root[data-palette="teal"]:not([data-mode="light"]) { --md-sys-color-primary: #80d5d4; --md-sys-color-on-primary: #003737; --md-sys-color-primary-container: #004f4f; --md-sys-color-on-primary-container: #9cf1f0; --md-sys-color-inverse-primary: #006a6a; --md-sys-color-secondary: #b0cccb; --md-sys-color-on-secondary: #1b3534; --md-sys-color-secondary-container: #324b4b; --md-sys-color-on-secondary-container: #cce8e7; --md-sys-color-tertiary: #b3c8e8; --md-sys-color-on-tertiary: #1c314b; --md-sys-color-tertiary-container: #334863; --md-sys-color-on-tertiary-container: #d3e4ff; --md-sys-color-error: #ffb4ab; --md-sys-color-on-error: #690005; --md-sys-color-error-container: #93000a; --md-sys-color-on-error-container: #ffdad6; --md-sys-color-background: #0e1514; --md-sys-color-on-background: #dde4e3; --md-sys-color-surface: #0e1514; --md-sys-color-surface-dim: #0e1514; --md-sys-color-surface-bright: #343a3a; --md-sys-color-surface-container-lowest: #090f0f; --md-sys-color-surface-container-low: #161d1d; --md-sys-color-surface-container: #1a2121; --md-sys-color-surface-container-high: #252b2b; --md-sys-color-surface-container-highest: #2f3636; --md-sys-color-on-surface: #dde4e3; --md-sys-color-surface-variant: #3f4948; --md-sys-color-on-surface-variant: #bec9c8; --md-sys-color-inverse-surface: #dde4e3; --md-sys-color-inverse-on-surface: #2b3231; --md-sys-color-outline: #889392; --md-sys-color-outline-variant: #3f4948; --md-sys-color-shadow: #000000; --md-sys-color-scrim: #000000; --md-sys-color-surface-tint: #80d5d4; --md-sys-color-success: #82d996; --md-sys-color-on-success: #003918; --md-sys-color-success-container: #005226; --md-sys-color-on-success-container: #9ef6b0; --md-sys-color-warning: #e2c54a; --md-sys-color-on-warning: #3a3000; --md-sys-color-warning-container: #544600; --md-sys-color-on-warning-container: #ffe16a; } }
|
||||||
|
|
||||||
|
/* green (seed #386A20) */
|
||||||
|
:root[data-palette="green"] { --md-sys-color-primary: #446732; --md-sys-color-on-primary: #ffffff; --md-sys-color-primary-container: #c5efab; --md-sys-color-on-primary-container: #2d4f1c; --md-sys-color-inverse-primary: #a9d291; --md-sys-color-secondary: #55624c; --md-sys-color-on-secondary: #ffffff; --md-sys-color-secondary-container: #d8e7cb; --md-sys-color-on-secondary-container: #3e4a35; --md-sys-color-tertiary: #386666; --md-sys-color-on-tertiary: #ffffff; --md-sys-color-tertiary-container: #bbebec; --md-sys-color-on-tertiary-container: #1e4e4f; --md-sys-color-error: #ba1a1a; --md-sys-color-on-error: #ffffff; --md-sys-color-error-container: #ffdad6; --md-sys-color-on-error-container: #93000a; --md-sys-color-background: #f8faf0; --md-sys-color-on-background: #191d16; --md-sys-color-surface: #f8faf0; --md-sys-color-surface-dim: #d9dbd1; --md-sys-color-surface-bright: #f8faf0; --md-sys-color-surface-container-lowest: #ffffff; --md-sys-color-surface-container-low: #f2f5ea; --md-sys-color-surface-container: #edefe5; --md-sys-color-surface-container-high: #e7e9df; --md-sys-color-surface-container-highest: #e1e4d9; --md-sys-color-on-surface: #191d16; --md-sys-color-surface-variant: #dfe4d7; --md-sys-color-on-surface-variant: #43483e; --md-sys-color-inverse-surface: #2e312b; --md-sys-color-inverse-on-surface: #f0f2e7; --md-sys-color-outline: #74796d; --md-sys-color-outline-variant: #c3c8bb; --md-sys-color-shadow: #000000; --md-sys-color-scrim: #000000; --md-sys-color-surface-tint: #446732; --md-sys-color-success: #386a1f; --md-sys-color-on-success: #ffffff; --md-sys-color-success-container: #b8f397; --md-sys-color-on-success-container: #072100; --md-sys-color-warning: #6f5d00; --md-sys-color-on-warning: #ffffff; --md-sys-color-warning-container: #ffe16a; --md-sys-color-on-warning-container: #221b00; }
|
||||||
|
:root[data-palette="green"][data-mode="dark"] { --md-sys-color-primary: #a9d291; --md-sys-color-on-primary: #173807; --md-sys-color-primary-container: #2d4f1c; --md-sys-color-on-primary-container: #c5efab; --md-sys-color-inverse-primary: #446732; --md-sys-color-secondary: #bdcbb0; --md-sys-color-on-secondary: #283420; --md-sys-color-secondary-container: #3e4a35; --md-sys-color-on-secondary-container: #d8e7cb; --md-sys-color-tertiary: #a0cfd0; --md-sys-color-on-tertiary: #003738; --md-sys-color-tertiary-container: #1e4e4f; --md-sys-color-on-tertiary-container: #bbebec; --md-sys-color-error: #ffb4ab; --md-sys-color-on-error: #690005; --md-sys-color-error-container: #93000a; --md-sys-color-on-error-container: #ffdad6; --md-sys-color-background: #11140f; --md-sys-color-on-background: #e1e4d9; --md-sys-color-surface: #11140f; --md-sys-color-surface-dim: #11140f; --md-sys-color-surface-bright: #373a33; --md-sys-color-surface-container-lowest: #0c0f0a; --md-sys-color-surface-container-low: #191d16; --md-sys-color-surface-container: #1d211a; --md-sys-color-surface-container-high: #282b24; --md-sys-color-surface-container-highest: #32362f; --md-sys-color-on-surface: #e1e4d9; --md-sys-color-surface-variant: #43483e; --md-sys-color-on-surface-variant: #c3c8bb; --md-sys-color-inverse-surface: #e1e4d9; --md-sys-color-inverse-on-surface: #2e312b; --md-sys-color-outline: #8d9286; --md-sys-color-outline-variant: #43483e; --md-sys-color-shadow: #000000; --md-sys-color-scrim: #000000; --md-sys-color-surface-tint: #a9d291; --md-sys-color-success: #9cd67e; --md-sys-color-on-success: #113800; --md-sys-color-success-container: #205107; --md-sys-color-on-success-container: #b8f397; --md-sys-color-warning: #e2c54a; --md-sys-color-on-warning: #3a3000; --md-sys-color-warning-container: #544600; --md-sys-color-on-warning-container: #ffe16a; }
|
||||||
|
@media (prefers-color-scheme: dark) { :root[data-palette="green"]:not([data-mode="light"]) { --md-sys-color-primary: #a9d291; --md-sys-color-on-primary: #173807; --md-sys-color-primary-container: #2d4f1c; --md-sys-color-on-primary-container: #c5efab; --md-sys-color-inverse-primary: #446732; --md-sys-color-secondary: #bdcbb0; --md-sys-color-on-secondary: #283420; --md-sys-color-secondary-container: #3e4a35; --md-sys-color-on-secondary-container: #d8e7cb; --md-sys-color-tertiary: #a0cfd0; --md-sys-color-on-tertiary: #003738; --md-sys-color-tertiary-container: #1e4e4f; --md-sys-color-on-tertiary-container: #bbebec; --md-sys-color-error: #ffb4ab; --md-sys-color-on-error: #690005; --md-sys-color-error-container: #93000a; --md-sys-color-on-error-container: #ffdad6; --md-sys-color-background: #11140f; --md-sys-color-on-background: #e1e4d9; --md-sys-color-surface: #11140f; --md-sys-color-surface-dim: #11140f; --md-sys-color-surface-bright: #373a33; --md-sys-color-surface-container-lowest: #0c0f0a; --md-sys-color-surface-container-low: #191d16; --md-sys-color-surface-container: #1d211a; --md-sys-color-surface-container-high: #282b24; --md-sys-color-surface-container-highest: #32362f; --md-sys-color-on-surface: #e1e4d9; --md-sys-color-surface-variant: #43483e; --md-sys-color-on-surface-variant: #c3c8bb; --md-sys-color-inverse-surface: #e1e4d9; --md-sys-color-inverse-on-surface: #2e312b; --md-sys-color-outline: #8d9286; --md-sys-color-outline-variant: #43483e; --md-sys-color-shadow: #000000; --md-sys-color-scrim: #000000; --md-sys-color-surface-tint: #a9d291; --md-sys-color-success: #9cd67e; --md-sys-color-on-success: #113800; --md-sys-color-success-container: #205107; --md-sys-color-on-success-container: #b8f397; --md-sys-color-warning: #e2c54a; --md-sys-color-on-warning: #3a3000; --md-sys-color-warning-container: #544600; --md-sys-color-on-warning-container: #ffe16a; } }
|
||||||
|
|
||||||
|
/* orange (seed #8B5000) */
|
||||||
|
:root[data-palette="orange"] { --md-sys-color-primary: #865319; --md-sys-color-on-primary: #ffffff; --md-sys-color-primary-container: #ffdcbe; --md-sys-color-on-primary-container: #6a3c01; --md-sys-color-inverse-primary: #fdb975; --md-sys-color-secondary: #735a42; --md-sys-color-on-secondary: #ffffff; --md-sys-color-secondary-container: #ffdcbe; --md-sys-color-on-secondary-container: #59422d; --md-sys-color-tertiary: #586339; --md-sys-color-on-tertiary: #ffffff; --md-sys-color-tertiary-container: #dce8b4; --md-sys-color-on-tertiary-container: #414b24; --md-sys-color-error: #ba1a1a; --md-sys-color-on-error: #ffffff; --md-sys-color-error-container: #ffdad6; --md-sys-color-on-error-container: #93000a; --md-sys-color-background: #fff8f5; --md-sys-color-on-background: #211a14; --md-sys-color-surface: #fff8f5; --md-sys-color-surface-dim: #e6d7cd; --md-sys-color-surface-bright: #fff8f5; --md-sys-color-surface-container-lowest: #ffffff; --md-sys-color-surface-container-low: #fff1e7; --md-sys-color-surface-container: #faebe0; --md-sys-color-surface-container-high: #f4e5db; --md-sys-color-surface-container-highest: #efe0d5; --md-sys-color-on-surface: #211a14; --md-sys-color-surface-variant: #f2dfd1; --md-sys-color-on-surface-variant: #51453a; --md-sys-color-inverse-surface: #372f28; --md-sys-color-inverse-on-surface: #fdeee3; --md-sys-color-outline: #837468; --md-sys-color-outline-variant: #d5c3b5; --md-sys-color-shadow: #000000; --md-sys-color-scrim: #000000; --md-sys-color-surface-tint: #865319; --md-sys-color-success: #516600; --md-sys-color-on-success: #ffffff; --md-sys-color-success-container: #d3ee80; --md-sys-color-on-success-container: #161e00; --md-sys-color-warning: #835500; --md-sys-color-on-warning: #ffffff; --md-sys-color-warning-container: #ffddb4; --md-sys-color-on-warning-container: #291800; }
|
||||||
|
:root[data-palette="orange"][data-mode="dark"] { --md-sys-color-primary: #fdb975; --md-sys-color-on-primary: #4a2800; --md-sys-color-primary-container: #6a3c01; --md-sys-color-on-primary-container: #ffdcbe; --md-sys-color-inverse-primary: #865319; --md-sys-color-secondary: #e1c1a4; --md-sys-color-on-secondary: #402c18; --md-sys-color-secondary-container: #59422d; --md-sys-color-on-secondary-container: #ffdcbe; --md-sys-color-tertiary: #c0cc9a; --md-sys-color-on-tertiary: #2b3410; --md-sys-color-tertiary-container: #414b24; --md-sys-color-on-tertiary-container: #dce8b4; --md-sys-color-error: #ffb4ab; --md-sys-color-on-error: #690005; --md-sys-color-error-container: #93000a; --md-sys-color-on-error-container: #ffdad6; --md-sys-color-background: #19120c; --md-sys-color-on-background: #efe0d5; --md-sys-color-surface: #19120c; --md-sys-color-surface-dim: #19120c; --md-sys-color-surface-bright: #403830; --md-sys-color-surface-container-lowest: #130d07; --md-sys-color-surface-container-low: #211a14; --md-sys-color-surface-container: #261e18; --md-sys-color-surface-container-high: #302822; --md-sys-color-surface-container-highest: #3c332c; --md-sys-color-on-surface: #efe0d5; --md-sys-color-surface-variant: #51453a; --md-sys-color-on-surface-variant: #d5c3b5; --md-sys-color-inverse-surface: #efe0d5; --md-sys-color-inverse-on-surface: #372f28; --md-sys-color-outline: #9e8e81; --md-sys-color-outline-variant: #51453a; --md-sys-color-shadow: #000000; --md-sys-color-scrim: #000000; --md-sys-color-surface-tint: #fdb975; --md-sys-color-success: #b7d167; --md-sys-color-on-success: #293500; --md-sys-color-success-container: #3c4d00; --md-sys-color-on-success-container: #d3ee80; --md-sys-color-warning: #ffb955; --md-sys-color-on-warning: #452b00; --md-sys-color-warning-container: #633f00; --md-sys-color-on-warning-container: #ffddb4; }
|
||||||
|
@media (prefers-color-scheme: dark) { :root[data-palette="orange"]:not([data-mode="light"]) { --md-sys-color-primary: #fdb975; --md-sys-color-on-primary: #4a2800; --md-sys-color-primary-container: #6a3c01; --md-sys-color-on-primary-container: #ffdcbe; --md-sys-color-inverse-primary: #865319; --md-sys-color-secondary: #e1c1a4; --md-sys-color-on-secondary: #402c18; --md-sys-color-secondary-container: #59422d; --md-sys-color-on-secondary-container: #ffdcbe; --md-sys-color-tertiary: #c0cc9a; --md-sys-color-on-tertiary: #2b3410; --md-sys-color-tertiary-container: #414b24; --md-sys-color-on-tertiary-container: #dce8b4; --md-sys-color-error: #ffb4ab; --md-sys-color-on-error: #690005; --md-sys-color-error-container: #93000a; --md-sys-color-on-error-container: #ffdad6; --md-sys-color-background: #19120c; --md-sys-color-on-background: #efe0d5; --md-sys-color-surface: #19120c; --md-sys-color-surface-dim: #19120c; --md-sys-color-surface-bright: #403830; --md-sys-color-surface-container-lowest: #130d07; --md-sys-color-surface-container-low: #211a14; --md-sys-color-surface-container: #261e18; --md-sys-color-surface-container-high: #302822; --md-sys-color-surface-container-highest: #3c332c; --md-sys-color-on-surface: #efe0d5; --md-sys-color-surface-variant: #51453a; --md-sys-color-on-surface-variant: #d5c3b5; --md-sys-color-inverse-surface: #efe0d5; --md-sys-color-inverse-on-surface: #372f28; --md-sys-color-outline: #9e8e81; --md-sys-color-outline-variant: #51453a; --md-sys-color-shadow: #000000; --md-sys-color-scrim: #000000; --md-sys-color-surface-tint: #fdb975; --md-sys-color-success: #b7d167; --md-sys-color-on-success: #293500; --md-sys-color-success-container: #3c4d00; --md-sys-color-on-success-container: #d3ee80; --md-sys-color-warning: #ffb955; --md-sys-color-on-warning: #452b00; --md-sys-color-warning-container: #633f00; --md-sys-color-on-warning-container: #ffddb4; } }
|
||||||
@@ -0,0 +1,159 @@
|
|||||||
|
/*
|
||||||
|
* Data tables (M3 has no table spec): surface rows, outline-variant dividers,
|
||||||
|
* title-small headers, hover state layer, secondary-container selection.
|
||||||
|
* Compact density: ~40px rows.
|
||||||
|
*/
|
||||||
|
|
||||||
|
table.list, .table-list {
|
||||||
|
font: var(--md-sys-typescale-body-medium);
|
||||||
|
letter-spacing: var(--md-sys-typescale-body-medium-tracking);
|
||||||
|
font-variant-numeric: tabular-nums;
|
||||||
|
border: 1px solid var(--md-sys-color-outline-variant);
|
||||||
|
border-radius: var(--md-sys-shape-corner-medium);
|
||||||
|
border-collapse: separate;
|
||||||
|
border-spacing: 0;
|
||||||
|
margin-block-end: 8px;
|
||||||
|
}
|
||||||
|
/* A table that scrolls sideways: the wrapper is the outlined card, so the card edge and
|
||||||
|
corners stay visible while the table scrolls inside it */
|
||||||
|
.autoscroll:has(> table.list) {
|
||||||
|
clear: both; /* scrolling makes it narrow beside a float instead of going below it */
|
||||||
|
padding: 0;
|
||||||
|
margin-block-end: 8px;
|
||||||
|
border: 1px solid var(--md-sys-color-outline-variant);
|
||||||
|
border-radius: var(--md-sys-shape-corner-medium);
|
||||||
|
}
|
||||||
|
.autoscroll > table.list { margin: 0; border: 0; border-radius: 0; }
|
||||||
|
table.list th, .table-list-header {
|
||||||
|
background-color: var(--md-sys-color-surface-container);
|
||||||
|
color: var(--md-sys-color-on-surface-variant);
|
||||||
|
font: var(--md-sys-typescale-title-small);
|
||||||
|
letter-spacing: var(--md-sys-typescale-title-small-tracking);
|
||||||
|
padding-block: 10px;
|
||||||
|
padding-inline: 8px;
|
||||||
|
border-block-end: 1px solid var(--md-sys-color-outline-variant);
|
||||||
|
}
|
||||||
|
table.list th a, table.list th a:link, table.list th a:visited { color: var(--md-sys-color-on-surface-variant); }
|
||||||
|
table.list td {
|
||||||
|
block-size: 40px;
|
||||||
|
padding-block: 4px;
|
||||||
|
padding-inline: 8px;
|
||||||
|
border-block-start: 1px solid var(--md-sys-color-outline-variant);
|
||||||
|
background-color: transparent;
|
||||||
|
}
|
||||||
|
table.list tbody tr:first-child td, table.list tbody tr.group + tr td { border-block-start: 0; }
|
||||||
|
|
||||||
|
/* No striping: M3 separates rows with dividers */
|
||||||
|
table.list:not(.odd-even) tbody tr:nth-child(odd), table.list:not(.odd-even) tbody tr:nth-child(even),
|
||||||
|
.odd, .even, .box table.list:not(.odd-even) tbody tr:nth-child(even), .box .even {
|
||||||
|
background-color: transparent;
|
||||||
|
}
|
||||||
|
table.list:not(.odd-even) tbody tr:nth-child(odd):hover, table.list:not(.odd-even) tbody tr:nth-child(even):hover,
|
||||||
|
.odd:hover, .even:hover {
|
||||||
|
background-color: color-mix(in srgb, var(--md-sys-color-on-surface) var(--md-sys-state-hover-state-layer-opacity), transparent);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Status names in the workflow header are td cells: same band as the th row above */
|
||||||
|
table.workflows thead td {
|
||||||
|
background-color: var(--md-sys-color-surface-container);
|
||||||
|
color: var(--md-sys-color-on-surface-variant);
|
||||||
|
font: var(--md-sys-typescale-title-small);
|
||||||
|
letter-spacing: var(--md-sys-typescale-title-small-tracking);
|
||||||
|
border-block-end: 1px solid var(--md-sys-color-outline-variant);
|
||||||
|
}
|
||||||
|
/* Role names in permission group rows sit on the group name's line */
|
||||||
|
table.permissions tr.group td { vertical-align: middle; }
|
||||||
|
/* Field permissions: the "»" copy link stays next to its select */
|
||||||
|
table.fields_permissions td { white-space: nowrap; }
|
||||||
|
/* An empty table: no divider under the header, the table border closes it */
|
||||||
|
table.list:not(:has(tbody tr)) th { border-block-end: 0; }
|
||||||
|
/* Child projects: chevron in the theme's colour, one file per mode */
|
||||||
|
tr.idnt :is(td.subject, td.name) { background-image: url(../images/chevron-right-idnt.svg); }
|
||||||
|
[dir="rtl"] tr.idnt :is(td.subject, td.name) { background-image: url(../images/chevron-left-idnt.svg); }
|
||||||
|
:root[data-mode="dark"] tr.idnt :is(td.subject, td.name) { background-image: url(../images/chevron-right-idnt-dark.svg); }
|
||||||
|
:root[data-mode="dark"][dir="rtl"] tr.idnt :is(td.subject, td.name) { background-image: url(../images/chevron-left-idnt-dark.svg); }
|
||||||
|
@media (prefers-color-scheme: dark) {
|
||||||
|
:root:not([data-mode="light"]) tr.idnt :is(td.subject, td.name) { background-image: url(../images/chevron-right-idnt-dark.svg); }
|
||||||
|
:root:not([data-mode="light"])[dir="rtl"] tr.idnt :is(td.subject, td.name) { background-image: url(../images/chevron-left-idnt-dark.svg); }
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Repository file, annotate and diff views: outlined like table.list, line numbers
|
||||||
|
separated by one divider instead of a grid (scm.css loads after the theme, hence html) */
|
||||||
|
html table.filecontent {
|
||||||
|
inline-size: 100%;
|
||||||
|
overflow: hidden;
|
||||||
|
border: 1px solid var(--md-sys-color-outline-variant);
|
||||||
|
border-collapse: separate;
|
||||||
|
border-spacing: 0;
|
||||||
|
border-radius: var(--md-sys-shape-corner-medium);
|
||||||
|
background-color: var(--md-sys-color-surface-container-lowest);
|
||||||
|
}
|
||||||
|
html table.filecontent th, html table.filecontent th.line-num {
|
||||||
|
border: 0;
|
||||||
|
border-inline-end: 1px solid var(--md-sys-color-outline-variant);
|
||||||
|
background-color: var(--md-sys-color-surface-container);
|
||||||
|
}
|
||||||
|
html table.filecontent th.filename {
|
||||||
|
padding-block: 10px;
|
||||||
|
padding-inline: 12px;
|
||||||
|
border-inline-end: 0;
|
||||||
|
border-block-end: 1px solid var(--md-sys-color-outline-variant);
|
||||||
|
color: var(--md-sys-color-on-surface-variant);
|
||||||
|
font: var(--md-sys-typescale-title-small);
|
||||||
|
}
|
||||||
|
/* CSV import preview */
|
||||||
|
.sample-data {
|
||||||
|
margin: 0;
|
||||||
|
overflow: hidden;
|
||||||
|
border: 1px solid var(--md-sys-color-outline-variant);
|
||||||
|
border-collapse: separate;
|
||||||
|
border-spacing: 0;
|
||||||
|
border-radius: var(--md-sys-shape-corner-medium);
|
||||||
|
background-color: transparent;
|
||||||
|
}
|
||||||
|
.sample-data td { padding-block: 8px; padding-inline: 12px; border: 0; border-block-start: 1px solid var(--md-sys-color-outline-variant); }
|
||||||
|
.sample-data tr:first-child td { border-block-start: 0; background-color: var(--md-sys-color-surface-container); }
|
||||||
|
|
||||||
|
tr.group td {
|
||||||
|
padding-block: 12px 8px;
|
||||||
|
padding-inline: 8px;
|
||||||
|
border-block-end: 1px solid var(--md-sys-color-outline-variant);
|
||||||
|
background-color: var(--md-sys-color-surface-container-low);
|
||||||
|
color: var(--md-sys-color-on-surface);
|
||||||
|
}
|
||||||
|
tr.group span.name { font-weight: 500; }
|
||||||
|
tr.group span.totals, tr.group a.toggle-all { color: var(--md-sys-color-on-surface-variant); }
|
||||||
|
tr.group span.totals .value { color: var(--md-sys-color-on-surface); font-weight: 500; }
|
||||||
|
table.list tbody tr.group:hover { background-color: transparent; }
|
||||||
|
|
||||||
|
/* Selected rows (context menu); core uses !important */
|
||||||
|
html .context-menu-selection, html .context-menu-selection:hover {
|
||||||
|
background-color: var(--md-sys-color-secondary-container) !important;
|
||||||
|
color: var(--md-sys-color-on-secondary-container) !important;
|
||||||
|
}
|
||||||
|
html .context-menu-selection a, html .context-menu-selection a:hover { color: var(--md-sys-color-on-secondary-container) !important; }
|
||||||
|
html .context-menu-selection svg.icon-svg { stroke: var(--md-sys-color-on-secondary-container) !important; }
|
||||||
|
|
||||||
|
table.list tr.overdue:not(.context-menu-selection) td.due_date { color: var(--md-sys-color-error); }
|
||||||
|
a.issue.closed, a.issue.closed:link, a.issue.closed:visited { color: var(--md-sys-color-on-surface-variant); }
|
||||||
|
|
||||||
|
.query-totals { color: var(--md-sys-color-on-surface-variant); }
|
||||||
|
.query-totals .value { color: var(--md-sys-color-on-surface); font-weight: 500; }
|
||||||
|
#query_form_content { font-size: inherit; }
|
||||||
|
#query_form_with_buttons > p.contextual { font: var(--md-sys-typescale-label-large); }
|
||||||
|
|
||||||
|
/* Query filters: checkbox + label sit level with the 40px operator/value fields. The field cell is
|
||||||
|
40px high and centers its content; the row stays top-aligned so an expanded multi-select grows
|
||||||
|
downwards without dragging the label to its middle. */
|
||||||
|
#filters-table .filter { align-items: flex-start; margin-block: 4px 0; }
|
||||||
|
#filters-table .filter .field { display: flex; align-items: center; gap: 8px; min-block-size: 40px; }
|
||||||
|
#filters-table .filter .field input[type="checkbox"] { margin: 0; }
|
||||||
|
#filters-table .filter .values { display: flex; align-items: center; min-block-size: 40px; flex-wrap: wrap; gap: 4px 8px; }
|
||||||
|
.add-filter { display: flex; align-items: center; justify-content: flex-end; gap: 8px; }
|
||||||
|
/* Core fixes the operator at 120px, too narrow for "has never been" with M3 field padding */
|
||||||
|
#filters-table .filter .operator select { inline-size: 180px; }
|
||||||
|
/* All value fields share one width so the filter rows form a clean second column.
|
||||||
|
"between" filters show two fields (both spans visible): each takes half. */
|
||||||
|
#filters-table .filter .values select.value,
|
||||||
|
#filters-table .filter .values input.value:not([size="3"]) { inline-size: 260px; }
|
||||||
|
#filters-table .filter .values:has(> span:first-child + span:not([style*="none"])) input.value { inline-size: 126px; padding-inline: 8px; }
|
||||||
@@ -0,0 +1,74 @@
|
|||||||
|
/*
|
||||||
|
* Material Design 3 system tokens (type, shape, state, motion, elevation).
|
||||||
|
* Color roles live in palettes.css, generated by tools/palettes/build_palettes.mjs.
|
||||||
|
*/
|
||||||
|
|
||||||
|
:root {
|
||||||
|
/* Typeface */
|
||||||
|
--md-ref-typeface-plain: Roboto, system-ui, sans-serif;
|
||||||
|
|
||||||
|
/* Type scale, as `font` shorthand values: weight size/line-height family */
|
||||||
|
--md-sys-typescale-display-large: 400 3.5625rem/4rem var(--md-ref-typeface-plain);
|
||||||
|
--md-sys-typescale-display-medium: 400 2.8125rem/3.25rem var(--md-ref-typeface-plain);
|
||||||
|
--md-sys-typescale-display-small: 400 2.25rem/2.75rem var(--md-ref-typeface-plain);
|
||||||
|
--md-sys-typescale-headline-large: 400 2rem/2.5rem var(--md-ref-typeface-plain);
|
||||||
|
--md-sys-typescale-headline-medium: 400 1.75rem/2.25rem var(--md-ref-typeface-plain);
|
||||||
|
--md-sys-typescale-headline-small: 400 1.5rem/2rem var(--md-ref-typeface-plain);
|
||||||
|
--md-sys-typescale-title-large: 400 1.375rem/1.75rem var(--md-ref-typeface-plain);
|
||||||
|
--md-sys-typescale-title-medium: 500 1rem/1.5rem var(--md-ref-typeface-plain);
|
||||||
|
--md-sys-typescale-title-small: 500 0.875rem/1.25rem var(--md-ref-typeface-plain);
|
||||||
|
--md-sys-typescale-body-large: 400 1rem/1.5rem var(--md-ref-typeface-plain);
|
||||||
|
--md-sys-typescale-body-medium: 400 0.875rem/1.25rem var(--md-ref-typeface-plain);
|
||||||
|
--md-sys-typescale-body-small: 400 0.75rem/1rem var(--md-ref-typeface-plain);
|
||||||
|
--md-sys-typescale-label-large: 500 0.875rem/1.25rem var(--md-ref-typeface-plain);
|
||||||
|
--md-sys-typescale-label-medium: 500 0.75rem/1rem var(--md-ref-typeface-plain);
|
||||||
|
--md-sys-typescale-label-small: 500 0.6875rem/1rem var(--md-ref-typeface-plain);
|
||||||
|
|
||||||
|
/* Tracking (letter-spacing) per type role */
|
||||||
|
--md-sys-typescale-display-large-tracking: -0.25px;
|
||||||
|
--md-sys-typescale-title-medium-tracking: 0.15px;
|
||||||
|
--md-sys-typescale-title-small-tracking: 0.1px;
|
||||||
|
--md-sys-typescale-body-large-tracking: 0.5px;
|
||||||
|
--md-sys-typescale-body-medium-tracking: 0.25px;
|
||||||
|
--md-sys-typescale-body-small-tracking: 0.4px;
|
||||||
|
--md-sys-typescale-label-large-tracking: 0.1px;
|
||||||
|
--md-sys-typescale-label-medium-tracking: 0.5px;
|
||||||
|
--md-sys-typescale-label-small-tracking: 0.5px;
|
||||||
|
|
||||||
|
/* Shape */
|
||||||
|
--md-sys-shape-corner-none: 0;
|
||||||
|
--md-sys-shape-corner-extra-small: 4px;
|
||||||
|
--md-sys-shape-corner-small: 8px;
|
||||||
|
--md-sys-shape-corner-medium: 12px;
|
||||||
|
--md-sys-shape-corner-large: 16px;
|
||||||
|
--md-sys-shape-corner-extra-large: 28px;
|
||||||
|
--md-sys-shape-corner-full: 9999px;
|
||||||
|
|
||||||
|
/* State layer opacities */
|
||||||
|
--md-sys-state-hover-state-layer-opacity: 8%;
|
||||||
|
--md-sys-state-focus-state-layer-opacity: 10%;
|
||||||
|
--md-sys-state-pressed-state-layer-opacity: 10%;
|
||||||
|
--md-sys-state-dragged-state-layer-opacity: 16%;
|
||||||
|
--md-sys-state-disabled-content-opacity: 38%;
|
||||||
|
--md-sys-state-disabled-container-opacity: 12%;
|
||||||
|
|
||||||
|
/* Motion */
|
||||||
|
--md-sys-motion-duration-short2: 100ms;
|
||||||
|
--md-sys-motion-duration-short4: 200ms;
|
||||||
|
--md-sys-motion-duration-medium2: 300ms;
|
||||||
|
--md-sys-motion-duration-medium4: 400ms;
|
||||||
|
--md-sys-motion-duration-long2: 500ms;
|
||||||
|
--md-sys-motion-easing-standard: cubic-bezier(0.2, 0, 0, 1);
|
||||||
|
--md-sys-motion-easing-standard-decelerate: cubic-bezier(0, 0, 0, 1);
|
||||||
|
--md-sys-motion-easing-standard-accelerate: cubic-bezier(0.3, 0, 1, 1);
|
||||||
|
--md-sys-motion-easing-emphasized-decelerate: cubic-bezier(0.05, 0.7, 0.1, 1);
|
||||||
|
--md-sys-motion-easing-emphasized-accelerate: cubic-bezier(0.3, 0, 0.8, 0.15);
|
||||||
|
|
||||||
|
/* Elevation (shadow part; M3 prefers surface-container roles for depth) */
|
||||||
|
--md-sys-elevation-level0: none;
|
||||||
|
--md-sys-elevation-level1: 0 1px 2px rgb(0 0 0 / 30%), 0 1px 3px 1px rgb(0 0 0 / 15%);
|
||||||
|
--md-sys-elevation-level2: 0 1px 2px rgb(0 0 0 / 30%), 0 2px 6px 2px rgb(0 0 0 / 15%);
|
||||||
|
--md-sys-elevation-level3: 0 1px 3px rgb(0 0 0 / 30%), 0 4px 8px 3px rgb(0 0 0 / 15%);
|
||||||
|
--md-sys-elevation-level4: 0 2px 3px rgb(0 0 0 / 30%), 0 6px 10px 4px rgb(0 0 0 / 15%);
|
||||||
|
--md-sys-elevation-level5: 0 4px 4px rgb(0 0 0 / 30%), 0 8px 12px 6px rgb(0 0 0 / 15%);
|
||||||
|
}
|
||||||
@@ -0,0 +1,40 @@
|
|||||||
|
/*
|
||||||
|
* One type scale for the whole app. Core Redmine sets ~60 relative sizes (0.8125rem, 0.9em, 93%, …)
|
||||||
|
* that compound when nested, e.g. the sidebar at 13px and its "Add" link at 11.7px.
|
||||||
|
* Here they are mapped onto the M3 scale: 14px (body-medium) for anything readable,
|
||||||
|
* 12px (body-small) for secondary meta text, headings on the heading scale.
|
||||||
|
* e2e/check-font-sizes.mjs reports anything that falls off the scale again.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* 14px: content, lists, actions, sidebars, forms */
|
||||||
|
#sidebar, .contextual, .contextual input, .contextual select, .buttons, #query_form_content,
|
||||||
|
#query_form_with_buttons > p.contextual, .query-totals, span.search_for_watchers, span.add_attachment,
|
||||||
|
table.issues td.block_column, tr.message td.last_message, table.boards td.last-message,
|
||||||
|
.tabular.settings p, #errorExplanation ul, .conflict-details, div.wiki ul.toc a,
|
||||||
|
#document-list .document-item .wiki.description, table.permissions td.role, #workflow_form table select,
|
||||||
|
tr.group span.totals, tr.group a.toggle-all, ul.properties, #sidebar h3 + .contextual, #search-results dd {
|
||||||
|
font-size: 0.875rem;
|
||||||
|
}
|
||||||
|
/* Parts of a number (hours "8:00") keep the number's size */
|
||||||
|
.hours-dec, table.time-entries td.hours .hours-dec, table#time-report .hours-dec, .total-hours span.hours-int {
|
||||||
|
font-size: inherit;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 12px: secondary meta text (who/when, stats, breadcrumbs, footers of blocks) */
|
||||||
|
p.breadcrumb, p.subtitle, p.footnote, div.issue p.author, div.issue div.subject p,
|
||||||
|
#issue_tree .issues-stat, #relations .issues-stat, .wiki-update-info, p.other-formats, em.info,
|
||||||
|
div.attachments span.author, table.files tr.file td.digest, tr.entry td.size,
|
||||||
|
table.plugins span.description, table.plugins span.url, #document-list .document-item .updated_on,
|
||||||
|
.cal .calbody, div.tooltip:hover span.tip, div.issue.details .reaction, div.message .reaction, div.news .reaction {
|
||||||
|
font-size: 0.75rem;
|
||||||
|
}
|
||||||
|
div.issue span.private, div.journal span.private { font-size: 0.6875rem; }
|
||||||
|
|
||||||
|
/* Headings */
|
||||||
|
.wiki h1, #content .wiki h1 { font: var(--md-sys-typescale-headline-small); }
|
||||||
|
.wiki h2, #content .wiki h2 { font: var(--md-sys-typescale-title-large); }
|
||||||
|
.wiki h3, #content .wiki h3, div#roadmap .wiki h1, div#roadmap .wiki h2 { font: var(--md-sys-typescale-title-medium); letter-spacing: var(--md-sys-typescale-title-medium-tracking); }
|
||||||
|
.wiki h4, #content .wiki h4 { font: var(--md-sys-typescale-title-small); letter-spacing: var(--md-sys-typescale-title-small-tracking); }
|
||||||
|
#document-list .document-item h4.title { font: var(--md-sys-typescale-title-medium); }
|
||||||
|
.total-hours { font: var(--md-sys-typescale-title-medium); }
|
||||||
|
.cal .calbody p.day-num { font: var(--md-sys-typescale-label-large); }
|
||||||
@@ -0,0 +1,64 @@
|
|||||||
|
# Builds tonalmine/images/icons.svg from tools/icon_map.yml.
|
||||||
|
# Usage (from repo root): ruby tools/build_icons.rb
|
||||||
|
# Ruby stdlib only. Downloads are cached in tools/.cache/.
|
||||||
|
require 'yaml'
|
||||||
|
require 'net/http'
|
||||||
|
require 'uri'
|
||||||
|
require 'fileutils'
|
||||||
|
|
||||||
|
CORE_ICONS = 'https://raw.githubusercontent.com/redmine/redmine/7.0-stable/config/icon_source.yml'
|
||||||
|
SYMBOLS = 'https://raw.githubusercontent.com/google/material-design-icons/master/symbols/web'
|
||||||
|
ROOT = File.expand_path('..', __dir__)
|
||||||
|
CACHE = File.join(ROOT, 'tools/.cache')
|
||||||
|
OUT = File.join(ROOT, 'tonalmine/images/icons.svg')
|
||||||
|
|
||||||
|
def fetch(url)
|
||||||
|
res = Net::HTTP.get_response(URI(url))
|
||||||
|
res.is_a?(Net::HTTPSuccess) ? res.body : nil
|
||||||
|
end
|
||||||
|
|
||||||
|
def fail_with(message, items)
|
||||||
|
warn "#{message}:\n #{items.join("\n ")}"
|
||||||
|
exit 1
|
||||||
|
end
|
||||||
|
|
||||||
|
# 1. Map must cover exactly the core icon names.
|
||||||
|
core_yml = fetch(CORE_ICONS) or fail_with('Could not fetch', [CORE_ICONS])
|
||||||
|
core = YAML.safe_load(core_yml).map { |e| e['name'] }.uniq
|
||||||
|
map = YAML.load_file(File.join(ROOT, 'tools/icon_map.yml'))
|
||||||
|
names = map.map { |e| e['name'] }
|
||||||
|
dupes = names.select { |n| names.count(n) > 1 }.uniq
|
||||||
|
fail_with('Duplicate names in icon_map.yml', dupes) if dupes.any?
|
||||||
|
missing = core - names
|
||||||
|
extra = names - core
|
||||||
|
fail_with('Missing from icon_map.yml', missing) if missing.any?
|
||||||
|
fail_with('Not in Redmine icon_source.yml (extra)', extra) if extra.any?
|
||||||
|
|
||||||
|
# 2. Download (or read cached) SVGs.
|
||||||
|
FileUtils.mkdir_p(CACHE)
|
||||||
|
not_found = []
|
||||||
|
symbols = map.sort_by { |e| e['name'] }.map do |e|
|
||||||
|
file = "#{e['symbol']}#{e['fill'] ? '_fill1' : ''}_24px.svg"
|
||||||
|
cached = File.join(CACHE, file)
|
||||||
|
unless File.exist?(cached)
|
||||||
|
svg = fetch("#{SYMBOLS}/#{e['symbol']}/materialsymbolsoutlined/#{file}")
|
||||||
|
next not_found << "#{e['name']} -> #{file}" unless svg
|
||||||
|
File.write(cached, svg)
|
||||||
|
end
|
||||||
|
paths = File.read(cached).scan(/<path\b[^>]*\bd="([^"]+)"/).flatten
|
||||||
|
fail_with('No <path> found in', [cached]) if paths.empty?
|
||||||
|
body = paths.map { |d| %(<path d="#{d}" fill="currentColor" stroke="none"/>) }.join
|
||||||
|
%(<symbol id="icon--#{e['name']}" viewBox="0 -960 960 960">#{body}</symbol>)
|
||||||
|
end
|
||||||
|
fail_with('Material Symbol not found', not_found) if not_found.any?
|
||||||
|
|
||||||
|
# 3. Write the sprite.
|
||||||
|
File.write(OUT, <<~SVG)
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<!-- Generated by tools/build_icons.rb from tools/icon_map.yml. Do not edit by hand.
|
||||||
|
Icons: Material Symbols Outlined by Google (github.com/google/material-design-icons),
|
||||||
|
Apache License 2.0, see LICENSE-material-symbols.txt. -->
|
||||||
|
#{symbols.join("\n")}
|
||||||
|
</svg>
|
||||||
|
SVG
|
||||||
|
puts "Wrote #{symbols.size} icons to #{OUT.sub("#{ROOT}/", '')}"
|
||||||
@@ -0,0 +1,242 @@
|
|||||||
|
# Redmine 7.0 icon name -> Material Symbols (Outlined, weight 400) name.
|
||||||
|
# Order follows Redmine's config/icon_source.yml. `fill: true` uses the filled variant.
|
||||||
|
# Rebuild the sprite with: ruby tools/build_icons.rb
|
||||||
|
- name: edit
|
||||||
|
symbol: edit
|
||||||
|
- name: add
|
||||||
|
symbol: add_circle
|
||||||
|
- name: copy
|
||||||
|
symbol: content_copy
|
||||||
|
- name: del
|
||||||
|
symbol: delete
|
||||||
|
- name: save
|
||||||
|
symbol: save
|
||||||
|
- name: download
|
||||||
|
symbol: download
|
||||||
|
- name: attachment
|
||||||
|
symbol: attach_file
|
||||||
|
- name: time-add
|
||||||
|
symbol: more_time
|
||||||
|
- name: time
|
||||||
|
symbol: schedule
|
||||||
|
- name: fav
|
||||||
|
symbol: star
|
||||||
|
- name: copy-link
|
||||||
|
symbol: link # note: core uses a clipboard; "link" reads better for "Copy link"
|
||||||
|
- name: 3-bullets
|
||||||
|
symbol: more_horiz
|
||||||
|
- name: history
|
||||||
|
symbol: history
|
||||||
|
- name: folder
|
||||||
|
symbol: folder
|
||||||
|
- name: folder-open
|
||||||
|
symbol: folder_open
|
||||||
|
- name: lock
|
||||||
|
symbol: lock
|
||||||
|
- name: unlock
|
||||||
|
symbol: lock_open
|
||||||
|
- name: link-break
|
||||||
|
symbol: link_off
|
||||||
|
- name: zoom-in
|
||||||
|
symbol: zoom_in
|
||||||
|
- name: zoom-out
|
||||||
|
symbol: zoom_out
|
||||||
|
- name: settings
|
||||||
|
symbol: settings
|
||||||
|
- name: news
|
||||||
|
symbol: newspaper
|
||||||
|
- name: user
|
||||||
|
symbol: person
|
||||||
|
- name: group
|
||||||
|
symbol: group
|
||||||
|
- name: bookmarked
|
||||||
|
symbol: bookmark
|
||||||
|
- name: bookmark-delete
|
||||||
|
symbol: bookmark_remove
|
||||||
|
- name: bookmark-add
|
||||||
|
symbol: bookmark_add
|
||||||
|
- name: import
|
||||||
|
symbol: database_upload
|
||||||
|
- name: summary
|
||||||
|
symbol: bolt # note: mirrors core's Tabler "bolt"
|
||||||
|
- name: angle-down
|
||||||
|
symbol: expand_more
|
||||||
|
- name: angle-right
|
||||||
|
symbol: chevron_right
|
||||||
|
- name: angle-up
|
||||||
|
symbol: expand_less
|
||||||
|
- name: angle-left
|
||||||
|
symbol: chevron_left
|
||||||
|
- name: email
|
||||||
|
symbol: mail
|
||||||
|
- name: email-disabled
|
||||||
|
symbol: mail_off
|
||||||
|
- name: stats
|
||||||
|
symbol: bar_chart
|
||||||
|
- name: reorder
|
||||||
|
symbol: reorder # note: Tabler "menu-order" has up/down arrows; Material is plain lines
|
||||||
|
- name: close
|
||||||
|
symbol: close # note: plain X, no square frame
|
||||||
|
- name: checked
|
||||||
|
symbol: check
|
||||||
|
- name: reload
|
||||||
|
symbol: refresh
|
||||||
|
- name: link
|
||||||
|
symbol: link
|
||||||
|
- name: plugins
|
||||||
|
symbol: extension
|
||||||
|
- name: roles
|
||||||
|
symbol: admin_panel_settings # note: Tabler "shield-cog"
|
||||||
|
- name: list
|
||||||
|
symbol: list
|
||||||
|
- name: workflows
|
||||||
|
symbol: account_tree # note: Tabler "jump-rope" has no Material equivalent
|
||||||
|
- name: server-authentication
|
||||||
|
symbol: dns
|
||||||
|
- name: table-multiple
|
||||||
|
symbol: refresh # note: mirrors core, which also draws "refresh" here
|
||||||
|
- name: projects
|
||||||
|
symbol: inventory_2 # note: Tabler "packages"
|
||||||
|
- name: project
|
||||||
|
symbol: inventory_2 # note: Tabler "packages"
|
||||||
|
- name: package
|
||||||
|
symbol: package_2
|
||||||
|
- name: custom-fields
|
||||||
|
symbol: dynamic_form # note: Tabler "input-check"
|
||||||
|
- name: help
|
||||||
|
symbol: info
|
||||||
|
- name: changeset
|
||||||
|
symbol: code
|
||||||
|
- name: clear-query
|
||||||
|
symbol: filter_alt_off # note: by meaning; core uses a square X
|
||||||
|
- name: warning
|
||||||
|
symbol: warning
|
||||||
|
- name: comments
|
||||||
|
symbol: forum
|
||||||
|
- name: comment
|
||||||
|
symbol: comment
|
||||||
|
- name: message
|
||||||
|
symbol: chat_bubble
|
||||||
|
- name: reply
|
||||||
|
symbol: reply # note: by meaning; core uses Tabler "messages"
|
||||||
|
- name: arrow-right
|
||||||
|
symbol: arrow_forward
|
||||||
|
- name: wiki-page
|
||||||
|
symbol: article # note: Tabler "notebook"
|
||||||
|
- name: bullet-end
|
||||||
|
symbol: arrow_circle_left
|
||||||
|
- name: bullet-go
|
||||||
|
symbol: arrow_circle_right
|
||||||
|
- name: bullet-go-end
|
||||||
|
symbol: diamond # note: Tabler "diamonds"
|
||||||
|
- name: move
|
||||||
|
symbol: move_item # note: Tabler "arrow-forward-up"
|
||||||
|
- name: cancel
|
||||||
|
symbol: undo
|
||||||
|
- name: document
|
||||||
|
symbol: description
|
||||||
|
- name: issue
|
||||||
|
symbol: sticky_note_2 # note: Tabler "note"
|
||||||
|
- name: issue-closed
|
||||||
|
symbol: check_box
|
||||||
|
- name: issue-edit
|
||||||
|
symbol: edit_square
|
||||||
|
- name: issue-note
|
||||||
|
symbol: add_comment
|
||||||
|
- name: file
|
||||||
|
symbol: draft
|
||||||
|
- name: text-plain
|
||||||
|
symbol: description
|
||||||
|
- name: text-x-c
|
||||||
|
symbol: code_blocks # note: generic code file
|
||||||
|
- name: text-x-csharp
|
||||||
|
symbol: code_blocks # note: generic code file
|
||||||
|
- name: text-x-java
|
||||||
|
symbol: code_blocks # note: generic code file
|
||||||
|
- name: text-x-php
|
||||||
|
symbol: php
|
||||||
|
- name: text-x-ruby
|
||||||
|
symbol: code_blocks # note: generic code file
|
||||||
|
- name: text-xml
|
||||||
|
symbol: code # note: generic markup
|
||||||
|
- name: text-css
|
||||||
|
symbol: css
|
||||||
|
- name: text-html
|
||||||
|
symbol: html
|
||||||
|
- name: application-javascript
|
||||||
|
symbol: javascript
|
||||||
|
- name: application-pdf
|
||||||
|
symbol: picture_as_pdf
|
||||||
|
- name: application-zip
|
||||||
|
symbol: folder_zip
|
||||||
|
- name: application-gzip
|
||||||
|
symbol: folder_zip
|
||||||
|
- name: chevrons-right
|
||||||
|
symbol: keyboard_double_arrow_right
|
||||||
|
- name: chevrons-left
|
||||||
|
symbol: keyboard_double_arrow_left
|
||||||
|
- name: key
|
||||||
|
symbol: key
|
||||||
|
- name: search
|
||||||
|
symbol: search
|
||||||
|
- name: toggle-plus
|
||||||
|
symbol: add_box
|
||||||
|
- name: toggle-minus
|
||||||
|
symbol: indeterminate_check_box
|
||||||
|
- name: circle-minus
|
||||||
|
symbol: do_not_disturb_on
|
||||||
|
- name: circle-dot-filled
|
||||||
|
symbol: radio_button_checked
|
||||||
|
fill: true
|
||||||
|
- name: watch
|
||||||
|
symbol: visibility
|
||||||
|
- name: unwatch
|
||||||
|
symbol: visibility_off
|
||||||
|
- name: copy-pre-content
|
||||||
|
symbol: content_paste
|
||||||
|
- name: thumb-up
|
||||||
|
symbol: thumb_up
|
||||||
|
- name: thumb-up-filled
|
||||||
|
symbol: thumb_up
|
||||||
|
fill: true
|
||||||
|
- name: alert-circle
|
||||||
|
symbol: error
|
||||||
|
- name: bulb
|
||||||
|
symbol: lightbulb
|
||||||
|
- name: message-report
|
||||||
|
symbol: feedback
|
||||||
|
- name: quote-filled
|
||||||
|
symbol: format_quote
|
||||||
|
fill: true
|
||||||
|
- name: loader
|
||||||
|
symbol: progress_activity
|
||||||
|
- name: hourglass
|
||||||
|
symbol: hourglass
|
||||||
|
- name: webhook
|
||||||
|
symbol: webhook
|
||||||
|
- name: apps
|
||||||
|
symbol: apps
|
||||||
|
- name: shield-check
|
||||||
|
symbol: verified_user
|
||||||
|
- name: arrow-narrow-left
|
||||||
|
symbol: arrow_left_alt
|
||||||
|
- name: arrow-narrow-right
|
||||||
|
symbol: arrow_right_alt
|
||||||
|
- name: photo
|
||||||
|
symbol: image
|
||||||
|
- name: movie
|
||||||
|
symbol: movie
|
||||||
|
- name: file-music
|
||||||
|
symbol: audio_file
|
||||||
|
- name: file-type-docx
|
||||||
|
symbol: docs # note: generic document with lines
|
||||||
|
- name: file-type-xls
|
||||||
|
symbol: table # note: generic spreadsheet
|
||||||
|
- name: file-type-ppt
|
||||||
|
symbol: slideshow # note: generic presentation
|
||||||
|
- name: maximize
|
||||||
|
symbol: fullscreen
|
||||||
|
- name: link-add
|
||||||
|
symbol: add_link
|
||||||
|
- name: unknown
|
||||||
|
symbol: help
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
.build/
|
||||||
@@ -0,0 +1,73 @@
|
|||||||
|
// Generates tonalmine/stylesheets/palettes.css: one M3 color scheme per seed color,
|
||||||
|
// in light and dark. Run: cd tools/palettes && npm install && npm run build
|
||||||
|
// (bundled with esbuild because material-color-utilities 0.4.0 has extensionless ESM imports).
|
||||||
|
import { writeFileSync, readFileSync } from 'node:fs';
|
||||||
|
import { resolve } from 'node:path';
|
||||||
|
import { Hct, SchemeTonalSpot, MaterialDynamicColors as C, hexFromArgb, argbFromHex, customColor } from '@material/material-color-utilities';
|
||||||
|
|
||||||
|
// The first palette is the default. Ids must match PALETTES in tonalmine/javascripts/theme.js.
|
||||||
|
const PALETTES = [
|
||||||
|
['purple', '#6750A4'],
|
||||||
|
['blue', '#0061A4'],
|
||||||
|
['teal', '#006A6A'],
|
||||||
|
['green', '#386A20'],
|
||||||
|
['orange', '#8B5000'],
|
||||||
|
];
|
||||||
|
const CUSTOM = [['success', '#386A20'], ['warning', '#7C5800']];
|
||||||
|
const ROLES = ['primary', 'onPrimary', 'primaryContainer', 'onPrimaryContainer', 'inversePrimary',
|
||||||
|
'secondary', 'onSecondary', 'secondaryContainer', 'onSecondaryContainer',
|
||||||
|
'tertiary', 'onTertiary', 'tertiaryContainer', 'onTertiaryContainer',
|
||||||
|
'error', 'onError', 'errorContainer', 'onErrorContainer',
|
||||||
|
'background', 'onBackground', 'surface', 'surfaceDim', 'surfaceBright',
|
||||||
|
'surfaceContainerLowest', 'surfaceContainerLow', 'surfaceContainer', 'surfaceContainerHigh', 'surfaceContainerHighest',
|
||||||
|
'onSurface', 'surfaceVariant', 'onSurfaceVariant', 'inverseSurface', 'inverseOnSurface',
|
||||||
|
'outline', 'outlineVariant', 'shadow', 'scrim', 'surfaceTint'];
|
||||||
|
|
||||||
|
const kebab = (s) => s.replace(/[A-Z]/g, (m) => '-' + m.toLowerCase());
|
||||||
|
const hex = (argb) => hexFromArgb(argb);
|
||||||
|
|
||||||
|
function roles(seedHex, dark) {
|
||||||
|
const seed = argbFromHex(seedHex);
|
||||||
|
const scheme = new SchemeTonalSpot(Hct.fromInt(seed), dark, 0);
|
||||||
|
const lines = ROLES.map((r) => `--md-sys-color-${kebab(r)}: ${hex(C[r].getArgb(scheme))};`);
|
||||||
|
for (const [name, value] of CUSTOM) {
|
||||||
|
const c = customColor(seed, { name, value: argbFromHex(value), blend: true })[dark ? 'dark' : 'light'];
|
||||||
|
lines.push(`--md-sys-color-${name}: ${hex(c.color)};`, `--md-sys-color-on-${name}: ${hex(c.onColor)};`,
|
||||||
|
`--md-sys-color-${name}-container: ${hex(c.colorContainer)};`, `--md-sys-color-on-${name}-container: ${hex(c.onColorContainer)};`);
|
||||||
|
}
|
||||||
|
return lines.join(' ');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Specificity: the default palette uses bare :root, the others add [data-palette], and every dark
|
||||||
|
// rule adds one more attribute, so "palette + mode" always beats "palette" and the default.
|
||||||
|
let css = `/*
|
||||||
|
* Generated by tools/palettes/build_palettes.mjs; do not edit by hand.
|
||||||
|
* M3 color roles (TonalSpot, contrast 0) per palette, light and dark.
|
||||||
|
* <html data-palette="..."> picks the palette, <html data-mode="light|dark"> forces a mode;
|
||||||
|
* without data-mode the OS setting (prefers-color-scheme) decides.
|
||||||
|
*/
|
||||||
|
|
||||||
|
:root { color-scheme: light; }
|
||||||
|
:root[data-mode="dark"] { color-scheme: dark; }
|
||||||
|
@media (prefers-color-scheme: dark) { :root:not([data-mode="light"]) { color-scheme: dark; } }
|
||||||
|
`;
|
||||||
|
PALETTES.forEach(([id, seed], i) => {
|
||||||
|
const sel = i === 0 ? ':root' : `:root[data-palette="${id}"]`;
|
||||||
|
css += `
|
||||||
|
/* ${id} (seed ${seed}) */
|
||||||
|
${sel} { ${roles(seed, false)} }
|
||||||
|
${sel}[data-mode="dark"] { ${roles(seed, true)} }
|
||||||
|
@media (prefers-color-scheme: dark) { ${sel}:not([data-mode="light"]) { ${roles(seed, true)} } }
|
||||||
|
`;
|
||||||
|
});
|
||||||
|
|
||||||
|
// Paths are relative to tools/palettes (npm runs scripts there); the bundle itself lives in .build/.
|
||||||
|
const theme = resolve(process.cwd(), '../../tonalmine');
|
||||||
|
const out = `${theme}/stylesheets/palettes.css`;
|
||||||
|
writeFileSync(out, css);
|
||||||
|
|
||||||
|
// Keep theme.js in sync: every palette id must appear in its PALETTES list.
|
||||||
|
const js = readFileSync(`${theme}/javascripts/theme.js`, 'utf8');
|
||||||
|
const missing = PALETTES.map(([id]) => id).filter((id) => !js.includes(`'${id}'`));
|
||||||
|
if (missing.length) { console.error(`theme.js is missing palettes: ${missing.join(', ')}`); process.exit(1); }
|
||||||
|
console.log(`Wrote ${PALETTES.length} palettes to ${out}`);
|
||||||
@@ -0,0 +1,505 @@
|
|||||||
|
{
|
||||||
|
"name": "tonalmine-palettes",
|
||||||
|
"lockfileVersion": 3,
|
||||||
|
"requires": true,
|
||||||
|
"packages": {
|
||||||
|
"": {
|
||||||
|
"name": "tonalmine-palettes",
|
||||||
|
"devDependencies": {
|
||||||
|
"@material/material-color-utilities": "0.4.0",
|
||||||
|
"esbuild": "^0.25.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@esbuild/aix-ppc64": {
|
||||||
|
"version": "0.25.12",
|
||||||
|
"resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.12.tgz",
|
||||||
|
"integrity": "sha512-Hhmwd6CInZ3dwpuGTF8fJG6yoWmsToE+vYgD4nytZVxcu1ulHpUQRAB1UJ8+N1Am3Mz4+xOByoQoSZf4D+CpkA==",
|
||||||
|
"cpu": [
|
||||||
|
"ppc64"
|
||||||
|
],
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"aix"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": ">=18"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@esbuild/android-arm": {
|
||||||
|
"version": "0.25.12",
|
||||||
|
"resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.12.tgz",
|
||||||
|
"integrity": "sha512-VJ+sKvNA/GE7Ccacc9Cha7bpS8nyzVv0jdVgwNDaR4gDMC/2TTRc33Ip8qrNYUcpkOHUT5OZ0bUcNNVZQ9RLlg==",
|
||||||
|
"cpu": [
|
||||||
|
"arm"
|
||||||
|
],
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"android"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": ">=18"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@esbuild/android-arm64": {
|
||||||
|
"version": "0.25.12",
|
||||||
|
"resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.12.tgz",
|
||||||
|
"integrity": "sha512-6AAmLG7zwD1Z159jCKPvAxZd4y/VTO0VkprYy+3N2FtJ8+BQWFXU+OxARIwA46c5tdD9SsKGZ/1ocqBS/gAKHg==",
|
||||||
|
"cpu": [
|
||||||
|
"arm64"
|
||||||
|
],
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"android"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": ">=18"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@esbuild/android-x64": {
|
||||||
|
"version": "0.25.12",
|
||||||
|
"resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.12.tgz",
|
||||||
|
"integrity": "sha512-5jbb+2hhDHx5phYR2By8GTWEzn6I9UqR11Kwf22iKbNpYrsmRB18aX/9ivc5cabcUiAT/wM+YIZ6SG9QO6a8kg==",
|
||||||
|
"cpu": [
|
||||||
|
"x64"
|
||||||
|
],
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"android"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": ">=18"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@esbuild/darwin-arm64": {
|
||||||
|
"version": "0.25.12",
|
||||||
|
"resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.12.tgz",
|
||||||
|
"integrity": "sha512-N3zl+lxHCifgIlcMUP5016ESkeQjLj/959RxxNYIthIg+CQHInujFuXeWbWMgnTo4cp5XVHqFPmpyu9J65C1Yg==",
|
||||||
|
"cpu": [
|
||||||
|
"arm64"
|
||||||
|
],
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"darwin"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": ">=18"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@esbuild/darwin-x64": {
|
||||||
|
"version": "0.25.12",
|
||||||
|
"resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.12.tgz",
|
||||||
|
"integrity": "sha512-HQ9ka4Kx21qHXwtlTUVbKJOAnmG1ipXhdWTmNXiPzPfWKpXqASVcWdnf2bnL73wgjNrFXAa3yYvBSd9pzfEIpA==",
|
||||||
|
"cpu": [
|
||||||
|
"x64"
|
||||||
|
],
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"darwin"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": ">=18"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@esbuild/freebsd-arm64": {
|
||||||
|
"version": "0.25.12",
|
||||||
|
"resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.12.tgz",
|
||||||
|
"integrity": "sha512-gA0Bx759+7Jve03K1S0vkOu5Lg/85dou3EseOGUes8flVOGxbhDDh/iZaoek11Y8mtyKPGF3vP8XhnkDEAmzeg==",
|
||||||
|
"cpu": [
|
||||||
|
"arm64"
|
||||||
|
],
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"freebsd"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": ">=18"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@esbuild/freebsd-x64": {
|
||||||
|
"version": "0.25.12",
|
||||||
|
"resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.12.tgz",
|
||||||
|
"integrity": "sha512-TGbO26Yw2xsHzxtbVFGEXBFH0FRAP7gtcPE7P5yP7wGy7cXK2oO7RyOhL5NLiqTlBh47XhmIUXuGciXEqYFfBQ==",
|
||||||
|
"cpu": [
|
||||||
|
"x64"
|
||||||
|
],
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"freebsd"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": ">=18"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@esbuild/linux-arm": {
|
||||||
|
"version": "0.25.12",
|
||||||
|
"resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.12.tgz",
|
||||||
|
"integrity": "sha512-lPDGyC1JPDou8kGcywY0YILzWlhhnRjdof3UlcoqYmS9El818LLfJJc3PXXgZHrHCAKs/Z2SeZtDJr5MrkxtOw==",
|
||||||
|
"cpu": [
|
||||||
|
"arm"
|
||||||
|
],
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"linux"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": ">=18"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@esbuild/linux-arm64": {
|
||||||
|
"version": "0.25.12",
|
||||||
|
"resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.12.tgz",
|
||||||
|
"integrity": "sha512-8bwX7a8FghIgrupcxb4aUmYDLp8pX06rGh5HqDT7bB+8Rdells6mHvrFHHW2JAOPZUbnjUpKTLg6ECyzvas2AQ==",
|
||||||
|
"cpu": [
|
||||||
|
"arm64"
|
||||||
|
],
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"linux"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": ">=18"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@esbuild/linux-ia32": {
|
||||||
|
"version": "0.25.12",
|
||||||
|
"resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.12.tgz",
|
||||||
|
"integrity": "sha512-0y9KrdVnbMM2/vG8KfU0byhUN+EFCny9+8g202gYqSSVMonbsCfLjUO+rCci7pM0WBEtz+oK/PIwHkzxkyharA==",
|
||||||
|
"cpu": [
|
||||||
|
"ia32"
|
||||||
|
],
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"linux"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": ">=18"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@esbuild/linux-loong64": {
|
||||||
|
"version": "0.25.12",
|
||||||
|
"resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.12.tgz",
|
||||||
|
"integrity": "sha512-h///Lr5a9rib/v1GGqXVGzjL4TMvVTv+s1DPoxQdz7l/AYv6LDSxdIwzxkrPW438oUXiDtwM10o9PmwS/6Z0Ng==",
|
||||||
|
"cpu": [
|
||||||
|
"loong64"
|
||||||
|
],
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"linux"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": ">=18"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@esbuild/linux-mips64el": {
|
||||||
|
"version": "0.25.12",
|
||||||
|
"resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.12.tgz",
|
||||||
|
"integrity": "sha512-iyRrM1Pzy9GFMDLsXn1iHUm18nhKnNMWscjmp4+hpafcZjrr2WbT//d20xaGljXDBYHqRcl8HnxbX6uaA/eGVw==",
|
||||||
|
"cpu": [
|
||||||
|
"mips64el"
|
||||||
|
],
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"linux"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": ">=18"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@esbuild/linux-ppc64": {
|
||||||
|
"version": "0.25.12",
|
||||||
|
"resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.12.tgz",
|
||||||
|
"integrity": "sha512-9meM/lRXxMi5PSUqEXRCtVjEZBGwB7P/D4yT8UG/mwIdze2aV4Vo6U5gD3+RsoHXKkHCfSxZKzmDssVlRj1QQA==",
|
||||||
|
"cpu": [
|
||||||
|
"ppc64"
|
||||||
|
],
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"linux"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": ">=18"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@esbuild/linux-riscv64": {
|
||||||
|
"version": "0.25.12",
|
||||||
|
"resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.12.tgz",
|
||||||
|
"integrity": "sha512-Zr7KR4hgKUpWAwb1f3o5ygT04MzqVrGEGXGLnj15YQDJErYu/BGg+wmFlIDOdJp0PmB0lLvxFIOXZgFRrdjR0w==",
|
||||||
|
"cpu": [
|
||||||
|
"riscv64"
|
||||||
|
],
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"linux"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": ">=18"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@esbuild/linux-s390x": {
|
||||||
|
"version": "0.25.12",
|
||||||
|
"resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.12.tgz",
|
||||||
|
"integrity": "sha512-MsKncOcgTNvdtiISc/jZs/Zf8d0cl/t3gYWX8J9ubBnVOwlk65UIEEvgBORTiljloIWnBzLs4qhzPkJcitIzIg==",
|
||||||
|
"cpu": [
|
||||||
|
"s390x"
|
||||||
|
],
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"linux"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": ">=18"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@esbuild/linux-x64": {
|
||||||
|
"version": "0.25.12",
|
||||||
|
"resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.12.tgz",
|
||||||
|
"integrity": "sha512-uqZMTLr/zR/ed4jIGnwSLkaHmPjOjJvnm6TVVitAa08SLS9Z0VM8wIRx7gWbJB5/J54YuIMInDquWyYvQLZkgw==",
|
||||||
|
"cpu": [
|
||||||
|
"x64"
|
||||||
|
],
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"linux"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": ">=18"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@esbuild/netbsd-arm64": {
|
||||||
|
"version": "0.25.12",
|
||||||
|
"resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.12.tgz",
|
||||||
|
"integrity": "sha512-xXwcTq4GhRM7J9A8Gv5boanHhRa/Q9KLVmcyXHCTaM4wKfIpWkdXiMog/KsnxzJ0A1+nD+zoecuzqPmCRyBGjg==",
|
||||||
|
"cpu": [
|
||||||
|
"arm64"
|
||||||
|
],
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"netbsd"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": ">=18"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@esbuild/netbsd-x64": {
|
||||||
|
"version": "0.25.12",
|
||||||
|
"resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.12.tgz",
|
||||||
|
"integrity": "sha512-Ld5pTlzPy3YwGec4OuHh1aCVCRvOXdH8DgRjfDy/oumVovmuSzWfnSJg+VtakB9Cm0gxNO9BzWkj6mtO1FMXkQ==",
|
||||||
|
"cpu": [
|
||||||
|
"x64"
|
||||||
|
],
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"netbsd"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": ">=18"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@esbuild/openbsd-arm64": {
|
||||||
|
"version": "0.25.12",
|
||||||
|
"resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.12.tgz",
|
||||||
|
"integrity": "sha512-fF96T6KsBo/pkQI950FARU9apGNTSlZGsv1jZBAlcLL1MLjLNIWPBkj5NlSz8aAzYKg+eNqknrUJ24QBybeR5A==",
|
||||||
|
"cpu": [
|
||||||
|
"arm64"
|
||||||
|
],
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"openbsd"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": ">=18"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@esbuild/openbsd-x64": {
|
||||||
|
"version": "0.25.12",
|
||||||
|
"resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.12.tgz",
|
||||||
|
"integrity": "sha512-MZyXUkZHjQxUvzK7rN8DJ3SRmrVrke8ZyRusHlP+kuwqTcfWLyqMOE3sScPPyeIXN/mDJIfGXvcMqCgYKekoQw==",
|
||||||
|
"cpu": [
|
||||||
|
"x64"
|
||||||
|
],
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"openbsd"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": ">=18"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@esbuild/openharmony-arm64": {
|
||||||
|
"version": "0.25.12",
|
||||||
|
"resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.25.12.tgz",
|
||||||
|
"integrity": "sha512-rm0YWsqUSRrjncSXGA7Zv78Nbnw4XL6/dzr20cyrQf7ZmRcsovpcRBdhD43Nuk3y7XIoW2OxMVvwuRvk9XdASg==",
|
||||||
|
"cpu": [
|
||||||
|
"arm64"
|
||||||
|
],
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"openharmony"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": ">=18"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@esbuild/sunos-x64": {
|
||||||
|
"version": "0.25.12",
|
||||||
|
"resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.12.tgz",
|
||||||
|
"integrity": "sha512-3wGSCDyuTHQUzt0nV7bocDy72r2lI33QL3gkDNGkod22EsYl04sMf0qLb8luNKTOmgF/eDEDP5BFNwoBKH441w==",
|
||||||
|
"cpu": [
|
||||||
|
"x64"
|
||||||
|
],
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"sunos"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": ">=18"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@esbuild/win32-arm64": {
|
||||||
|
"version": "0.25.12",
|
||||||
|
"resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.12.tgz",
|
||||||
|
"integrity": "sha512-rMmLrur64A7+DKlnSuwqUdRKyd3UE7oPJZmnljqEptesKM8wx9J8gx5u0+9Pq0fQQW8vqeKebwNXdfOyP+8Bsg==",
|
||||||
|
"cpu": [
|
||||||
|
"arm64"
|
||||||
|
],
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"win32"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": ">=18"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@esbuild/win32-ia32": {
|
||||||
|
"version": "0.25.12",
|
||||||
|
"resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.12.tgz",
|
||||||
|
"integrity": "sha512-HkqnmmBoCbCwxUKKNPBixiWDGCpQGVsrQfJoVGYLPT41XWF8lHuE5N6WhVia2n4o5QK5M4tYr21827fNhi4byQ==",
|
||||||
|
"cpu": [
|
||||||
|
"ia32"
|
||||||
|
],
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"win32"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": ">=18"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@esbuild/win32-x64": {
|
||||||
|
"version": "0.25.12",
|
||||||
|
"resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.12.tgz",
|
||||||
|
"integrity": "sha512-alJC0uCZpTFrSL0CCDjcgleBXPnCrEAhTBILpeAp7M/OFgoqtAetfBzX0xM00MUsVVPpVjlPuMbREqnZCXaTnA==",
|
||||||
|
"cpu": [
|
||||||
|
"x64"
|
||||||
|
],
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"win32"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": ">=18"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@material/material-color-utilities": {
|
||||||
|
"version": "0.4.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@material/material-color-utilities/-/material-color-utilities-0.4.0.tgz",
|
||||||
|
"integrity": "sha512-dlq6VExJReb8dhjj3a/yTigr3ncNwoFmL5Iy2ENtbDX03EmNeOEdZ+vsaGrj7RTuO+mB7L58II4LCsl4NpM8uw==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "Apache-2.0"
|
||||||
|
},
|
||||||
|
"node_modules/esbuild": {
|
||||||
|
"version": "0.25.12",
|
||||||
|
"resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.12.tgz",
|
||||||
|
"integrity": "sha512-bbPBYYrtZbkt6Os6FiTLCTFxvq4tt3JKall1vRwshA3fdVztsLAatFaZobhkBC8/BrPetoa0oksYoKXoG4ryJg==",
|
||||||
|
"dev": true,
|
||||||
|
"hasInstallScript": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"bin": {
|
||||||
|
"esbuild": "bin/esbuild"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=18"
|
||||||
|
},
|
||||||
|
"optionalDependencies": {
|
||||||
|
"@esbuild/aix-ppc64": "0.25.12",
|
||||||
|
"@esbuild/android-arm": "0.25.12",
|
||||||
|
"@esbuild/android-arm64": "0.25.12",
|
||||||
|
"@esbuild/android-x64": "0.25.12",
|
||||||
|
"@esbuild/darwin-arm64": "0.25.12",
|
||||||
|
"@esbuild/darwin-x64": "0.25.12",
|
||||||
|
"@esbuild/freebsd-arm64": "0.25.12",
|
||||||
|
"@esbuild/freebsd-x64": "0.25.12",
|
||||||
|
"@esbuild/linux-arm": "0.25.12",
|
||||||
|
"@esbuild/linux-arm64": "0.25.12",
|
||||||
|
"@esbuild/linux-ia32": "0.25.12",
|
||||||
|
"@esbuild/linux-loong64": "0.25.12",
|
||||||
|
"@esbuild/linux-mips64el": "0.25.12",
|
||||||
|
"@esbuild/linux-ppc64": "0.25.12",
|
||||||
|
"@esbuild/linux-riscv64": "0.25.12",
|
||||||
|
"@esbuild/linux-s390x": "0.25.12",
|
||||||
|
"@esbuild/linux-x64": "0.25.12",
|
||||||
|
"@esbuild/netbsd-arm64": "0.25.12",
|
||||||
|
"@esbuild/netbsd-x64": "0.25.12",
|
||||||
|
"@esbuild/openbsd-arm64": "0.25.12",
|
||||||
|
"@esbuild/openbsd-x64": "0.25.12",
|
||||||
|
"@esbuild/openharmony-arm64": "0.25.12",
|
||||||
|
"@esbuild/sunos-x64": "0.25.12",
|
||||||
|
"@esbuild/win32-arm64": "0.25.12",
|
||||||
|
"@esbuild/win32-ia32": "0.25.12",
|
||||||
|
"@esbuild/win32-x64": "0.25.12"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
{
|
||||||
|
"name": "tonalmine-palettes",
|
||||||
|
"private": true,
|
||||||
|
"type": "module",
|
||||||
|
"scripts": {
|
||||||
|
"build": "esbuild build_palettes.mjs --bundle --platform=node --format=esm --outfile=.build/palettes.mjs --log-level=warning && node .build/palettes.mjs"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@material/material-color-utilities": "0.4.0",
|
||||||
|
"esbuild": "^0.25.0"
|
||||||
|
}
|
||||||
|
}
|
||||||