Add lookbook

This commit is contained in:
Oliver Günther
2023-07-31 13:36:18 +02:00
parent 2fdaedcadd
commit 8989f2d439
40 changed files with 1071 additions and 1728 deletions
+3
View File
@@ -279,6 +279,9 @@ group :development do
gem 'livingstyleguide', '~> 2.1.0'
gem 'sassc-rails'
# Lookbook
gem 'lookbook', '~> 2.0.3'
gem 'colored2'
# git hooks manager
+18 -13
View File
@@ -216,7 +216,6 @@ PATH
GEM
remote: https://rubygems.org/
specs:
Ascii85 (1.1.0)
actioncable (7.0.6)
actionpack (= 7.0.6)
activesupport (= 7.0.6)
@@ -306,7 +305,6 @@ GEM
addressable (2.8.4)
public_suffix (>= 2.0.2, < 6.0)
aes_key_wrap (1.1.0)
afm (0.2.2)
airbrake (13.0.3)
airbrake-ruby (~> 6.0)
airbrake-ruby (6.2.1)
@@ -383,6 +381,8 @@ GEM
cuprite (0.14.3)
capybara (~> 3.0)
ferrum (~> 0.13.0)
css_parser (1.14.0)
addressable
daemons (1.4.1)
dalli (3.2.5)
date (3.3.3)
@@ -532,12 +532,13 @@ GEM
gravatar_image_tag (1.2.0)
hana (1.3.7)
hashdiff (1.0.1)
hashery (2.1.2)
hashie (3.6.0)
html-pipeline (2.14.3)
activesupport (>= 2)
nokogiri (>= 1.4)
htmlbeautifier (1.4.2)
htmldiff (0.0.1)
htmlentities (4.3.4)
http-accept (1.7.0)
http-cookie (1.0.5)
domain_name (~> 0.5)
@@ -603,6 +604,18 @@ GEM
loofah (2.21.3)
crass (~> 1.0.2)
nokogiri (>= 1.12.0)
lookbook (2.0.3)
activemodel
css_parser
htmlbeautifier (~> 1.3)
htmlentities (~> 4.3.4)
marcel (~> 1.0)
railties (>= 5.0)
redcarpet (~> 3.5)
rouge (>= 3.26, < 5.0)
view_component (>= 2.0)
yard (~> 0.9.25)
zeitwerk (~> 2.5)
mail (2.8.1)
mini_mime (>= 0.1.1)
net-imap
@@ -679,14 +692,6 @@ GEM
ast (~> 2.4.1)
racc
pdf-core (0.9.0)
pdf-inspector (1.3.0)
pdf-reader (>= 1.0, < 3.0.a)
pdf-reader (2.11.0)
Ascii85 (~> 1.0)
afm (~> 0.2.1)
hashery (~> 2.0)
ruby-rc4
ttfunk
pg (1.5.3)
plaintext (0.3.4)
activesupport (> 2.2.1)
@@ -873,7 +878,6 @@ GEM
ruby-ole (1.2.12.2)
ruby-prof (1.6.3)
ruby-progressbar (1.13.0)
ruby-rc4 (0.1.5)
ruby-saml (1.15.0)
nokogiri (>= 1.13.10)
rexml
@@ -995,6 +999,7 @@ GEM
activerecord (>= 4.2)
xpath (3.2.0)
nokogiri (~> 1.8)
yard (0.9.34)
zeitwerk (2.6.8)
PLATFORMS
@@ -1070,6 +1075,7 @@ DEPENDENCIES
listen (~> 3.8.0)
livingstyleguide (~> 2.1.0)
lograge (~> 0.12.0)
lookbook (~> 2.0.3)
mail (= 2.8.1)
matrix (~> 0.4.2)
md_to_pdf!
@@ -1111,7 +1117,6 @@ DEPENDENCIES
ox
paper_trail (~> 12.3)
parallel_tests (~> 4.0)
pdf-inspector (~> 1.2)
pg (~> 1.5.0)
plaintext (~> 0.3.2)
prawn (~> 2.2)
+56
View File
@@ -0,0 +1,56 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
viewBox="0 0 500 500"
version="1.1"
id="svg861"
sodipodi:docname="icon_logo.svg"
inkscape:version="1.0.2 (e86c8708, 2021-01-15)">
<metadata
id="metadata867">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
</cc:Work>
</rdf:RDF>
</metadata>
<defs
id="defs865" />
<sodipodi:namedview
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="1792"
inkscape:window-height="1067"
id="namedview863"
showgrid="false"
inkscape:zoom="1.346"
inkscape:cx="250"
inkscape:cy="250"
inkscape:window-x="0"
inkscape:window-y="25"
inkscape:window-maximized="0"
inkscape:current-layer="svg861" />
<path
d="m 267.98948,387.74784 v 0 a 4.9312711,5.0968082 0 0 0 0,0.66712 28.761445,29.726934 0 0 0 57.49708,0 3.3047262,3.415662 0 0 0 0,-0.74718 v 0 -71.16852 h -57.49708 z"
style="fill:#0770b8;stroke-width:2.62479"
id="path857" />
<path
d="M 402.16653,3.4858609 H 363.82654 A 95.346514,98.547187 0 0 0 267.98948,101.95299 V 221.39442 H 99.319355 A 95.346514,98.547187 0 0 0 3.4822955,319.86155 v 79.25404 a 96.327605,99.561212 0 0 0 95.8370595,99.64126 h 38.339985 a 96.327605,99.561212 0 0 0 95.83706,-99.64126 v -79.25404 c 0,-1.30756 0,-3.36229 0,-3.36229 h -57.49707 v 82.72307 a 38.882169,40.187399 0 0 1 -38.33999,40.21408 H 99.319355 A 38.882169,40.187399 0 0 1 60.979367,399.22233 V 319.96829 A 37.901078,39.173374 0 0 1 99.319355,280.92834 H 402.16653 a 96.301787,99.534527 0 0 0 95.83706,-99.61458 V 101.95299 A 95.346514,98.547187 0 0 0 402.16653,3.4858609 Z M 440.50652,181.20702 a 38.856351,40.160714 0 0 1 -38.33999,40.1874 H 325.61565 V 101.95299 a 37.901078,39.173374 0 0 1 38.33998,-39.039947 h 38.33999 a 37.901078,39.173374 0 0 1 38.2109,39.039947 z"
style="fill:#0770b8;stroke-width:2.62479"
id="path859" />
</svg>

After

Width:  |  Height:  |  Size: 2.5 KiB

+6
View File
@@ -0,0 +1,6 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 500 500">
<path d="M267.99 387.748a4.931 5.097 0 0 0 0 .667 28.761 29.727 0 0 0 57.497 0 3.305 3.416 0 0 0 0-.747v-71.169h-57.498z"
style="fill:#fff;stroke-width:2.62479"/>
<path d="M402.167 3.486h-38.34a95.347 98.547 0 0 0-95.838 98.467v119.441H99.32a95.347 98.547 0 0 0-95.837 98.468v79.254a96.328 99.561 0 0 0 95.837 99.64h38.34a96.328 99.561 0 0 0 95.837-99.64v-82.617H176v82.723a38.882 40.187 0 0 1-38.34 40.214H99.32a38.882 40.187 0 0 1-38.34-40.214v-79.254a37.901 39.173 0 0 1 38.34-39.04h302.848a96.302 99.535 0 0 0 95.837-99.614v-79.361a95.347 98.547 0 0 0-95.837-98.467Zm38.34 177.721a38.856 40.16 0 0 1-38.34 40.187h-76.551V101.953a37.901 39.173 0 0 1 38.34-39.04h38.34a37.901 39.173 0 0 1 38.21 39.04z"
style="fill:#fff;stroke-width:2.62479"/>
</svg>

After

Width:  |  Height:  |  Size: 836 B

+6
View File
@@ -54,6 +54,12 @@ module FrontendAssetHelper
end
end
def include_spot_assets
capture do
concat stylesheet_link_tag variable_asset_path("spot.css"), media: :all, skip_pipeline: true
end
end
private
def angular_cli_asset(path)
@@ -0,0 +1,38 @@
<%#-- copyright
OpenProject is an open source project management software.
Copyright (C) 2012-2023 the OpenProject GmbH
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License version 3.
OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows:
Copyright (C) 2006-2013 Jean-Philippe Lang
Copyright (C) 2010-2013 the ChiliProject Team
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
See COPYRIGHT and LICENSE files for more details.
++#%><!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<%= include_frontend_assets %>
</head>
<body class="viewcomponent-preview">
<section class="viewcomponent-preview--content">
<%= yield %>
</section>
</body>
</html>
+45
View File
@@ -0,0 +1,45 @@
OpenProject::Application.configure do
next unless Rails.env.development?
config.lookbook.project_name = "OpenProject Lookbook"
config.lookbook.project_logo = Rails.root.join('app/assets/images/icon_logo_white.svg').read
config.lookbook.ui_favicon = Rails.root.join('app/assets/images/icon_logo.svg').read
config.lookbook.page_paths = [Rails.root.join("spec/components/docs/").to_s]
# Show notes first, all other panels next
config.lookbook.component_paths << Primer::ViewComponents::Engine.root.join("app", "components").to_s
config.view_component.preview_paths << Primer::ViewComponents::Engine.root.join("previews").to_s
config.lookbook.preview_inspector.drawer_panels = [:notes, "*"]
config.lookbook.ui_theme = "blue"
SecureHeaders::Configuration.named_append(:lookbook) do
{
script_src: %w('unsafe-eval' 'unsafe-inline') # rubocop:disable Lint/PercentStringArray
}
end
# rubocop:disable Lint/ConstantDefinitionInBlock
module LookbookCspExtender
extend ActiveSupport::Concern
included do
before_action do
use_content_security_policy_named_append :lookbook
end
end
end
# rubocop:enable Lint/ConstantDefinitionInBlock
Rails.application.reloader.to_prepare do
[
Lookbook::ApplicationController,
Lookbook::PreviewController,
Lookbook::PreviewsController,
Lookbook::PageController,
Lookbook::PagesController,
Lookbook::InspectorController,
Lookbook::EmbedsController
].each do |controller|
controller.include LookbookCspExtender
end
end
end
+2
View File
@@ -1,5 +1,7 @@
OpenProject::Application.configure do
config.view_component.generate.preview_path = Rails.root.join("spec/components/previews").to_s
config.view_component.preview_paths << Rails.root.join("spec/components/previews").to_s
config.view_component.generate.preview = true
config.view_component.default_preview_layout = "component_preview"
end
+4
View File
@@ -603,4 +603,8 @@ OpenProject::Application.routes.draw do
# Routes for design related documentation and examples pages
get '/design/styleguide' => redirect('/assets/styleguide.html')
if Rails.env.development?
mount Lookbook::Engine, at: "/design/lookbook"
end
end
+4
View File
@@ -48,6 +48,10 @@
"src/assets"
],
"styles": [
{
"input": "src/spot.scss",
"bundleName": "spot"
},
"src/styles.scss",
"node_modules/codemirror/lib/codemirror.css",
"node_modules/jquery-ui/themes/base/core.css",
@@ -1,26 +0,0 @@
# User Avatars
```
Standard:<br />
<img class="avatar" src="/assets/default-avatar.png" />
<br /><br />
Standard Mini:<br />
<img class="avatar-mini" src="/assets/default-avatar.png" />
<br /><br />
Default:<br />
<div class="avatar avatar-default">OA</div>
<br /><br />
Default Medium:<br />
<div class="avatar-medium avatar-default">OA</div>
<br /><br />
Default Mini:<br />
<div class="avatar-mini avatar-default">OA</div>
<br /><br />
Gravatar:<br />
<img src="http://gravatar.com/avatar/cb4f282fed12016bd18a879c1f27ff97" class="avatar" />
<br /><br />
Gravatar Mini:<br />
<img src="http://gravatar.com/avatar/cb4f282fed12016bd18a879c1f27ff97" class="avatar-mini" />
```
@@ -1,108 +0,0 @@
# Widget Boxes
```
@full-width
<form>
<section class="widget-boxes -flex">
<!-- Widget box with arrows: Single-line -->
<div class="widget-box">
<h3 class="widget-box--header">
<div class="widget-box--header-title title-container">
<h2 class="editable-toolbar-title--fixed">Widget Box</h2>
</div>
</h3>
<p class="widget-box--additional-info">This widget box can be used to display content belonging to one subject.</p>
<ul class="widget-box--arrow-links">
<li>
<a>Go to Link 1</a>
</li>
<li>
<a>Go to link 2</a>
</li>
</ul>
</div>
<!-- Widget box with arrows: Multiline -->
<div class="widget-box">
<h3 class="widget-box--header">
<div class="widget-box--header-title title-container">
<h2 class="editable-toolbar-title--fixed">Widget Box 2</h2>
</div>
</h3>
<ul class="widget-box--arrow-links">
<li class="-widget-box--arrow-multiline">
<div>
<img class="avatar-mini" title="OpenProject Admin" src="https://via.placeholder.com/128" alt="Avatar">
<a href="">Demo project</a>:
<a href="">Important news</a>
<br>
<p class="widget-box--additional-info">Added by
<a title="User OpenProject Admin" href="">OpenProject Admin</a>
<time title="10/31/2018 09:15 AM" class="timestamp">3 months</time> ago
</p>
</div>
</li>
<li class="-widget-box--arrow-multiline">
<div>
<img class="avatar-mini" title="OpenProject Admin" src="https://via.placeholder.com/128" alt="Avatar">
<a href="">Demo project</a>:
<a href="">Great news !!!</a>
<br>
<p class="widget-box--additional-info">Added by
<a title="User OpenProject Admin" href="">OpenProject Admin</a>
<time title="08/14/2018 11:04 AM" class="timestamp">5 months</time> ago
</p>
</div>
</li>
</ul>
</div>
<!-- Widget box with button -->
<div class="widget-box">
<h3 class="widget-box--header">
<div class="widget-box--header-title title-container">
<h2 class="editable-toolbar-title--fixed">Widget Box 3</h2>
</div>
</h3>
<div class="overview">
<p>
Lorem ipsum dolor sit amet, his ei propriae suscipit.
Sit in atqui accumsan ponderum, eum ut luptatum lobortis, has ei tota illud detraxit.
</p>
</div>
<div class="widget-box--buttons">
<a class="button -highlight" href="">
<i class="button--icon icon-edit"></i>
<span class="button--text">Edit</span>
</a>
</div>
</div>
<!-- Widget box with enumeration and multiple buttons -->
<div class="widget-box">
<h3 class="widget-box--header">
<div class="widget-box--header-title title-container">
<h2 class="editable-toolbar-title--fixed">Widget Box 4</h2>
</div>
</h3>
<ul class="widget-box--enumeration">
<li>Enum1</li>
<li>Enum2</li>
<li>Enum3</li>
</ul>
<div class="widget-box--buttons">
<a class="button -alt-highlight" title="Add" href="">
<i class="button--icon icon-add"></i>
<span class="button--text">Add</span>
</a>
<a class="button -highlight-inverted" title="View all" href="">
<span class="button--text">View all</span>
</a>
</div>
</div>
</section>
</form>
```
@@ -1,358 +0,0 @@
# Wiki
Wiki-syntax is used for most textarea-fields within OpenProject. The users have several options to style text.
## Container
```
<div class="wiki">
</div>
```
## Paragraph
```
<div class="wiki">
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Fugit sed cum quam obcaecati eius nisi tenetur tempora odio minus nulla rerum hic, itaque nam dolorum vel fuga quibusdam, praesentium unde!</p>
<p>Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet.</p>
<p>Nam liber tempor cum soluta nobis eleifend option congue nihil imperdiet doming id quod mazim placerat facer possim assum. Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diam nonummy nibh euismod tincidunt ut laoreet dolore magna aliquam erat volutpat. Ut wisi enim ad minim veniam, quis nostrud exerci tation ullamcorper suscipit lobortis nisl ut aliquip ex ea commodo consequat.</p>
<p style="text-align:right"> Right aligned
Nam liber tempor cum soluta nobis eleifend option congue nihil imperdiet doming id quod mazim placerat facer possim assum. Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diam nonummy nibh euismod tincidunt ut laoreet dolore magna aliquam erat volutpat. Ut wisi enim ad minim veniam, quis nostrud exerci tation ullamcorper suscipit lobortis nisl ut aliquip ex ea commodo consequat.</p>
<p style="text-align:center"> Centered
Nam liber tempor cum soluta nobis eleifend option congue nihil imperdiet doming id quod mazim placerat facer possim assum. Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diam nonummy nibh euismod tincidunt ut laoreet dolore magna aliquam erat volutpat. Ut wisi enim ad minim veniam, quis nostrud exerci tation ullamcorper suscipit lobortis nisl ut aliquip ex ea commodo consequat.</p>
</div>
```
## Headings
```
<div class="wiki">
<h1>
Headline H1
<a href="#Heading-H1" class="op-uc-link_permalink">¶</a>
</h1>
<h2>
Headline H2
<a href="#Heading-H2" class="op-uc-link_permalink">¶</a>
</h2>
<h3>
Headline H3
<a href="#Heading-H3" class="op-uc-link_permalink">¶</a>
</h3>
<h4>
Headline H4
<a href="#Heading-H4" class="op-uc-link_permalink">¶</a>
</h4>
<h5>
Headline H5
</h5>
<h6>
Headline H6
</h6>
</div>
```
Note: Only headings to level ***three*** are supported in the wiki toolbar at the moment. Up to level ***four***, an anchor link is added.
## Table of contents
```
<div class="wiki">
<fieldset class="form--fieldset -collapsible">
<legend class="form--fieldset-legend" title="Show/Hide table of contents" >
<a href="#">Table of Contents</a>
</legend>
<div>
<ul class="toc">
<li>
<a href="#Heading-H1">Heading H1</a>
<ul>
<li>
<a href="#Heading-H2">Heading H2</a>
<ul>
<li>
<a href="#Heading-H3">Heading H3</a>
<ul>
<li>
<a href="#Heading-H4">Heading H4</a>
</li>
</ul>
</li>
</ul>
</li>
</ul>
</li>
<li>
<a href="#Heading-H1">Heading H1</a>
<ul>
<li>
<a href="#Heading-H2">Heading H2</a>
</li>
<li>
<a href="#Heading-H2">Heading H2</a>
</li>
<ul>
<li>
<a href="#Heading-H3">Heading H3</a>
</li>
<li>
<a href="#Heading-H3">Heading H3</a>
</li>
</ul>
<li>
<a href="#Heading-H2">Heading H2</a>
</li>
</ul>
</li>
<li>
<a href="#Heading-H1">Heading H1</a>
</li>
</ul>
</div>
</fieldset>
</div>
```
Note: Only headings to level ***four*** are considered in the table of contents.
## Font styles
```
<div class="wiki">
<p>
<strong>Strong</strong>
</p>
<p>
<em>Emphasis</em>
</p>
<p>
<ins>Inserted</ins>
</p>
<p>
<ins>Deleted</ins>
</p>
<p>
<strong><em>StrongEmphasis</em></strong>
</p>
<p>
<b>Bold</b>
</p>
<p>
<i>Italic</i>
</p>
<p>
<cite>Citation</cite>
</p>
<p>
<sup>Superscript</sup>
</p>
<p>
<sub>Subscript</sub>
</p>
</div>
```
## Inline code
```
<div class="wiki">
<code>
function Y(f) {
var p = function(h) {
return function(x) {
return f(h(h))(x);
};
};
return p(p);
}
</code>
</div>
```
## Preformatted Text
```
<div class="wiki">
<pre>
This is very
formatted
text
</pre>
</div>
```
## Unordered List
```
<div class="wiki">
<ul>
<li>Item 1</li>
<li>Item 2
<ul>
<li> Subitem 1 </li>
<li>
Subitem 2
<ul>
<li> Subsubitem 1 </li>
<li> Subsubitem 2 </li>
<li> Subsubitem 3 </li>
</ul>
</li>
</ul>
</li>
<li>Item 3</li>
</ul>
</div>
```
## Ordered List
```
<div class="wiki">
<ol>
<li>Item</li>
<li>Item
<ol>
<li>Subitem</li>
<li>SubItem
<ol>
<li>Subsubitem</li>
<li>SubsubItem</li>
<li>SubsubItem</li>
</ol>
</li>
<li>SubItem</li>
</ol>
</li>
<li>Item</li>
</ol>
</div>
```
## Blockquote
```
<div class="wiki">
<blockquote>
<p>
The good news is that you're going to live. The bad news is that he is here to kill you.
</p>
</blockquote>
</div>
```
## Link
```
<div class="wiki">
<p><a href="https://google.com">External link</a></p>
<p><a href="#">Internal link</a></p>
<p><a href="#" class="wiki-link">Wiki link</a></p>
<p><a href="#" class="version">Version link</a></p>
<p><a href="#" class="message">Message link</a></p>
<p><a href="#" class="project">Project link</a></p>
<p><a href="#" class="changeset">Changeset link</a></p>
<p><a href="#" class="attachment">Attachment link</a></p>
<p><a href="#" class="source download">Source download link</a></p>
<p><a href="#" class="source">Source link</a></p>
</div>
```
Links to work packages come in various alternatives:
* only the ID
```
<div class="wiki">
<p><a href="/work_packages/56" class="issue work_package status-8 priority-2" title="pariatur eveniet autem ea consequatur maiores fuga illo (on hold)">#56</a></p>
</div>
```
* ID with a description
```
<div class="wiki">
<p><a href="/work_packages/56" class="issue" title="pariatur eveniet autem ea consequatur maiores fuga illo">Bug #56 on hold</a>: Work Package link without description 2015-03-27 2015-04-30</p>
</div>
```
* ID with description, assignee and responsible and additionally parts of the description
```
<div class="wiki">
<p><a href="/work_packages/56" class="issue" title="pariatur eveniet autem ea consequatur maiores fuga illo">Bug #56 on hold</a>: Work Package link with description 2015-03-27 2015-04-30</p>
<div class="indent quick_info attributes"><span class="label">Responsible:</span> Ulices Volkman<br><span class="label">Assignee:</span> Danika O'Keefe</div>
<div class="indent quick_info description"><p>Accedo asporto cicuta cribro canto totam molestias quis. Speculum arma desolo nam volo. Vorago explicabo aut arx. Adficio voluptates qui voluptas. Crur annus consequatur cedo vestrum comminor. Demum sollers bis arcesso dolores agnitio defaeco curso. Copia adversus via appono damno ut territo sed.</p></div>
</div>
```
## Image
```
<div class="wiki">
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Fugit sed cum quam obcaecati eius nisi tenetur tempora odio minus nulla rerum hic, itaque nam dolorum vel fuga quibusdam, praesentium unde!</p>
<div>
<img src="https://via.placeholder.com/500" alt="">
</div>
<p>Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet.</p>
</div>
```
## Table
```
<div class="wiki">
<table>
<tbody><tr>
<td> Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor </td>
<td> invidunt ut labore et </td>
<td> dolore magna aliquyam erat, sed diam </td>
<td> voluptua. At vero eos et accusam et justo duo dolores et ea rebum. </td>
</tr>
<tr>
<td> Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed </td>
<td> diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. </td>
<td> Duis autem vel eum iriure dolor in hendrerit in vulputate velit esse <br>molestie consequat, vel illum dolore eu feugiat nulla facilisis at vero eros et accumsan et iusto odio dignissim qui blandit praesent luptatum zzril delenit augue duis dolore te feugait nulla facilisi. Lorem ipsum dolor sit amet, <br>consectetuer adipiscing elit, sed diam nonummy nibh euismod tincidunt ut laoreet dolore magna aliquam erat volutpat. </td>
<td> Ut wisi enim ad minim veniam, quis nostrud exerci tation ullamcorper suscipit lobortis nisl ut aliquip ex ea commodo consequat. Duis autem vel eum iriure dolor in hendrerit in vulputate velit esse molestie consequat, vel illum dolore eu feugiat nulla facilisis at vero eros et accumsan et iusto odio dignissim qui blandit praesent luptatum zzril delenit augue duis dolore te feugait nulla facilisi. </td>
</tr>
<tr>
<td> Nam liber tempor cum soluta nobis </td>
<td> eleifend option congue nihil imperdiet doming id </td>
<td> quod mazim placerat facer possim assum. </td>
<td> Lorem ipsum dolor sit amet, consectetuer </td>
</tr>
<tr>
<td> adipiscing elit, sed diam nonummy nibh </td>
<td> </td>
<td> euismod tincidunt ut laoreet dolore magna aliquam erat volutpat. </td>
<td> Ut wisi enim ad minim veniam, quis nostrud exerci </td>
</tr>
<tr>
<td> tation ullamcorper suscipit lobortis nisl ut aliquip ex ea </td>
<td> commodo consequat. </td>
<td> Duis autem vel eum iriure dolor in hendrerit in vulputate velit esse </td>
<td> molestie consequat, vel illum dolore eu feugiat nulla facilisis. </td>
</tr>
</tbody>
</table>
</div>
```
@@ -1,389 +0,0 @@
# Work Packages - [Details Pane] - Activities
```
<div class='work-package-details-activities-list'>
<div class='work-package-details-activities-activity'>
<h3 class='activity-date -with-toggler'>
<span class='activity-date--label'>March 19, 2014</span>
<a href="" class="activity-comments--toggler button -small -transparent">
<span>Show activities with comments only</span>
</a>
</h3>
<div class='work-package-details-activities-activity-contents'>
<img alt='Avatar' class='avatar' src="https://via.placeholder.com/128" title='OpenProject Admin'>
<span class='user'>
<a href='/users/1' name=''>OpenProject Admin</a>
</span>
<span class='date'>
updated on
<span title='03/19/2014 4:38 PM'>
<span title=''>03/19/2014</span>
<span title=''>4:38 PM</span>
</span>
</span>
<div class='comments-number'>
<span>
<a href='#1' name='1'>#1</a>
</span>
<div class='comments-icons ng-hide'>
<i class='icon-quote action-icon'></i>
<i class='icon-edit action-icon'></i>
</div>
</div>
<div class="user-comment wiki">
<span class='comment wiki'>
<span class='message ng-hide'></span>
</span>
<ul class='work-package-details-activities-messages'>
<li>
<span class='message'>
<strong>Custom Integer</strong>
changed from
<i title='12442234'>12442234</i>
to
<i title='34'>34</i>
</span>
</li>
</ul>
</div>
</div>
</div>
<div class='work-package-details-activities-activity'>
<h3 class='activity-date'>
<span class='activity-date--label'>April 30, 2014</span>
</h3>
<div class='work-package-details-activities-activity-contents'>
<img alt='Avatar' class='avatar' src="https://via.placeholder.com/128" title='OpenProject Admin'>
<span class='user'>
<a href='/users/1' name=''>OpenProject Admin</a>
</span>
<span class='date'>
updated on
<span title='04/30/2014 9:40 AM'>
<span title=''>04/30/2014</span>
<span title=''>9:40 AM</span>
</span>
</span>
<div class='comments-number'>
<span>
<a href='#2' name='2'>#2</a>
</span>
<div class='comments-icons ng-hide'>
<i class='icon-quote action-icon'></i>
<i class='icon-edit action-icon'></i>
</div>
</div>
<div class="user-comment wiki">
<span class='comment wiki'>
<span class='message ng-hide'></span>
</span>
<ul class='work-package-details-activities-messages'>
<li>
<span class='message'>
<strong>Type</strong>
changed from
<i title='Support'>Support</i>
to
<i title='Bug'>Bug</i>
</span>
</li>
</ul>
</div>
</div>
</div>
<div class='work-package-details-activities-activity'>
<h3 class='activity-date'>
<span class='activity-date--label'>July 11, 2014</span>
</h3>
<div class='work-package-details-activities-activity-contents'>
<img alt='Avatar' class='avatar' src="https://via.placeholder.com/128" title='OpenProject Admin'>
<span class='user'>
<a href='/users/1' name=''>OpenProject Admin</a>
</span>
<span class='date'>
updated on
<span title='07/11/2014 4:27 PM'>
<span title=''>07/11/2014</span>
<span title=''>4:27 PM</span>
</span>
</span>
<div class='comments-number'>
<span>
<a href='#3' name='3'>#3</a>
</span>
<div class='comments-icons ng-hide'>
<i class='icon-quote action-icon'></i>
<i class='icon-edit action-icon'></i>
</div>
</div>
<div class="user-comment wiki">
<span class='comment wiki'>
<span class='message'>
<p>This is an example wiki text.</p>
</span>
</span>
</div>
</div>
</div>
<div class='work-package-details-activities-activity'>
<div class='work-package-details-activities-activity-contents'>
<img alt='Avatar' class='avatar' src="https://via.placeholder.com/128" title='OpenProject Admin'>
<span class='user'>
<a href='/users/1' name=''>OpenProject Admin</a>
</span>
<span class='date'>
updated on
<span title='07/11/2014 4:27 PM'>
<span title=''>07/11/2014</span>
<span title=''>4:27 PM</span>
</span>
</span>
<div class='comments-number'>
<span>
<a href='#4' name='4'>#4</a>
</span>
<div class='comments-icons ng-hide'>
<i class='icon-quote action-icon'></i>
<i class='icon-edit action-icon'></i>
</div>
</div>
<div class="user-comment wiki">
<span class='comment wiki'>
<span class='message ng-hide'></span>
</span>
<ul class='work-package-details-activities-messages'>
<li>
<span class='message'>
<strong>Description</strong>
set (<a class='description-details' href='/journals/5520/diff/description'>Details</a>)
</span>
</li>
</ul>
</div>
</div>
</div>
<div class='work-package-details-activities-activity'>
<h3 class='activity-date'>
<span class='activity-date--label'>August 21, 2014</span>
</h3>
<div class='work-package-details-activities-activity-contents'>
<img alt='Avatar' class='avatar' src="https://via.placeholder.com/128" title='OpenProject Admin'>
<span class='user'>
<a href='/users/1' name=''>OpenProject Admin</a>
</span>
<span class='date'>
updated on
<span title='08/21/2014 11:03 AM'>
<span title=''>08/21/2014</span>
<span title=''>11:03 AM</span>
</span>
</span>
<div class='comments-number'>
<span>
<a href='#5' name='5'>#5</a>
</span>
<div class='comments-icons ng-hide'>
<i class='icon-quote action-icon'></i>
<i class='icon-edit action-icon'></i>
</div>
</div>
<div class="user-comment wiki">
<span class='comment wiki'>
<span class='message ng-hide'></span>
</span>
<ul class='work-package-details-activities-messages'>
<li>
<span class='message'>
<strong>Parent</strong>
set to
<i title='molestias officia beatae aut et sunt ut labore'>molestias officia beatae aut et sunt ut labore</i>
</span>
</li>
</ul>
</div>
</div>
</div>
<div class='work-package-details-activities-activity'>
<div class='work-package-details-activities-activity-contents'>
<img alt='Avatar' class='avatar' src="https://via.placeholder.com/128" title='OpenProject Admin'>
<span class='user'>
<a href='/users/1' name=''>OpenProject Admin</a>
</span>
<span class='date'>
updated on
<span title='08/21/2014 11:05 AM'>
<span title=''>08/21/2014</span>
<span title=''>11:05 AM</span>
</span>
</span>
<div class='comments-number'>
<span>
<a href='#6' name='6'>#6</a>
</span>
<div class='comments-icons ng-hide'>
<i class='icon-quote action-icon'></i>
<i class='icon-edit action-icon'></i>
</div>
</div>
<div class="user-comment wiki">
<span class='comment wiki'>
<span class='message ng-hide'></span>
</span>
<ul class='work-package-details-activities-messages'>
<li>
<span class='message'>
<strong>Parent</strong>
deleted (<strike>
<i title='molestias officia beatae aut et sunt ut labore'>molestias officia beatae aut et sunt ut labore</i>
</strike>)
</span>
</li>
</ul>
</div>
</div>
</div>
<div class='work-package-details-activities-activity'>
<h3 class='activity-date'>
<span class='activity-date--label'>September 2, 2014</span>
</h3>
<div class='work-package-details-activities-activity-contents'>
<img alt='Avatar' class='avatar' src="https://via.placeholder.com/128" title='OpenProject Admin'>
<span class='user'>
<a href='/users/1' name=''>OpenProject Admin</a>
</span>
<span class='date'>
updated on
<span title='09/02/2014 8:50 AM'>
<span title=''>09/02/2014</span>
<span title=''>8:50 AM</span>
</span>
</span>
<div class='comments-number'>
<span>
<a href='#12' name='12'>#12</a>
</span>
<div class='comments-icons ng-hide'>
<i class='icon-quote action-icon'></i>
<i class='icon-edit action-icon'></i>
</div>
</div>
<div class="user-comment wiki">
<span class='comment wiki'>
<span class='message ng-hide'></span>
</span>
<ul class='work-package-details-activities-messages'>
<li>
<span class='message'>
<strong>Subject</strong>
changed from
<i title='Nothing important'>Nothing important</i>
to
<i title='Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed felis metus, lobortis eget nisi id, scelerisque sagittis eros. Duis eget tempor risus, id sagittis nisi. In accumsan sapien sed scelerisque mattis. Sed bibendum condimentum magna eget vestibulum. Etiam bibendum, justo vitae efficitur placerat, justo lorem bibendum eros, et mattis diam diam eget urna. Aenean id magna pharetra, auctor dui ut, ultrices turpis. Duis eu massa non libero dictum vestibulum et consectetur diam. Sed varius nisl leo, vitae auctor velit imperdiet in. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Suspendisse at odio lorem. In at iaculis dui, a convallis nibh. Vivamus rhoncus arcu quis purus euismod rutrum. Morbi a metus vitae metus finibus venenatis.'>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed felis metus, lobortis eget nisi id, scelerisque sagittis eros. Duis eget tempor risus, id sagittis nisi. In accumsan sapien sed scelerisque mattis. Sed bibendum condimentum magna eget vestibulum. Etiam bibendum, justo vitae efficitur placerat, justo lorem bibendum eros, et mattis diam diam eget urna. Aenean id magna pharetra, auctor dui ut, ultrices turpis. Duis eu massa non libero dictum vestibulum et consectetur diam. Sed varius nisl leo, vitae auctor velit imperdiet in. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Suspendisse at odio lorem. In at iaculis dui, a convallis nibh. Vivamus rhoncus arcu quis purus euismod rutrum. Morbi a metus vitae metus finibus venenatis.</i>
</span>
</li>
</ul>
</div>
</div>
</div>
<div class='work-package-details-activities-activity'>
<div class='work-package-details-activities-activity-contents'>
<img alt='Avatar' class='avatar' src="https://via.placeholder.com/128" title='OpenProject Admin'>
<span class='user'>
<a href='/users/1' name=''>OpenProject Admin</a>
</span>
<span class='date'>
updated on
<span title='09/02/2014 8:51 AM'>
<span title=''>09/02/2014</span>
<span title=''>8:51 AM</span>
</span>
</span>
<div class='comments-number'>
<span>
<a href='#13' name='13'>#13</a>
</span>
<div class='comments-icons ng-hide'>
<i class='icon-quote action-icon'></i>
<i class='icon-edit action-icon'></i>
</div>
</div>
<div class="user-comment wiki">
<span class='comment wiki'>
<span class='message ng-hide'></span>
</span>
<ul class='work-package-details-activities-messages'>
<li>
<span class='message'>
<strong>Custom User</strong>
set to
<i title='Zena Labadie'>Zena Labadie</i>
</span>
</li>
<li>
<span class='message'>
<strong>Custom Description</strong>
changed from
<i title='QUAS'>QUAS</i>
to
<i title='QUASQUASQUASQUASQUASQUASQUASQUASQUASQUASQUASQUASQUASQUASQUASQUASQUASQUASQUASQUASQUASQUAS QUASQUASQUASQUASQUASQUASQUASQUASQUASQUASQUASQUASQUASQUASQUASQUASQUASQUASQUASQUASQUASQUAS'>QUASQUASQUASQUASQUASQUASQUASQUASQUASQUASQUASQUASQUASQUASQUASQUASQUASQUASQUASQUASQUASQUAS QUASQUASQUASQUASQUASQUASQUASQUASQUASQUASQUASQUASQUASQUASQUASQUASQUASQUASQUASQUASQUASQUAS</i>
</span>
</li>
</ul>
</div>
</div>
</div>
<div class='work-package-details-activities-activity'>
<h3 class='activity-date'>
<span class='activity-date--label'>September 12, 2014</span>
</h3>
<div class='work-package-details-activities-activity-contents'>
<img alt='Avatar' class='avatar' src="https://via.placeholder.com/128" title='OpenProject Admin'>
<span class='user'>
<a href='/users/1' name=''>OpenProject Admin</a>
</span>
<span class='date'>
updated on
<span title='09/12/2014 8:49 AM'>
<span title=''>09/12/2014</span>
<span title=''>8:49 AM</span>
</span>
</span>
<div class='comments-number'>
<span>
<a href='#14' name='14'>#14</a>
</span>
<div class='comments-icons ng-hide'>
<i class='icon-quote action-icon'></i>
<i class='icon-edit action-icon'></i>
</div>
</div>
<div class="user-comment wiki">
<span class='comment wiki'>
<span class='message ng-hide'></span>
</span>
<ul class='work-package-details-activities-messages'>
<li>
<span class='message'>
<strong>Description</strong>
changed (<a class='description-details' href='/journals/5543/diff/description'>Details</a>)
</span>
</li>
<li>
<span class='message'>
<strong>Assignee</strong>
set to
<i title='Deron Feil'>Deron Feil</i>
</span>
</li>
<li>
<span class='message'>
<strong>Responsible</strong>
set to
<i title='Zena Labadie'>Zena Labadie</i>
</span>
</li>
</ul>
</div>
</div>
</div>
```
@@ -1,8 +0,0 @@
# Typography
Typography is divided into content and UI, depending on where the styles are applied.
Content refers to user generated information, such as wiki-syntax based entries, e.g. the description of a work package
UI is everything relating to the application itself.
@@ -1,20 +0,0 @@
# Fonts
## Lato
*Lato* for headlines:
~~~
@font-example 32px Lato
ABCDEFGHIJKLMNOPQRSTUVWXYZÄÖÜ
~~~
*Lato* for normal/small text:
~~~
@font-example bold 14px Lato
~~~
~~~
@font-example 14px Lato
~~~
@@ -1,304 +0,0 @@
## OpenProject Icon Font
*OpenProject Icon Font* for icons:
<ul class="icon-list">
<li><span class="icon icon-accessibility"></span>accessibility</li>
<li><span class="icon icon-accountable"></span>accountable</li>
<li><span class="icon icon-activity-history"></span>activity-history</li>
<li><span class="icon icon-add-attachment"></span>add-attachment</li>
<li><span class="icon icon-add-link"></span>add-link</li>
<li><span class="icon icon-add"></span>add</li>
<li><span class="icon icon-align-center"></span>align-center</li>
<li><span class="icon icon-align-justify"></span>align-justify</li>
<li><span class="icon icon-align-left"></span>align-left</li>
<li><span class="icon icon-align-right"></span>align-right</li>
<li><span class="icon icon-arrow-down1"></span>arrow-down1</li>
<li><span class="icon icon-arrow-down2"></span>arrow-down2</li>
<li><span class="icon icon-arrow-in"></span>arrow-in</li>
<li><span class="icon icon-arrow-left-right"></span>arrow-left-right</li>
<li><span class="icon icon-arrow-left1"></span>arrow-left1</li>
<li><span class="icon icon-arrow-left2"></span>arrow-left2</li>
<li><span class="icon icon-arrow-left3"></span>arrow-left3</li>
<li><span class="icon icon-arrow-left4"></span>arrow-left4</li>
<li><span class="icon icon-arrow-out"></span>arrow-out</li>
<li><span class="icon icon-arrow-right2"></span>arrow-right2</li>
<li><span class="icon icon-arrow-right3"></span>arrow-right3</li>
<li><span class="icon icon-arrow-right4"></span>arrow-right4</li>
<li><span class="icon icon-arrow-right5"></span>arrow-right5</li>
<li><span class="icon icon-arrow-right6"></span>arrow-right6</li>
<li><span class="icon icon-arrow-right7"></span>arrow-right7</li>
<li><span class="icon icon-arrow-thin"></span>arrow-thin</li>
<li><span class="icon icon-arrow-up1"></span>arrow-up1</li>
<li><span class="icon icon-arrow-up2"></span>arrow-up2</li>
<li><span class="icon icon-assigned-to-me"></span>assigned-to-me</li>
<li><span class="icon icon-assigned"></span>assigned</li>
<li><span class="icon icon-attachment"></span>attachment</li>
<li><span class="icon icon-attention"></span>attention</li>
<li><span class="icon icon-back-up"></span>back-up</li>
<li><span class="icon icon-backlogs"></span>backlogs</li>
<li><span class="icon icon-baseline"></span>baseline</li>
<li><span class="icon icon-bcf"></span>bcf</li>
<li><span class="icon icon-bell"></span>bell</li>
<li><span class="icon icon-billing-information"></span>billing-information</li>
<li><span class="icon icon-boards"></span>boards</li>
<li><span class="icon icon-bold"></span>bold</li>
<li><span class="icon icon-budget"></span>budget</li>
<li><span class="icon icon-bug"></span>bug</li>
<li><span class="icon icon-calendar"></span>calendar</li>
<li><span class="icon icon-calendar2"></span>calendar2</li>
<li><span class="icon icon-camera"></span>camera</li>
<li><span class="icon icon-cancel-circle"></span>cancel-circle</li>
<li><span class="icon icon-cancel"></span>cancel</li>
<li><span class="icon icon-cart"></span>cart</li>
<li><span class="icon icon-changeset-down"></span>changeset-down</li>
<li><span class="icon icon-changeset-up"></span>changeset-up</li>
<li><span class="icon icon-changeset"></span>changeset</li>
<li><span class="icon icon-chart1"></span>chart1</li>
<li><span class="icon icon-chart2"></span>chart2</li>
<li><span class="icon icon-chart3"></span>chart3</li>
<li><span class="icon icon-checkmark-circle"></span>checkmark-circle</li>
<li><span class="icon icon-checkmark"></span>checkmark</li>
<li><span class="icon icon-clipboard"></span>clipboard</li>
<li><span class="icon icon-close"></span>close</li>
<li><span class="icon icon-code-tag"></span>code-tag</li>
<li><span class="icon icon-color-text"></span>color-text</li>
<li><span class="icon icon-color-underline"></span>color-underline</li>
<li><span class="icon icon-column-left"></span>column-left</li>
<li><span class="icon icon-column-right"></span>column-right</li>
<li><span class="icon icon-columns"></span>columns</li>
<li><span class="icon icon-compare2"></span>compare2</li>
<li><span class="icon icon-concept"></span>concept</li>
<li><span class="icon icon-console-light"></span>console-light</li>
<li><span class="icon icon-console"></span>console</li>
<li><span class="icon icon-contacts"></span>contacts</li>
<li><span class="icon icon-copy"></span>copy</li>
<li><span class="icon icon-cost-reports"></span>cost-reports</li>
<li><span class="icon icon-cost-types"></span>cost-types</li>
<li><span class="icon icon-cursor"></span>cursor</li>
<li><span class="icon icon-custom-development"></span>custom-development</li>
<li><span class="icon icon-custom-fields"></span>custom-fields</li>
<li><span class="icon icon-cut"></span>cut</li>
<li><span class="icon icon-date-alert"></span>date-alert</li>
<li><span class="icon icon-date-alerts"></span>date-alerts</li>
<li><span class="icon icon-delete-folder"></span>delete-folder</li>
<li><span class="icon icon-delete"></span>delete</li>
<li><span class="icon icon-delta-triangle"></span>delta-triangle</li>
<li><span class="icon icon-dependency"></span>dependency</li>
<li><span class="icon icon-design"></span>design</li>
<li><span class="icon icon-double-arrow-left"></span>double-arrow-left</li>
<li><span class="icon icon-double-arrow-right"></span>double-arrow-right</li>
<li><span class="icon icon-download-arrow"></span>download-arrow</li>
<li><span class="icon icon-download"></span>download</li>
<li><span class="icon icon-drag-handle"></span>drag-handle</li>
<li><span class="icon icon-dropdown-open"></span>dropdown-open</li>
<li><span class="icon icon-dropdown"></span>dropdown</li>
<li><span class="icon icon-duplicate"></span>duplicate</li>
<li><span class="icon icon-edit"></span>edit</li>
<li><span class="icon icon-email-alert"></span>email-alert</li>
<li><span class="icon icon-enterprise-addons"></span>enterprise-addons</li>
<li><span class="icon icon-enterprise"></span>enterprise</li>
<li><span class="icon icon-enumerations"></span>enumerations</li>
<li><span class="icon icon-error"></span>error</li>
<li><span class="icon icon-export-atom"></span>export-atom</li>
<li><span class="icon icon-export-bcf"></span>export-bcf</li>
<li><span class="icon icon-export-csv"></span>export-csv</li>
<li><span class="icon icon-export-pdf-descr"></span>export-pdf-descr</li>
<li><span class="icon icon-export-pdf-with-descriptions"></span>export-pdf-with-descriptions</li>
<li><span class="icon icon-export-pdf"></span>export-pdf</li>
<li><span class="icon icon-export-xls-descr"></span>export-xls-descr</li>
<li><span class="icon icon-export-xls-with-descriptions"></span>export-xls-with-descriptions</li>
<li><span class="icon icon-export-xls-with-relations"></span>export-xls-with-relations</li>
<li><span class="icon icon-export-xls"></span>export-xls</li>
<li><span class="icon icon-export"></span>export</li>
<li><span class="icon icon-external-link"></span>external-link</li>
<li><span class="icon icon-faq"></span>faq</li>
<li><span class="icon icon-file-doc"></span>file-doc</li>
<li><span class="icon icon-file-form"></span>file-form</li>
<li><span class="icon icon-file-presentation"></span>file-presentation</li>
<li><span class="icon icon-file-sheet"></span>file-sheet</li>
<li><span class="icon icon-file-text"></span>file-text</li>
<li><span class="icon icon-filter"></span>filter</li>
<li><span class="icon icon-flag"></span>flag</li>
<li><span class="icon icon-folder-add"></span>folder-add</li>
<li><span class="icon icon-folder-locked"></span>folder-locked</li>
<li><span class="icon icon-folder-open"></span>folder-open</li>
<li><span class="icon icon-folder-remove"></span>folder-remove</li>
<li><span class="icon icon-folder"></span>folder</li>
<li><span class="icon icon-forums"></span>forums</li>
<li><span class="icon icon-from-fullscreen"></span>from-fullscreen</li>
<li><span class="icon icon-getting-started"></span>getting-started</li>
<li><span class="icon icon-glossar"></span>glossar</li>
<li><span class="icon icon-google-plus"></span>google-plus</li>
<li><span class="icon icon-group-by"></span>group-by</li>
<li><span class="icon icon-group"></span>group</li>
<li><span class="icon icon-hamburger"></span>hamburger</li>
<li><span class="icon icon-headline1"></span>headline1</li>
<li><span class="icon icon-headline2"></span>headline2</li>
<li><span class="icon icon-headline3"></span>headline3</li>
<li><span class="icon icon-headset"></span>headset</li>
<li><span class="icon icon-help"></span>help</li>
<li><span class="icon icon-help1"></span>help1</li>
<li><span class="icon icon-help2"></span>help2</li>
<li><span class="icon icon-hierarchy"></span>hierarchy</li>
<li><span class="icon icon-home"></span>home</li>
<li><span class="icon icon-hosting"></span>hosting</li>
<li><span class="icon icon-ifc"></span>ifc</li>
<li><span class="icon icon-image1"></span>image1</li>
<li><span class="icon icon-image2"></span>image2</li>
<li><span class="icon icon-import"></span>import</li>
<li><span class="icon icon-inbox"></span>inbox</li>
<li><span class="icon icon-info1"></span>info1</li>
<li><span class="icon icon-info2"></span>info2</li>
<li><span class="icon icon-input-disabled"></span>input-disabled</li>
<li><span class="icon icon-installation-services"></span>installation-services</li>
<li><span class="icon icon-italic"></span>italic</li>
<li><span class="icon icon-key"></span>key</li>
<li><span class="icon icon-link"></span>link</li>
<li><span class="icon icon-loading1"></span>loading1</li>
<li><span class="icon icon-loading2"></span>loading2</li>
<li><span class="icon icon-location"></span>location</li>
<li><span class="icon icon-locked"></span>locked</li>
<li><span class="icon icon-logout"></span>logout</li>
<li><span class="icon icon-mail1"></span>mail1</li>
<li><span class="icon icon-mail2"></span>mail2</li>
<li><span class="icon icon-maintenance-support"></span>maintenance-support</li>
<li><span class="icon icon-mark-all-read"></span>mark-all-read</li>
<li><span class="icon icon-mark-read"></span>mark-read</li>
<li><span class="icon icon-medal"></span>medal</li>
<li><span class="icon icon-meetings"></span>meetings</li>
<li><span class="icon icon-mention"></span>mention</li>
<li><span class="icon icon-menu"></span>menu</li>
<li><span class="icon icon-merge-branch"></span>merge-branch</li>
<li><span class="icon icon-microphone"></span>microphone</li>
<li><span class="icon icon-milestone"></span>milestone</li>
<li><span class="icon icon-minus1"></span>minus1</li>
<li><span class="icon icon-minus2"></span>minus2</li>
<li><span class="icon icon-mobile"></span>mobile</li>
<li><span class="icon icon-modules"></span>modules</li>
<li><span class="icon icon-more"></span>more</li>
<li><span class="icon icon-move"></span>move</li>
<li><span class="icon icon-movie"></span>movie</li>
<li><span class="icon icon-music"></span>music</li>
<li><span class="icon icon-new-planning-element"></span>new-planning-element</li>
<li><span class="icon icon-news"></span>news</li>
<li><span class="icon icon-nextcloud-circle"></span>nextcloud-circle</li>
<li><span class="icon icon-nextcloud"></span>nextcloud</li>
<li><span class="icon icon-no-hierarchy"></span>no-hierarchy</li>
<li><span class="icon icon-no-zen-mode"></span>no-zen-mode</li>
<li><span class="icon icon-not-supported"></span>not-supported</li>
<li><span class="icon icon-notes"></span>notes</li>
<li><span class="icon icon-openid"></span>openid</li>
<li><span class="icon icon-openproject"></span>openproject</li>
<li><span class="icon icon-ordered-list"></span>ordered-list</li>
<li><span class="icon icon-outline"></span>outline</li>
<li><span class="icon icon-paragraph-left"></span>paragraph-left</li>
<li><span class="icon icon-paragraph-right"></span>paragraph-right</li>
<li><span class="icon icon-paragraph"></span>paragraph</li>
<li><span class="icon icon-payment-history"></span>payment-history</li>
<li><span class="icon icon-phone"></span>phone</li>
<li><span class="icon icon-pin"></span>pin</li>
<li><span class="icon icon-play"></span>play</li>
<li><span class="icon icon-plugins"></span>plugins</li>
<li><span class="icon icon-plus"></span>plus</li>
<li><span class="icon icon-pre"></span>pre</li>
<li><span class="icon icon-presentation"></span>presentation</li>
<li><span class="icon icon-preview"></span>preview</li>
<li><span class="icon icon-print"></span>print</li>
<li><span class="icon icon-priority"></span>priority</li>
<li><span class="icon icon-project-types"></span>project-types</li>
<li><span class="icon icon-projects"></span>projects</li>
<li><span class="icon icon-publish"></span>publish</li>
<li><span class="icon icon-pulldown-up"></span>pulldown-up</li>
<li><span class="icon icon-pulldown"></span>pulldown</li>
<li><span class="icon icon-quote"></span>quote</li>
<li><span class="icon icon-quote2"></span>quote2</li>
<li><span class="icon icon-redo"></span>redo</li>
<li><span class="icon icon-relation-follows"></span>relation-follows</li>
<li><span class="icon icon-relation-new-child"></span>relation-new-child</li>
<li><span class="icon icon-relation-precedes"></span>relation-precedes</li>
<li><span class="icon icon-relations"></span>relations</li>
<li><span class="icon icon-reload"></span>reload</li>
<li><span class="icon icon-reminder"></span>reminder</li>
<li><span class="icon icon-remove-link"></span>remove-link</li>
<li><span class="icon icon-remove"></span>remove</li>
<li><span class="icon icon-rename"></span>rename</li>
<li><span class="icon icon-reported-by-me"></span>reported-by-me</li>
<li><span class="icon icon-resizer-bottom-right"></span>resizer-bottom-right</li>
<li><span class="icon icon-resizer-vertical-lines"></span>resizer-vertical-lines</li>
<li><span class="icon icon-roadmap"></span>roadmap</li>
<li><span class="icon icon-rss"></span>rss</li>
<li><span class="icon icon-rubber"></span>rubber</li>
<li><span class="icon icon-save"></span>save</li>
<li><span class="icon icon-search"></span>search</li>
<li><span class="icon icon-select-all"></span>select-all</li>
<li><span class="icon icon-send-mail"></span>send-mail</li>
<li><span class="icon icon-server-key"></span>server-key</li>
<li><span class="icon icon-settings"></span>settings</li>
<li><span class="icon icon-settings2"></span>settings2</li>
<li><span class="icon icon-settings3"></span>settings3</li>
<li><span class="icon icon-settings4"></span>settings4</li>
<li><span class="icon icon-shortcuts"></span>shortcuts</li>
<li><span class="icon icon-show-all-projects"></span>show-all-projects</li>
<li><span class="icon icon-show-more-horizontal"></span>show-more-horizontal</li>
<li><span class="icon icon-show-more"></span>show-more</li>
<li><span class="icon icon-slack"></span>slack</li>
<li><span class="icon icon-sort-ascending"></span>sort-ascending</li>
<li><span class="icon icon-sort-by"></span>sort-by</li>
<li><span class="icon icon-sort-descending"></span>sort-descending</li>
<li><span class="icon icon-sort-down"></span>sort-down</li>
<li><span class="icon icon-sort-up"></span>sort-up</li>
<li><span class="icon icon-square"></span>square</li>
<li><span class="icon icon-star"></span>star</li>
<li><span class="icon icon-status-reporting"></span>status-reporting</li>
<li><span class="icon icon-status"></span>status</li>
<li><span class="icon icon-strike-through"></span>strike-through</li>
<li><span class="icon icon-team-planner"></span>team-planner</li>
<li><span class="icon icon-text"></span>text</li>
<li><span class="icon icon-ticket-checked"></span>ticket-checked</li>
<li><span class="icon icon-ticket-down"></span>ticket-down</li>
<li><span class="icon icon-ticket-edit"></span>ticket-edit</li>
<li><span class="icon icon-ticket-minus"></span>ticket-minus</li>
<li><span class="icon icon-ticket-note"></span>ticket-note</li>
<li><span class="icon icon-ticket"></span>ticket</li>
<li><span class="icon icon-time-tracking-running"></span>time-tracking-running</li>
<li><span class="icon icon-time-tracking-start"></span>time-tracking-start</li>
<li><span class="icon icon-time-tracking-stop"></span>time-tracking-stop</li>
<li><span class="icon icon-time"></span>time</li>
<li><span class="icon icon-to-fullscreen"></span>to-fullscreen</li>
<li><span class="icon icon-training-consulting"></span>training-consulting</li>
<li><span class="icon icon-two-factor-authentication"></span>two-factor-authentication</li>
<li><span class="icon icon-types"></span>types</li>
<li><span class="icon icon-underline"></span>underline</li>
<li><span class="icon icon-undo"></span>undo</li>
<li><span class="icon icon-unit"></span>unit</li>
<li><span class="icon icon-unlocked"></span>unlocked</li>
<li><span class="icon icon-unordered-list"></span>unordered-list</li>
<li><span class="icon icon-unwatched"></span>unwatched</li>
<li><span class="icon icon-upload-arrow"></span>upload-arrow</li>
<li><span class="icon icon-upload"></span>upload</li>
<li><span class="icon icon-user-minus"></span>user-minus</li>
<li><span class="icon icon-user-plus"></span>user-plus</li>
<li><span class="icon icon-user"></span>user</li>
<li><span class="icon icon-view-card"></span>view-card</li>
<li><span class="icon icon-view-fullscreen"></span>view-fullscreen</li>
<li><span class="icon icon-view-list"></span>view-list</li>
<li><span class="icon icon-view-model"></span>view-model</li>
<li><span class="icon icon-view-split-viewer-table"></span>view-split-viewer-table</li>
<li><span class="icon icon-view-split"></span>view-split</li>
<li><span class="icon icon-view-split2"></span>view-split2</li>
<li><span class="icon icon-view-timeline"></span>view-timeline</li>
<li><span class="icon icon-warning"></span>warning</li>
<li><span class="icon icon-watched"></span>watched</li>
<li><span class="icon icon-watching"></span>watching</li>
<li><span class="icon icon-wiki-edit"></span>wiki-edit</li>
<li><span class="icon icon-wiki"></span>wiki</li>
<li><span class="icon icon-wiki2"></span>wiki2</li>
<li><span class="icon icon-work-packages"></span>work-packages</li>
<li><span class="icon icon-workflow"></span>workflow</li>
<li><span class="icon icon-yes"></span>yes</li>
<li><span class="icon icon-zen-mode"></span>zen-mode</li>
<li><span class="icon icon-zoom-auto"></span>zoom-auto</li>
<li><span class="icon icon-zoom-in"></span>zoom-in</li>
<li><span class="icon icon-zoom-out"></span>zoom-out</li>
</ul>
@@ -48,3 +48,6 @@
// Print layout
@import print
// View component preview styles
@import viewcomponent_previews
@@ -1,143 +0,0 @@
# Toolbar
A toolbar that can and should be used for actions on the current view. Initially designed for the Work package list, this can be reused throughout the application.
## Standard Button Bar
```
@full-width
<div class="toolbar-container">
<div class="toolbar">
<div class="title-container">
<h2>Title of the page</h2>
</div>
<ul class="toolbar-items">
<li class="toolbar-item">
<a href="#" class="button -highlight">An important button</a>
</li>
<li class="toolbar-item">
<button class="button">Normal button</button>
</li>
<li class="toolbar-item">
<button class="button">
<i class="button--icon icon-star"></i>
<span class="button--text">Favourite button</span>
</button>
</li>
</ul>
</div>
</div>
```
## Toolbar with form elements
```
@full-width
<div class="toolbar-container">
<div class="toolbar">
<div class="title-container">
<h2>Dragonball Z characters</h2>
</div>
<ul class="toolbar-items">
<li class="toolbar-item">
<select name="attribute">
<option value="" selected></option>
<option value="super">Super</option>
</select>
</li>
<li class="toolbar-item">
<input type="text" name="race" placeholder="Race">
</li>
<li class="toolbar-item">
<input type="number" id="level" placeholder="Level">
</li>
<li class="toolbar-item">
<select>
<option value="" selected></option>
<option value="vegeta">Vegeta</option>
<option value="kakarotto">Kakarotto</option>
<option value="gohan">Gohan</option>
<option value="piccolo">Piccolo</option>
<option value="oob">Boo</option>
</select>
</li>
<li class="toolbar-item -icon-only">
<a href="#" class="button -highlight" aria-label="Add" title="Add">
<i class="button--icon icon-add"></i>
<span class="button--text">Add</span>
</a>
</li>
</ul>
</div>
<p class="subtitle">now with extremely long subtitle: Lorem ipsum dolor sit amet, consectetur adipisicing elit. Iste consequatur doloribus suscipit nemo temporibus deserunt alias incidunt doloremque officia rerum, nobis fuga, recusandae voluptatibus voluptatem tenetur repellendus itaque et. Eum.</p>
</div>
```
## Toolbar with affix form elements
```
@full-width
<div class="toolbar-container ">
<div class="toolbar">
<div class="title-container">
<h2 title="Checkout information">Checkout information</h2>
</div>
<ul class="toolbar-items">
<li class="toolbar-item toolbar-input-group">
<div class="toolbar-input-group--affix -prepend">
<span>git clone</span>
</div>
<input type="text" class="-clickable" size="40" readonly="readonly" value="https://zerberus.example.org/git/asdf.git">
</li>
<li class="toolbar-item toolbar-input-group">
<input type="text" class="-clickable" size="40" readonly="readonly" value="https://zerberus.example.org/git/asdf.git">
<div class="toolbar-input-group--affix -append">
<span>Read + Write</span>
</div>
</li>
</ul>
</div>
</div>
```
## Toolbar with labelled form elements
```
@full-width
<div class="toolbar-container">
<div class="toolbar">
<div class="title-container">
<h2>Dragonball Z characters</h2>
</div>
<ul class="toolbar-items">
<li class="toolbar-item toolbar-input-group">
<div>
<label for="name">Name</label>
</div>
<select name="name">
<option value="" selected></option>
<option value="vegeta">Vegeta</option>
<option value="kakarotto">Kakarotto</option>
<option value="gohan">Gohan</option>
<option value="piccolo">Piccolo</option>
<option value="oob">Boo</option>
</select>
</li>
<li class="toolbar-item toolbar-input-group">
<div>
<label for="haircolor">Hair color</label>
</div>
<select name="haircolor">
<option value="" selected></option>
<option value="black">black</option>
<option value="green">green</option>
<option value="red">red</option>
<option value="yellow">yellow</option>
<option value="grey">grey</option>
</select>
</li>
</ul>
</div>
<p class="subtitle">now with extremely long subtitle: Lorem ipsum dolor sit amet, consectetur adipisicing elit. Iste consequatur doloribus suscipit nemo temporibus deserunt alias incidunt doloremque officia rerum, nobis fuga, recusandae voluptatibus voluptatem tenetur repellendus itaque et. Eum.</p>
</div>
```
@@ -0,0 +1,3 @@
.viewcomponent-preview
&--content
margin: 1rem
+9
View File
@@ -0,0 +1,9 @@
// SPOT variables
@import "src/assets/sass/_helpers.sass";
// Fonts
@import "src/global_styles/fonts/_index.sass";
// SPOT styles
@import "app/spot/styles/sass/common";
@import "app/spot/styles/sass/components";
@@ -0,0 +1,47 @@
#-- copyright
# OpenProject is an open source project management software.
# Copyright (C) 2012-2023 the OpenProject GmbH
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License version 3.
#
# OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows:
# Copyright (C) 2006-2013 Jean-Philippe Lang
# Copyright (C) 2010-2013 the ChiliProject Team
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#
# See COPYRIGHT and LICENSE files for more details.
#++
module OpenProject
module Patches
##
# Allow directory labels in lookbook to be inflected
module LookbookTreeNodeInflector
def label
return name if name == 'OpenProject'
super
end
end
end
end
if Rails.env.development?
OpenProject::Patches.patch_gem_version 'lookbook', '2.0.3' do
Lookbook::TreeNode.prepend OpenProject::Patches::LookbookTreeNodeInflector
end
end
+24
View File
@@ -0,0 +1,24 @@
---
title: Using this resource
---
We use this lookbook to document the use and adaptation of the [Primer Design System](https://primer.style/) at [OpenProject](https://www.openproject.org).
You will find defined styles, components and patterns in the relevant sections.
## Approach
OpenProject is a complex, powerful tool. One of its key strengths is its customisability and its ability to adapt to a range of different needs. This includes complex filtering options, custom types and statuses, custom fields and a wide range of options to configure views and work package forms.
Nevertheless, it is very important that OpenProject be intuitive for new users who might not necessarily need that complexity, or indeed be overwhelmed by it.
Our design approach aims to strike the right balance between powerful and accessible with a two-tiered approach: apply sane defaults and present the most common options, and allow advanced users the option (via an additional click) to customise and fine-tune.
## The UX of Open Source
As an open source project with a considerably long history and a large number of contributors, different parts of OpenProject have evolved at different paces, sometimes with completely different technology. Similar components are sometimes implemented somewhat differently in different parts of the software, and there are even multiple implementations of the same basic design.
This is quite normal for a large open-source project that has not had a dedicated design team for most of its conception.
One of the goals of the design system is to introduce more coherence and introduce a more modern design language. Whilst we would naturally prefer to be able to update everything at the same time and push the new design system to the entire software, we recognise the need for a more pragmatic approach. The design system will be rolled out in phases, with a careful study of the consequences of updating each component or pattern, and the potential dependencies that will be affected.
_We recognise that UI/UX has not always been the highest priority for open-source projects. This is somewhat understandable given how open source projects have relatively fewer design resources dedicated to it than commercial products. Our goal is to do our part to improve that situation as much as we can and document our process._
+29
View File
@@ -0,0 +1,29 @@
---
title: Semantics
---
When describing components, we use certain words in very particular ways:
### Disabled
_Disabled_ is when no interaction is possible. A disabled element can itself have multiple states: a checkbox can be checked and disabled, a switch can be ON and disabled, a dropdown might have a value but but disabled.
The opposite of disabled is _enabled_. All elements are described in their enabled state unless explicitly mentioned.
### Focused and active
Focus simply refers to when an element has the current object in DOM that has the input focus. In OpenProject, elements that are focused generally have a blue outline.
The opposite of _in focus_ (or focused) is _not in focus_ (or focused).
_Active_ is a similar state as focused, but not entirely the same. For example, in the date picker, the start date can be "active" (meaning that clicking on a date in the mini-calendar will change the start date) but not in focus (because the mouse has clicked outside of the field).
The opposite of active is _inactive_.
### Checked and on
Checkboxes can be _checked_ (true) or _unchecked_ (false)
Radio options can also be "checked" (as in, in a set of three options, only one can be checked) despite this not being the technically correct word. This isi to to distinguish it from "selected" (which refers to selecting an element or an area with the cursor).
Switches can be _ON_ (true) or _OFF_ (false).
@@ -0,0 +1,195 @@
---
title: Typography
---
<%= include_spot_assets %>
OpenProject uses the "[Lato Sans](https://github.com/latofonts/lato-source)" typeface created by Adam Twardoch, Botio Nikoltchev, and Łukasz Dziedzic (released with the [SIL Open Font license](https://scripts.sil.org/cms/scripts/page.php?site_id=nrsi&id=OFL)).
There are 7 sizes, each with between three and eight variations.
## Considerations
A few things to keep in mind:
### Black text
“Black” text in OpenProject does not use the standard black HEX code (#000000); instead, black is defined as Grey-1 (#333333).
### Line height
The default line height is 16px, which corresponds to 1 REM with our Spacing baseline.
For each style, line height is specified with a slash. For example, for Header Small Bold, 24/32 represents 1.5 REM font size and 2 REM line height.
## Header Big
This is a larger header than the default, used in rare occasions where a header is needed for a containing element to a page. To be used only if absolutely necessary. Prefer "Header small" as much as possible.
So far, zero recorded use. Might get removed if this style is not used in until mid-2022.
<blockquote class="not-prose">
<p class="spot-header-big">
Aa
<br/>
ABCDEFGHIJKLMNOPQRSTUVWXYZ
<br/>
abcdefghijklmnopqrstuvwxyz
<br/>
0123456789 ! ? & / ( ) € $ £ ¥ ¢ = @ ; : , .
</p>
</blockquote>
## Header Small
This is the default type used for page headers. "Bold" is default and is almost always preferred, unless there is a need to use regular to distinguish additional or supporting information.
<blockquote class="not-prose">
<p class="spot-header-small">
Aa
<br/>
ABCDEFGHIJKLMNOPQRSTUVWXYZ
<br/>
abcdefghijklmnopqrstuvwxyz
<br/>
0123456789 ! ? & / ( ) € $ £ ¥ ¢ = @ ; : , .
</p>
</blockquote>
## Subheader Big
Very rarely used. Used if we need a header small than the regular header but still distinct from body text.
So far, zero recorded use. Might get removed if this style is not used in until mid-2022.
<blockquote class="not-prose">
<p class="spot-subheader-big">
Aa
<br/>
ABCDEFGHIJKLMNOPQRSTUVWXYZ
<br/>
abcdefghijklmnopqrstuvwxyz
<br/>
0123456789 ! ? & / ( ) € $ £ ¥ ¢ = @ ; : , .
</p>
</blockquote>
## Subheader Small
Very rarely used. Used if we need a header small than the regular header but still distinct from body text.
<blockquote class="not-prose">
<p class="spot-subheader-small">
Aa
<br/>
ABCDEFGHIJKLMNOPQRSTUVWXYZ
<br/>
abcdefghijklmnopqrstuvwxyz
<br/>
0123456789 ! ? & / ( ) € $ £ ¥ ¢ = @ ; : , .
</p>
</blockquote>
## Subheader Extra Small
This is really an alias of _Body Small/Bold_ when this style is used as a header (in some modals) instead of body text.
<blockquote class="not-prose">
<p class="spot-subheader-extra-small">
Aa
<br/>
ABCDEFGHIJKLMNOPQRSTUVWXYZ
<br/>
abcdefghijklmnopqrstuvwxyz
<br/>
0123456789 ! ? & / ( ) € $ £ ¥ ¢ = @ ; : , .
</p>
</blockquote>
## Body Big
Used occasionally (where?)
<blockquote class="not-prose">
<p class="spot-body-big">
Aa
<br/>
ABCDEFGHIJKLMNOPQRSTUVWXYZ
<br/>
abcdefghijklmnopqrstuvwxyz
<br/>
0123456789 ! ? & / ( ) € $ £ ¥ ¢ = @ ; : , .
</p>
</blockquote>
## Body Small
This is the default style for most text on OpenProject. This goes for labels but also input text. By far the most used style style in the application.
The regular version is used, among other places, on:
- Button text
- Drop down select
- Text fields
- Table text
- Card: work package title
- Sidebar element
The bold version is used in:
- Table headers
- Calendar header
- Sidebar header
**Example**
<blockquote class="not-prose">
<p class="spot-body-small">
Aa
<br/>
ABCDEFGHIJKLMNOPQRSTUVWXYZ
<br/>
abcdefghijklmnopqrstuvwxyz
<br/>
0123456789 ! ? & / ( ) € $ £ ¥ ¢ = @ ; : , .
</p>
</blockquote>
## Caption
The caption is used for indications and auxiliary information that usually adds context to a view, but are not primary elements. They are also used on elements where space is limited (like the date information on Team planner or Board cards).
The regular version is used, among other places, in:
- Chips
- Toast text
- Tooltips
- Card: project name and ID
The bold version is used in:
- Sidebar tabs
**Example**
<blockquote class="not-prose">
<p class="spot-caption">
Aa
<br/>
ABCDEFGHIJKLMNOPQRSTUVWXYZ
<br/>
abcdefghijklmnopqrstuvwxyz
<br/>
0123456789 ! ? & / ( ) € $ £ ¥ ¢ = @ ; : , .
</p>
</blockquote>
@@ -0,0 +1,237 @@
---
title: Colors
---
**Note**: This section concerns the OP colors in use, and is about to change/consolidated with Primer color modes
Because OpenProject can be customised with custom colour schemes, our foundation library only describe the colour palette of the default OpenProject theme.
Colours are organised in this format: **Category/_name_**.
There there are six categories:
- **Basic**
- **Main**
- **Accent**
- **Danger**
- **Indication**
- **Feedback**
## Basic
The basic colour set include eight shades of gray used mostly for basic text and backgrounds. The shades do not have additional semantic significance are are simply a continuum between **Basic/_Black_** and **Basic/_White_**.
The choice of which gray to use depends on the colourspace.
Note: **Basic/_Gray-1_** is the default colour for "black" text. Pure black (_Basic/Black_) is generally not used in OpenProject.
> Code example here (Black, Gray-1, Gray-2, Gray-3, Gray-4, Gray-5, Gray-6, White)
## Main
The **Main/** colourset is a set of three shades of the OpenProject blue.
**Main/_Main_**
> Example
This is the primary blue used for all main interactions and action buttons, including text links.
It is also used in the background of the header.
**Main/_Main Dark_**
> Example
This darker version of the main blue is mainly used:
- to communicate state information (a hover or a pressed state of a button, for example)
- when the use of **Main/_Main_** does not provide enough contrast (for a border colour, for example)
**Main/_Main Light_**
> Example
This lighter version of the main blue is used:
- to communicate state information (hover on dop-down list or indicating selected toggle element, for example)
- as a background colour of interactive elements (tooltip, toast or information banners)
## Accent
> Example
The **Accent/** colourset is a set of three shades of green that is used to accent certain special functions. This colour should be used sparingly, so that when it is used, it draws the users eye.
**Accent/_Accent_**
> Example
This is the primary accent green, used for example in the default state of an accent button.
**Accent/_Accent Dark_**
> Example
This darker version is mainly used:
- to communicate state information (a hover or a pressed state of a button, for example)
- when the use of **Accent/Main** does not provide enough contrast (for a border colour, for example)
**Accent/_Accent Light_**
> Example
This lighter version of the main green is used:
- to communicate state information (hover on dop-down list or indicating selected toggle element, for example)
- as a background colour of interactive elements (tooltip, toast or information banners)
## Danger
The **Danger/** colourset is a set of three shades of red used to communicate potential danger to the user, or to warn them of a problem.
It should also be used to indicate potential destructive actions (actions like delete account or delete user) and exceptionally also used to indicate information (like in a notification badge) when the Indication/ colours cannot be used.
**Danger/_Danger_**
> Example
This is the primary danger red, used for example in the default state of an accent button.
**Danger/_Danger Dark_**
> Example
This darker version is mainly used:
- to communicate state information (a hover or a pressed state of a button, for example)
- when the use of **Danger/Danger** does not provide enough contrast (for a border colour, for example)
**Danger/_Danger Light_**
> Example
This darker version of the main danger red is used:
- to communicate state information (hover on dop-down list or indicating selected toggle element, for example)
- as a background colour of interactive elements (tooltip, toast or information banners)
## Indication
Indication colours are used to indicate certain special states.
**Indication/_Flagged_**
> Example
This colour is used when “flagging” work packages. It is a teal colour meant to be distinct from **Indication/_Attention_**.
**Indication/_Current date_**
> Example
This colour is used to indicate the current date (today) in a calendar.
**Indication/_Enterprise_**
> Example
This colour is used to indicate that a certain feature or module requires the Enterprise plan to use.
**Indication/Focus**
> Example
This is the colour used to indicate which element has keyboard focus.
## Feedback
The **Feedback/**- colors are used to communicate for user feedback:
- Error
- Warning
- Info
- Success
Each of these has two versions (Dark and Light), the dark one usually used for the foreground text and icons and the light one for the background.
These are typically used in toast messages.
**Feedback/_Error_**
> Example, Error Light and Dark
This colour indicates that a response that is different from what the user would have expected. The user flow is usually interrupted when they see an error of this type.
**Feedback/_Warning_**
> Example, Warning Light and Dark
The warning is information that suggests something requires attention (and that could cause a problem), but that no error has been caused, and that the expected user flow can continue.
**Feedback/_Info_**
> Example, Info Light and Dark
This colour is used to indicate additional information that could be of interest to the user. (Like a toast that says “Loading...”, indicating something is happening in the background)
**Feedback/_Success_**
> Example, Success Light and Dark
This colour indicates that the requested user action was successful. It should be used sparingly and only when such a feedback is absolutely required.
<div class="colors">
<%
tokens = JSON.parse File.read(Rails.root.join('frontend/src/app/spot/styles/tokens/dist/tokens.json'))
tokens.select { |k, v| k.start_with?('spot-color-') }.each do |name, value|
%>
<div class="colors--color">
<div class="colors--preview" style="background-color: <%= value %>"></div>
<div className="colors--name"><%= name %></div>
<div className="colors--value"><%= value %></div>
</div>
<% end %>
</div>
<style>
.colors {
display: flex;
flex-wrap: wrap;
margin-right: -1rem;
}
.colors--color {
border-radius: 2px;
border: 1px solid #eeeeee;
margin-bottom: 1rem;
margin-right: 1rem;
display: flex;
flex-direction: column;
flex-basis: 200px;
flex-grow: 1;
flex-shrink: 1;
min-width: 150px;
max-width: 400px;
text-align: center;
}
.colors--preview {
flex-basis: 200px;
}
.colors--name {
font-weight: bold;
padding: 0.3rem;
}
.colors--value {
padding: 0.3rem;
padding-top: 0rem;
}
</style>
@@ -0,0 +1,9 @@
---
title: Focus state
---
Focus state in OpenProject is represented by a 2-pixel outline with colour _Indication/Focus_ around the focused element.
> Example of some elements with the focus state simulated
**Note**: _Active_ is a similar state as focused, but not entirely the same. For example, in the date picker, the start date can be "active" (meaning that clicking on a date in the mini-calendar will change the start date) but not in focus (because the mouse pointer has clicked outside of the field and the focus is technically outside the field).
+102
View File
@@ -0,0 +1,102 @@
---
title: Icons
---
<%= include_spot_assets %>
# Icons
> Note: This page concerns OP icons and is about to be migrated to reference Primer icons
Icons are used as visual indicators or small illustrations. They provide additional context when necessary.
<span class="spot-icon spot-icon_add"></span>
<span class="spot-icon spot-icon_accountable"></span>
<span class="spot-icon spot-icon_add-link"></span>
<span class="spot-icon spot-icon_contacts"></span>
<span class="spot-icon spot-icon_edit"></span>
## Design notes
Icons should generally not be used on its own without a label, especially on interactive elements, where their function might be ambiguous.
There are notable examples: if the meaning of the button is abundantly clear without a label and space is limited (or repetitive elements), an icon-only interactive element is possible (for example, the "Mark as read" button on each notification element).
However, icon-only buttons or links should never be used for critical primary functions like Save, Confirm, Remove and Delete.
## Usage
Icons are a CSS class only. To use them, apply the `spot-icon` BEM block on a generic inline element like `span`.
## Options
There are four pre-defined dimensions for icons: 12×12, 16×16, 20×20 and 24×24.
The default size is 16×16.
<button class="button">
Add work package
<span class="spot-icon spot-icon_add"></span>
</button>
<a href="#" class="spot-link">
<span>This is a spot-link</span>
<span class="spot-icon spot-icon_add"></span>
</a>
## Available icons
<%
icons = JSON.parse File.read(Rails.root.join('frontend/src/app/spot/icon-font/icons.json'))
%>
<div class="icons">
<% icons.each do |name| %>
<div class="icons--icon">
<div class="icons--preview">
<span class="icons--preview-icon spot-icon spot-icon_<%= name %>"></span>
</div>
<div class="icons--name"><%= name %></div>
</div>
<% end %>
</div>
<style>
.icons {
display: flex;
flex-wrap: wrap;
margin-right: -1rem;
}
.icons--icon {
border-radius: 2px;
border: 1px solid #eeeeee;
margin-bottom: 1rem;
margin-right: 1rem;
display: flex;
flex-direction: column;
flex-basis: 120px;
flex-grow: 1;
flex-shrink: 1;
min-width: 80px;
max-width: 180px;
text-align: center;
padding: 0.5rem;
}
.icons--preview {
width: 100%;
display: flex;
justify-content: center;
align-items: center;
}
.icons--preview-icon {
font-size: 3rem;
}
.icons--name {
font-weight: bold;
margin-top: 0.5rem;
}
</style>
@@ -0,0 +1,4 @@
# @logical_path OpenProject
class AdvancedFiltersPreview < Lookbook::Preview
def default; end
end
@@ -1,8 +1,3 @@
# Advanced filters
```
@full-width
<fieldset class="advanced-filters--container">
<legend>Selected filters</legend>
<ul class="advanced-filters--filters">
@@ -121,7 +116,7 @@
</div>
<div class="advanced-filters--filter-value">
<div id="div-values-due_date">
<span class="inline-label"><input class="advanced-filters--text-field" id="values-due_date" size="3" type="text" required><label for="values_" class="form-label -transparent">days</label></span>
<span class="inline-label"><input class="advanced-filters--text-field" id="values-due_date" size="3" type="text" required><label for="values_" class="form-label -transparent">days</label></span>
</div>
</div>
<div class="advanced-filters--remove-filter">
@@ -150,7 +145,7 @@
</div>
<div class="advanced-filters--filter-value">
<div id="div-values-start_date">
<span class="inline-label" ><input class="advanced-filters--text-field" id="values-start_date" size="3" type="text" required> <label for="values_" class="form-label -transparent">days</label></span>
<span class="inline-label" ><input class="advanced-filters--text-field" id="values-start_date" size="3" type="text" required> <label for="values_" class="form-label -transparent">days</label></span>
</div>
</div>
<div class="advanced-filters--remove-filter">
@@ -340,4 +335,3 @@
</li>
</ul>
</fieldset>
```
@@ -0,0 +1,12 @@
# frozen_string_literal: true
# @logical_path OpenProject
class ToolbarComponentPreview < Lookbook::Preview
# A toolbar that can and should be used for actions on the current view.
# Initially designed for the Work package list, this can be reused throughout the application.
def default; end
def with_form_elements; end
def with_labelled_form_elements; end
end
@@ -0,0 +1,21 @@
<div class="toolbar-container">
<div class="toolbar">
<div class="title-container">
<h2>Title of the page</h2>
</div>
<ul class="toolbar-items">
<li class="toolbar-item">
<a href="#" class="button -highlight">An important button</a>
</li>
<li class="toolbar-item">
<button class="button">Normal button</button>
</li>
<li class="toolbar-item">
<button class="button">
<i class="button--icon icon-star"></i>
<span class="button--text">Favourite button</span>
</button>
</li>
</ul>
</div>
</div>
@@ -0,0 +1,38 @@
<div class="toolbar-container">
<div class="toolbar">
<div class="title-container">
<h2>Dragonball Z characters</h2>
</div>
<ul class="toolbar-items">
<li class="toolbar-item">
<select name="attribute">
<option value="" selected></option>
<option value="super">Super</option>
</select>
</li>
<li class="toolbar-item">
<input type="text" name="race" placeholder="Race">
</li>
<li class="toolbar-item">
<input type="number" id="level" placeholder="Level">
</li>
<li class="toolbar-item">
<select>
<option value="" selected></option>
<option value="vegeta">Vegeta</option>
<option value="kakarotto">Kakarotto</option>
<option value="gohan">Gohan</option>
<option value="piccolo">Piccolo</option>
<option value="oob">Boo</option>
</select>
</li>
<li class="toolbar-item -icon-only">
<a href="#" class="button -highlight" aria-label="Add" title="Add">
<i class="button--icon icon-add"></i>
<span class="button--text">Add</span>
</a>
</li>
</ul>
</div>
<p class="subtitle">now with extremely long subtitle: Lorem ipsum dolor sit amet, consectetur adipisicing elit. Iste consequatur doloribus suscipit nemo temporibus deserunt alias incidunt doloremque officia rerum, nobis fuga, recusandae voluptatibus voluptatem tenetur repellendus itaque et. Eum.</p>
</div>
@@ -0,0 +1,36 @@
<div class="toolbar-container">
<div class="toolbar">
<div class="title-container">
<h2>Dragonball Z characters</h2>
</div>
<ul class="toolbar-items">
<li class="toolbar-item toolbar-input-group">
<div>
<label for="name">Name</label>
</div>
<select name="name">
<option value="" selected></option>
<option value="vegeta">Vegeta</option>
<option value="kakarotto">Kakarotto</option>
<option value="gohan">Gohan</option>
<option value="piccolo">Piccolo</option>
<option value="oob">Boo</option>
</select>
</li>
<li class="toolbar-item toolbar-input-group">
<div>
<label for="haircolor">Hair color</label>
</div>
<select name="haircolor">
<option value="" selected></option>
<option value="black">black</option>
<option value="green">green</option>
<option value="red">red</option>
<option value="yellow">yellow</option>
<option value="grey">grey</option>
</select>
</li>
</ul>
</div>
<p class="subtitle">now with extremely long subtitle: Lorem ipsum dolor sit amet, consectetur adipisicing elit. Iste consequatur doloribus suscipit nemo temporibus deserunt alias incidunt doloremque officia rerum, nobis fuga, recusandae voluptatibus voluptatem tenetur repellendus itaque et. Eum.</p>
</div>
@@ -0,0 +1,11 @@
<%= render TooltipComponent.new do |component| %>
<% component.with_trigger do %>
Hover me to see the tooltip
<% end %>
<% component.with_body do %>
<span class="spot-body-small">
Content of the tooltip
</span>
<% end %>
<% end %>
@@ -0,0 +1,7 @@
# frozen_string_literal: true
# @logical_path OpenProject
# @label Widget boxes
class WidgetComponentPreview < Lookbook::Preview
def default; end
end
@@ -0,0 +1,100 @@
<section class="widget-boxes -flex">
<!-- Widget box with arrows: Single-line -->
<div class="widget-box">
<h3 class="widget-box--header">
<div class="widget-box--header-title title-container">
<h2 class="editable-toolbar-title--fixed">Widget Box</h2>
</div>
</h3>
<p class="widget-box--additional-info">This widget box can be used to display content belonging to one subject.</p>
<ul class="widget-box--arrow-links">
<li>
<a>Go to Link 1</a>
</li>
<li>
<a>Go to link 2</a>
</li>
</ul>
</div>
<!-- Widget box with arrows: Multiline -->
<div class="widget-box">
<h3 class="widget-box--header">
<div class="widget-box--header-title title-container">
<h2 class="editable-toolbar-title--fixed">Widget Box 2</h2>
</div>
</h3>
<ul class="widget-box--arrow-links">
<li class="-widget-box--arrow-multiline">
<div>
<img class="avatar-mini" title="OpenProject Admin" src="https://via.placeholder.com/128" alt="Avatar">
<a href="">Demo project</a>:
<a href="">Important news</a>
<br>
<p class="widget-box--additional-info">Added by
<a title="User OpenProject Admin" href="">OpenProject Admin</a>
<time title="10/31/2018 09:15 AM" class="timestamp">3 months</time> ago
</p>
</div>
</li>
<li class="-widget-box--arrow-multiline">
<div>
<img class="avatar-mini" title="OpenProject Admin" src="https://via.placeholder.com/128" alt="Avatar">
<a href="">Demo project</a>:
<a href="">Great news !!!</a>
<br>
<p class="widget-box--additional-info">Added by
<a title="User OpenProject Admin" href="">OpenProject Admin</a>
<time title="08/14/2018 11:04 AM" class="timestamp">5 months</time> ago
</p>
</div>
</li>
</ul>
</div>
<!-- Widget box with button -->
<div class="widget-box">
<h3 class="widget-box--header">
<div class="widget-box--header-title title-container">
<h2 class="editable-toolbar-title--fixed">Widget Box 3</h2>
</div>
</h3>
<div class="overview">
<p>
Lorem ipsum dolor sit amet, his ei propriae suscipit.
Sit in atqui accumsan ponderum, eum ut luptatum lobortis, has ei tota illud detraxit.
</p>
</div>
<div class="widget-box--buttons">
<a class="button -highlight" href="">
<span class="spot-icon spot-icon_edit"></span>
<span>Edit</span>
</a>
</div>
</div>
<!-- Widget box with enumeration and multiple buttons -->
<div class="widget-box">
<h3 class="widget-box--header">
<div class="widget-box--header-title title-container">
<h2 class="editable-toolbar-title--fixed">Widget Box 4</h2>
</div>
</h3>
<ul class="widget-box--enumeration">
<li>Enum1</li>
<li>Enum2</li>
<li>Enum3</li>
</ul>
<div class="widget-box--buttons">
<a class="button -alt-highlight" title="Add" href="">
<span class="spot-icon spot-icon_add"></span>
<span>Add</span>
</a>
<a class="button -highlight-inverted" title="View all" href="">
<span class="button--text">View all</span>
</a>
</div>
</div>
</section>
@@ -1,227 +0,0 @@
#-- copyright
# OpenProject is an open source project management software.
# Copyright (C) 2012-2023 the OpenProject GmbH
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License version 3.
#
# OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows:
# Copyright (C) 2006-2013 Jean-Philippe Lang
# Copyright (C) 2010-2013 the ChiliProject Team
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#
# See COPYRIGHT and LICENSE files for more details.
#++
require 'spec_helper'
RSpec.describe WorkPackage::PDFExport::WorkPackageListToPdf do
include Redmine::I18n
include PDFExportSpecUtils
let(:type_standard) { create(:type_standard) }
let(:type_bug) { create(:type_bug) }
let(:project) { create(:project, name: 'Foo Bla. Report No. 4/2021 with/for Case 42', types: [type_standard, type_bug]) }
let(:user) do
create(:user,
member_in_project: project,
member_with_permissions: %w[view_work_packages export_work_packages])
end
let(:export_time) { DateTime.new(2023, 6, 30, 23, 59) }
let(:export_time_formatted) { format_time(export_time, true) }
let(:work_package_parent) do
create(:work_package,
project:,
type: type_standard,
subject: 'Work package 1',
story_points: 1,
description: 'This is a description')
end
let(:work_package_child) do
create(:work_package,
project:,
parent: work_package_parent,
type: type_bug,
subject: 'Work package 2',
story_points: 2,
description: 'This is work package 2')
end
let(:work_packages) do
[work_package_parent, work_package_child]
end
let(:query_attributes) { {} }
let!(:query) do
build(:query, user:, project:, **query_attributes).tap do |q|
q.column_names = column_names
q.sort_criteria = [%w[id asc]]
end
end
let(:column_titles) { column_names.map { |name| column_title(name) } }
let(:options) { {} }
let(:export) do
login_as(user)
work_packages
described_class.new(query, options)
end
let(:export_pdf) do
Timecop.freeze(export_time) do
export.export!
end
end
let(:column_names) { %i[id subject status story_points] }
def work_packages_sum
work_package_parent.story_points + work_package_child.story_points
end
def work_package_columns(work_package)
[work_package.id.to_s, work_package.subject, work_package.status.name, work_package.story_points.to_s]
end
def work_package_details(work_package, index)
["#{index}.", work_package.subject,
column_title(:id), work_package.id.to_s,
column_title(:status), work_package.status.name,
column_title(:story_points), work_package.story_points.to_s,
label_title(:description), work_package.description]
end
subject(:pdf) do
PDF::Inspector::Text.analyze(File.read(export_pdf.content.path))
end
describe 'with a request for a PDF table' do
it 'contains correct data' do
expect(pdf.strings).to eq([
query.name,
*column_titles,
*work_package_columns(work_package_parent),
*work_package_columns(work_package_child),
'1/1', export_time_formatted, query.name
])
end
end
describe 'with a request for a PDF table grouped' do
let(:query_attributes) { { group_by: 'type' } }
it 'contains correct data' do
expect(pdf.strings).to eq([
query.name,
work_package_parent.type.name,
*column_titles,
*work_package_columns(work_package_parent),
work_package_child.type.name,
*column_titles,
*work_package_columns(work_package_child),
'1/1', export_time_formatted, query.name
])
end
end
describe 'with a request for a PDF table grouped with sums' do
let(:query_attributes) { { group_by: 'type', display_sums: true } }
it 'contains correct data' do
expect(pdf.strings).to eq([
query.name,
work_package_parent.type.name,
*column_titles,
*work_package_columns(work_package_parent),
I18n.t('js.label_sum'), work_package_parent.story_points.to_s,
work_package_child.type.name,
*column_titles,
*work_package_columns(work_package_child),
I18n.t('js.label_sum'), work_package_child.story_points.to_s,
'1/1', export_time_formatted, query.name
])
end
end
describe 'with a request for a PDF Report' do
let(:options) { { show_report: true } }
it 'contains correct data' do
expect(pdf.strings).to eq([
query.name,
'1.', '2', work_package_parent.subject,
'2.', '2', work_package_child.subject,
'1/2', export_time_formatted, query.name,
*work_package_details(work_package_parent, "1"),
*work_package_details(work_package_child, "2"),
'2/2', export_time_formatted, query.name
])
end
end
describe 'with a request for a PDF Report with hierarchies' do
let(:options) { { show_report: true } }
let(:query_attributes) { { show_hierarchies: true } }
it 'contains correct data' do
expect(pdf.strings).to eq([
query.name,
'1.', '2', work_package_parent.subject,
'1.1.', '2', work_package_child.subject,
'1/2', export_time_formatted, query.name,
*work_package_details(work_package_parent, '1'),
*work_package_details(work_package_child, '1.1'),
'2/2', export_time_formatted, query.name
])
end
end
describe 'with a request for a PDF Report with sums' do
let(:options) { { show_report: true } }
let(:query_attributes) { { display_sums: true } }
it 'contains correct data' do
expect(pdf.strings).to eq([
query.name,
'1.', '2', work_package_parent.subject,
'2.', '2', work_package_child.subject,
'1/2', export_time_formatted, query.name,
I18n.t('js.work_packages.tabs.overview'),
column_title(:story_points),
I18n.t('js.label_sum'), work_packages_sum.to_s,
*work_package_details(work_package_parent, "1"),
*work_package_details(work_package_child, "2"),
'2/2', export_time_formatted, query.name
])
end
end
describe 'with a request for a PDF Report grouped with sums' do
let(:options) { { show_report: true } }
let(:query_attributes) { { display_sums: true, group_by: 'type' } }
it 'contains correct data' do
expect(pdf.strings).to eq([
query.name,
'1.', '2', work_package_parent.subject,
'2.', '2', work_package_child.subject,
'1/2', export_time_formatted, query.name,
I18n.t('js.work_packages.tabs.overview'),
column_title(:type), column_title(:story_points),
work_package_parent.type.name, work_package_parent.story_points.to_s,
work_package_child.type.name, work_package_child.story_points.to_s,
I18n.t('js.label_sum'), work_packages_sum.to_s,
*work_package_details(work_package_parent, "1"),
*work_package_details(work_package_child, "2"),
'2/2', export_time_formatted, query.name
])
end
end
end
@@ -1,112 +0,0 @@
#-- copyright
# OpenProject is an open source project management software.
# Copyright (C) 2012-2023 the OpenProject GmbH
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License version 3.
#
# OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows:
# Copyright (C) 2006-2013 Jean-Philippe Lang
# Copyright (C) 2010-2013 the ChiliProject Team
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#
# See COPYRIGHT and LICENSE files for more details.
#++
require 'spec_helper'
RSpec.describe WorkPackage::PDFExport::WorkPackageToPdf do
include Redmine::I18n
include PDFExportSpecUtils
let(:type) { create(:type_bug) }
let(:project) { create(:project, name: 'Foo Bla. Report No. 4/2021 with/for Case 42', types: [type]) }
let(:user) do
create(:user,
member_in_project: project,
member_with_permissions: %w[view_work_packages export_work_packages])
end
let(:export_time) { DateTime.new(2023, 6, 30, 23, 59) }
let(:export_time_formatted) { format_time(export_time, true) }
let(:image_path) { Rails.root.join("spec/fixtures/files/image.png") }
let(:image_attachment) { Attachment.new author: user, file: File.open(image_path) }
let(:attachments) { [image_attachment] }
let(:work_package) do
description = <<~DESCRIPTION
**Lorem** _ipsum_ ~~dolor~~ `sit` [amet](https://example.com/), consetetur sadipscing elitr.
<mention data-text="@OpenProject Admin">@OpenProject Admin</mention>
![](/api/v3/attachments/#{image_attachment.id}/content)
<p class="op-uc-p">
<figure class="op-uc-figure">
<div class="op-uc-figure--content">
<img class="op-uc-image" src="/api/v3/attachments/#{image_attachment.id}/content" alt='"foobar"'>
</div>
<figcaption>Image Caption</figcaption>
</figure>
</p>
<p><unknown-tag>Foo</unknown-tag></p>
DESCRIPTION
create(:work_package,
project:,
type:,
subject: 'Work package 1',
story_points: 1,
description:).tap do |wp|
allow(wp)
.to receive(:attachments)
.and_return attachments
end
end
let(:options) { {} }
let(:export) do
login_as(user)
described_class.new(work_package, options)
end
let(:export_pdf) do
Timecop.freeze(export_time) do
export.export!
end
end
subject(:pdf) do
content = export_pdf.content
# File.binwrite('WorkPackageToPdf-test-preview.pdf', content)
{ strings: PDF::Inspector::Text.analyze(content).strings,
images: PDF::Inspector::XObject.analyze(content).page_xobjects.flat_map do |o|
o.values.select { |v| v.hash[:Subtype] == :Image }
end }
end
describe 'with a request for a PDF' do
it 'contains correct data' do
expect(pdf[:strings]).to eq([
"#{type.name} ##{work_package.id} - #{work_package.subject}",
column_title(:id), work_package.id.to_s,
column_title(:updated_at), export_time_formatted,
column_title(:type), type.name,
column_title(:created_at), export_time_formatted,
column_title(:status), work_package.status.name,
column_title(:priority), work_package.priority.name,
label_title(:description),
'Lorem', ' ', 'ipsum', ' ', 'dolor', ' ', 'sit', ' ',
'amet', ', consetetur sadipscing elitr.', ' ', '@OpenProject Admin',
'Image Caption',
'Foo',
'1', export_time_formatted, project.name
])
expect(pdf[:images].length).to eq(2)
end
end
end
-12
View File
@@ -1,12 +0,0 @@
require 'spec_helper'
require 'pdf/inspector'
module PDFExportSpecUtils
def column_title(column_name)
label_title(column_name).upcase
end
def label_title(column_name)
WorkPackage.human_attribute_name(column_name)
end
end