mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
feat(invite): progress on invite feature, #2353
This commit is contained in:
parent
93b8287d23
commit
775e044e69
@ -22,7 +22,7 @@ func Register(r *macaron.Macaron) {
|
|||||||
r.Post("/login", bind(dtos.LoginCommand{}), wrap(LoginPost))
|
r.Post("/login", bind(dtos.LoginCommand{}), wrap(LoginPost))
|
||||||
r.Get("/login/:name", OAuthLogin)
|
r.Get("/login/:name", OAuthLogin)
|
||||||
r.Get("/login", LoginView)
|
r.Get("/login", LoginView)
|
||||||
r.Get("/invite", Index)
|
r.Get("/invite/:code", Index)
|
||||||
|
|
||||||
// authed views
|
// authed views
|
||||||
r.Get("/profile/", reqSignedIn, Index)
|
r.Get("/profile/", reqSignedIn, Index)
|
||||||
|
@ -10,9 +10,10 @@ type AddInviteForm struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type InviteInfo struct {
|
type InviteInfo struct {
|
||||||
Email string `json:"email"`
|
Email string `json:"email"`
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
Username string `json:"username"`
|
Username string `json:"username"`
|
||||||
|
InvitedBy string `json:"invitedBy"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type CompleteInviteForm struct {
|
type CompleteInviteForm struct {
|
||||||
|
@ -78,7 +78,7 @@ func AddOrgInvite(c *middleware.Context, inviteDto dtos.AddInviteForm) Response
|
|||||||
"OrgName": c.OrgName,
|
"OrgName": c.OrgName,
|
||||||
"Email": c.Email,
|
"Email": c.Email,
|
||||||
"LinkUrl": setting.ToAbsUrl("invite/" + cmd.Code),
|
"LinkUrl": setting.ToAbsUrl("invite/" + cmd.Code),
|
||||||
"InvitedBy": util.StringsFallback2(c.Name, c.Email),
|
"InvitedBy": util.StringsFallback3(c.Name, c.Email, c.Login),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -114,13 +114,14 @@ func GetInviteInfoByCode(c *middleware.Context) Response {
|
|||||||
return ApiError(500, "Failed to get invite", err)
|
return ApiError(500, "Failed to get invite", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
info := dtos.InviteInfo{
|
invite := query.Result
|
||||||
Email: query.Result.Email,
|
|
||||||
Name: query.Result.Name,
|
|
||||||
Username: query.Result.Email,
|
|
||||||
}
|
|
||||||
|
|
||||||
return Json(200, &info)
|
return Json(200, dtos.InviteInfo{
|
||||||
|
Email: invite.Email,
|
||||||
|
Name: invite.Name,
|
||||||
|
Username: invite.Email,
|
||||||
|
InvitedBy: util.StringsFallback3(invite.InvitedByName, invite.InvitedByLogin, invite.InvitedByEmail),
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func CompleteInvite(c *middleware.Context, completeInvite dtos.CompleteInviteForm) Response {
|
func CompleteInvite(c *middleware.Context, completeInvite dtos.CompleteInviteForm) Response {
|
||||||
|
@ -70,18 +70,21 @@ type GetTempUsersForOrgQuery struct {
|
|||||||
type GetTempUserByCodeQuery struct {
|
type GetTempUserByCodeQuery struct {
|
||||||
Code string
|
Code string
|
||||||
|
|
||||||
Result *TempUser
|
Result *TempUserDTO
|
||||||
}
|
}
|
||||||
|
|
||||||
type TempUserDTO struct {
|
type TempUserDTO struct {
|
||||||
Id int64 `json:"id"`
|
Id int64 `json:"id"`
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
Email string `json:"email"`
|
Email string `json:"email"`
|
||||||
Role string `json:"role"`
|
Role string `json:"role"`
|
||||||
InvitedBy string `json:"invitedBy"`
|
InvitedByLogin string `json:"invitedByLogin"`
|
||||||
Code string `json:"code"`
|
InvitedByEmail string `json:"invitedByEmail"`
|
||||||
Url string `json:"url"`
|
InvitedByName string `json:"invitedByName"`
|
||||||
EmailSent bool `json:"emailSent"`
|
Code string `json:"code"`
|
||||||
EmailSentOn time.Time `json:"emailSentOn"`
|
Status TempUserStatus `json:"status"`
|
||||||
Created time.Time `json:"createdOn"`
|
Url string `json:"url"`
|
||||||
|
EmailSent bool `json:"emailSent"`
|
||||||
|
EmailSentOn time.Time `json:"emailSentOn"`
|
||||||
|
Created time.Time `json:"createdOn"`
|
||||||
}
|
}
|
||||||
|
@ -56,10 +56,13 @@ func GetTempUsersForOrg(query *m.GetTempUsersForOrgQuery) error {
|
|||||||
tu.name as name,
|
tu.name as name,
|
||||||
tu.role as role,
|
tu.role as role,
|
||||||
tu.code as code,
|
tu.code as code,
|
||||||
|
tu.status as status,
|
||||||
tu.email_sent as email_sent,
|
tu.email_sent as email_sent,
|
||||||
tu.email_sent_on as email_sent_on,
|
tu.email_sent_on as email_sent_on,
|
||||||
tu.created as created,
|
tu.created as created,
|
||||||
u.login as invited_by
|
u.login as invited_by_login,
|
||||||
|
u.name as invited_by_name,
|
||||||
|
u.email as invited_by_email
|
||||||
FROM ` + dialect.Quote("temp_user") + ` as tu
|
FROM ` + dialect.Quote("temp_user") + ` as tu
|
||||||
LEFT OUTER JOIN ` + dialect.Quote("user") + ` as u on u.id = tu.invited_by_user_id
|
LEFT OUTER JOIN ` + dialect.Quote("user") + ` as u on u.id = tu.invited_by_user_id
|
||||||
WHERE tu.org_id=? AND tu.status =? ORDER BY tu.created desc`
|
WHERE tu.org_id=? AND tu.status =? ORDER BY tu.created desc`
|
||||||
@ -71,8 +74,26 @@ func GetTempUsersForOrg(query *m.GetTempUsersForOrgQuery) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func GetTempUserByCode(query *m.GetTempUserByCodeQuery) error {
|
func GetTempUserByCode(query *m.GetTempUserByCodeQuery) error {
|
||||||
var user m.TempUser
|
var rawSql = `SELECT
|
||||||
has, err := x.Table("temp_user").Where("code=?", query.Code).Get(&user)
|
tu.id as id,
|
||||||
|
tu.email as email,
|
||||||
|
tu.name as name,
|
||||||
|
tu.role as role,
|
||||||
|
tu.code as code,
|
||||||
|
tu.status as status,
|
||||||
|
tu.email_sent as email_sent,
|
||||||
|
tu.email_sent_on as email_sent_on,
|
||||||
|
tu.created as created,
|
||||||
|
u.login as invited_by_login,
|
||||||
|
u.name as invited_by_name,
|
||||||
|
u.email as invited_by_email
|
||||||
|
FROM ` + dialect.Quote("temp_user") + ` as tu
|
||||||
|
LEFT OUTER JOIN ` + dialect.Quote("user") + ` as u on u.id = tu.invited_by_user_id
|
||||||
|
WHERE tu.code=?`
|
||||||
|
|
||||||
|
var tempUser m.TempUserDTO
|
||||||
|
sess := x.Sql(rawSql, query.Code)
|
||||||
|
has, err := sess.Get(&tempUser)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@ -80,6 +101,6 @@ func GetTempUserByCode(query *m.GetTempUserByCodeQuery) error {
|
|||||||
return m.ErrTempUserNotFound
|
return m.ErrTempUserNotFound
|
||||||
}
|
}
|
||||||
|
|
||||||
query.Result = &user
|
query.Result = &tempUser
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -32,6 +32,14 @@ func TestTempUserCommandsAndQueries(t *testing.T) {
|
|||||||
So(len(query.Result), ShouldEqual, 1)
|
So(len(query.Result), ShouldEqual, 1)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
Convey("Should be able to get temp users by code", func() {
|
||||||
|
query := m.GetTempUserByCodeQuery{Code: "asd"}
|
||||||
|
err = GetTempUserByCode(&query)
|
||||||
|
|
||||||
|
So(err, ShouldBeNil)
|
||||||
|
So(query.Result.Name, ShouldEqual, "hello")
|
||||||
|
})
|
||||||
|
|
||||||
Convey("Should be able update status", func() {
|
Convey("Should be able update status", func() {
|
||||||
cmd2 := m.UpdateTempUserStatusCommand{Code: "asd", Status: m.TmpUserRevoked}
|
cmd2 := m.UpdateTempUserStatusCommand{Code: "asd", Status: m.TmpUserRevoked}
|
||||||
err := UpdateTempUserStatus(&cmd2)
|
err := UpdateTempUserStatus(&cmd2)
|
||||||
|
@ -6,3 +6,13 @@ func StringsFallback2(val1 string, val2 string) string {
|
|||||||
}
|
}
|
||||||
return val2
|
return val2
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func StringsFallback3(val1 string, val2 string, val3 string) string {
|
||||||
|
if val1 != "" {
|
||||||
|
return val1
|
||||||
|
}
|
||||||
|
if val2 != "" {
|
||||||
|
return val2
|
||||||
|
}
|
||||||
|
return val3
|
||||||
|
}
|
||||||
|
@ -20,7 +20,8 @@ function (angular, config) {
|
|||||||
$scope.formModel.username = invite.email;
|
$scope.formModel.username = invite.email;
|
||||||
$scope.formModel.inviteCode = $routeParams.code;
|
$scope.formModel.inviteCode = $routeParams.code;
|
||||||
|
|
||||||
$scope.greeting = invite.name || invite.email;
|
$scope.greeting = invite.name || invite.email || invite.username;
|
||||||
|
$scope.invitedBy = invite.invitedBy;
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -14,8 +14,8 @@
|
|||||||
Hello {{greeting}}.
|
Hello {{greeting}}.
|
||||||
</h3>
|
</h3>
|
||||||
|
|
||||||
<div class="long-tag modal-tagline">
|
<div class="modal-tagline">
|
||||||
<span class="body-copy-emphasis">{{.InvitedBy}}</span> has invited you to join the <span class="highlight-word">{{contextSrv.user.orgName}}</span> organization in Grafana.</br>Please complete the following to accept your invitation and continue:
|
<em>{{invitedBy}}</em> has invited you to join the <span class="highlight-word">{{contextSrv.user.orgName}}</span> organization in Grafana.</br>Please complete the following to accept your invitation and continue:
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<form name="inviteForm" class="login-form">
|
<form name="inviteForm" class="login-form">
|
||||||
@ -65,17 +65,6 @@
|
|||||||
</ul>
|
</ul>
|
||||||
<div class="clearfix"></div>
|
<div class="clearfix"></div>
|
||||||
</div>
|
</div>
|
||||||
<div class="tight-form">
|
|
||||||
<ul class="tight-form-list">
|
|
||||||
<li class="tight-form-item" style="width: 128px">
|
|
||||||
Confirm Password
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
<input type="password" name="confirmPassword" class="tight-form-input last" required ng-model="formModel.confirmPassword" id="confirmPassword" style="width: 253px" placeholder="confirm password">
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
<div class="clearfix"></div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div style="margin-left: 147px; width: 254px;">
|
<div style="margin-left: 147px; width: 254px;">
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
@import "type.less";
|
||||||
@import "login.less";
|
@import "login.less";
|
||||||
@import "submenu.less";
|
@import "submenu.less";
|
||||||
@import "graph.less";
|
@import "graph.less";
|
||||||
@ -277,11 +278,6 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.long-tag {
|
|
||||||
width: 90%;
|
|
||||||
margin: 0 auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
.confirm-modal {
|
.confirm-modal {
|
||||||
max-width: 500px;
|
max-width: 500px;
|
||||||
|
|
||||||
@ -371,7 +367,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.body-copy-emphasis {
|
.body-copy-emphasis {
|
||||||
color: @headingsColor;
|
color: @headingsColor;
|
||||||
}
|
}
|
||||||
|
|
||||||
.signup-page-container {
|
.signup-page-container {
|
||||||
|
247
public/css/less/type.less
Normal file
247
public/css/less/type.less
Normal file
@ -0,0 +1,247 @@
|
|||||||
|
//
|
||||||
|
// Typography
|
||||||
|
// --------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
|
// Body text
|
||||||
|
// -------------------------
|
||||||
|
|
||||||
|
p {
|
||||||
|
margin: 0 0 @baseLineHeight / 2;
|
||||||
|
}
|
||||||
|
.lead {
|
||||||
|
margin-bottom: @baseLineHeight;
|
||||||
|
font-size: @baseFontSize * 1.5;
|
||||||
|
font-weight: 200;
|
||||||
|
line-height: @baseLineHeight * 1.5;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Emphasis & misc
|
||||||
|
// -------------------------
|
||||||
|
|
||||||
|
// Ex: 14px base font * 85% = about 12px
|
||||||
|
small { font-size: 85%; }
|
||||||
|
|
||||||
|
strong { font-weight: 500; }
|
||||||
|
em { font-style: italic; color: @headingsColor; }
|
||||||
|
cite { font-style: normal; }
|
||||||
|
|
||||||
|
// Utility classes
|
||||||
|
.muted { color: @grayLight; }
|
||||||
|
a.muted:hover,
|
||||||
|
a.muted:focus { color: darken(@grayLight, 10%); }
|
||||||
|
|
||||||
|
.text-warning { color: @warningText; }
|
||||||
|
a.text-warning:hover,
|
||||||
|
a.text-warning:focus { color: darken(@warningText, 10%); }
|
||||||
|
|
||||||
|
.text-error { color: @errorText; }
|
||||||
|
a.text-error:hover,
|
||||||
|
a.text-error:focus { color: darken(@errorText, 10%); }
|
||||||
|
|
||||||
|
.text-info { color: @infoText; }
|
||||||
|
a.text-info:hover,
|
||||||
|
a.text-info:focus { color: darken(@infoText, 10%); }
|
||||||
|
|
||||||
|
.text-success { color: @successText; }
|
||||||
|
a.text-success:hover,
|
||||||
|
a.text-success:focus { color: darken(@successText, 10%); }
|
||||||
|
|
||||||
|
.text-left { text-align: left; }
|
||||||
|
.text-right { text-align: right; }
|
||||||
|
.text-center { text-align: center; }
|
||||||
|
|
||||||
|
|
||||||
|
// Headings
|
||||||
|
// -------------------------
|
||||||
|
|
||||||
|
h1, h2, h3, h4, h5, h6 {
|
||||||
|
margin: (@baseLineHeight / 2) 0;
|
||||||
|
font-family: @headingsFontFamily;
|
||||||
|
font-weight: @headingsFontWeight;
|
||||||
|
line-height: @baseLineHeight;
|
||||||
|
color: @headingsColor;
|
||||||
|
text-rendering: optimizelegibility; // Fix the character spacing for headings
|
||||||
|
small {
|
||||||
|
font-weight: normal;
|
||||||
|
line-height: 1;
|
||||||
|
color: @grayLight;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
h1,
|
||||||
|
h2,
|
||||||
|
h3 { line-height: @baseLineHeight * 2; }
|
||||||
|
|
||||||
|
h1 { font-size: @baseFontSize * 2.00; } // ~38px
|
||||||
|
h2 { font-size: @baseFontSize * 1.75; } // ~32px
|
||||||
|
h3 { font-size: @baseFontSize * 1.50; } // ~24px
|
||||||
|
h4 { font-size: @baseFontSize * 1.25; } // ~18px
|
||||||
|
h5 { font-size: @baseFontSize; }
|
||||||
|
h6 { font-size: @baseFontSize * 0.85; } // ~12px
|
||||||
|
|
||||||
|
h1 small { font-size: @baseFontSize * 1.75; } // ~24px
|
||||||
|
h2 small { font-size: @baseFontSize * 1.25; } // ~18px
|
||||||
|
h3 small { font-size: @baseFontSize; }
|
||||||
|
h4 small { font-size: @baseFontSize; }
|
||||||
|
|
||||||
|
|
||||||
|
// Page header
|
||||||
|
// -------------------------
|
||||||
|
|
||||||
|
.page-header {
|
||||||
|
padding-bottom: (@baseLineHeight / 2) - 1;
|
||||||
|
margin: @baseLineHeight 0 (@baseLineHeight * 1.5);
|
||||||
|
border-bottom: 1px solid @grayLighter;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// Lists
|
||||||
|
// --------------------------------------------------
|
||||||
|
|
||||||
|
// Unordered and Ordered lists
|
||||||
|
ul, ol {
|
||||||
|
padding: 0;
|
||||||
|
margin: 0 0 @baseLineHeight / 2 25px;
|
||||||
|
}
|
||||||
|
ul ul,
|
||||||
|
ul ol,
|
||||||
|
ol ol,
|
||||||
|
ol ul {
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
li {
|
||||||
|
line-height: @baseLineHeight;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove default list styles
|
||||||
|
ul.unstyled,
|
||||||
|
ol.unstyled {
|
||||||
|
margin-left: 0;
|
||||||
|
list-style: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Single-line list items
|
||||||
|
ul.inline,
|
||||||
|
ol.inline {
|
||||||
|
margin-left: 0;
|
||||||
|
list-style: none;
|
||||||
|
> li {
|
||||||
|
display: inline-block;
|
||||||
|
.ie7-inline-block();
|
||||||
|
padding-left: 5px;
|
||||||
|
padding-right: 5px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Description Lists
|
||||||
|
dl {
|
||||||
|
margin-bottom: @baseLineHeight;
|
||||||
|
}
|
||||||
|
dt,
|
||||||
|
dd {
|
||||||
|
line-height: @baseLineHeight;
|
||||||
|
}
|
||||||
|
dt {
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
dd {
|
||||||
|
margin-left: @baseLineHeight / 2;
|
||||||
|
}
|
||||||
|
// Horizontal layout (like forms)
|
||||||
|
.dl-horizontal {
|
||||||
|
.clearfix(); // Ensure dl clears floats if empty dd elements present
|
||||||
|
dt {
|
||||||
|
float: left;
|
||||||
|
width: @horizontalComponentOffset - 20;
|
||||||
|
clear: left;
|
||||||
|
text-align: right;
|
||||||
|
.text-overflow();
|
||||||
|
}
|
||||||
|
dd {
|
||||||
|
margin-left: @horizontalComponentOffset;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// MISC
|
||||||
|
// ----
|
||||||
|
|
||||||
|
// Horizontal rules
|
||||||
|
hr {
|
||||||
|
margin: @baseLineHeight 0;
|
||||||
|
border: 0;
|
||||||
|
border-top: 1px solid @hrBorder;
|
||||||
|
border-bottom: 1px solid @white;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Abbreviations and acronyms
|
||||||
|
abbr[title],
|
||||||
|
// Added data-* attribute to help out our tooltip plugin, per https://github.com/twbs/bootstrap/issues/5257
|
||||||
|
abbr[data-original-title] {
|
||||||
|
cursor: help;
|
||||||
|
border-bottom: 1px dotted @grayLight;
|
||||||
|
}
|
||||||
|
abbr.initialism {
|
||||||
|
font-size: 90%;
|
||||||
|
text-transform: uppercase;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Blockquotes
|
||||||
|
blockquote {
|
||||||
|
padding: 0 0 0 15px;
|
||||||
|
margin: 0 0 @baseLineHeight;
|
||||||
|
border-left: 5px solid @grayLighter;
|
||||||
|
p {
|
||||||
|
margin-bottom: 0;
|
||||||
|
font-size: @baseFontSize * 1.25;
|
||||||
|
font-weight: 300;
|
||||||
|
line-height: 1.25;
|
||||||
|
}
|
||||||
|
small {
|
||||||
|
display: block;
|
||||||
|
line-height: @baseLineHeight;
|
||||||
|
color: @grayLight;
|
||||||
|
&:before {
|
||||||
|
content: '\2014 \00A0';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Float right with text-align: right
|
||||||
|
&.pull-right {
|
||||||
|
float: right;
|
||||||
|
padding-right: 15px;
|
||||||
|
padding-left: 0;
|
||||||
|
border-right: 5px solid @grayLighter;
|
||||||
|
border-left: 0;
|
||||||
|
p,
|
||||||
|
small {
|
||||||
|
text-align: right;
|
||||||
|
}
|
||||||
|
small {
|
||||||
|
&:before {
|
||||||
|
content: '';
|
||||||
|
}
|
||||||
|
&:after {
|
||||||
|
content: '\00A0 \2014';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Quotes
|
||||||
|
q:before,
|
||||||
|
q:after,
|
||||||
|
blockquote:before,
|
||||||
|
blockquote:after {
|
||||||
|
content: "";
|
||||||
|
}
|
||||||
|
|
||||||
|
// Addresses
|
||||||
|
address {
|
||||||
|
display: block;
|
||||||
|
margin-bottom: @baseLineHeight;
|
||||||
|
font-style: normal;
|
||||||
|
line-height: @baseLineHeight;
|
||||||
|
}
|
1
public/vendor/bootstrap/less/bootstrap.less
vendored
1
public/vendor/bootstrap/less/bootstrap.less
vendored
@ -22,7 +22,6 @@
|
|||||||
|
|
||||||
// Base CSS
|
// Base CSS
|
||||||
@import "type.less";
|
@import "type.less";
|
||||||
@import "code.less";
|
|
||||||
@import "forms.less";
|
@import "forms.less";
|
||||||
@import "tables.less";
|
@import "tables.less";
|
||||||
|
|
||||||
|
246
public/vendor/bootstrap/less/type.less
vendored
246
public/vendor/bootstrap/less/type.less
vendored
@ -1,247 +1 @@
|
|||||||
//
|
|
||||||
// Typography
|
|
||||||
// --------------------------------------------------
|
|
||||||
|
|
||||||
|
|
||||||
// Body text
|
|
||||||
// -------------------------
|
|
||||||
|
|
||||||
p {
|
|
||||||
margin: 0 0 @baseLineHeight / 2;
|
|
||||||
}
|
|
||||||
.lead {
|
|
||||||
margin-bottom: @baseLineHeight;
|
|
||||||
font-size: @baseFontSize * 1.5;
|
|
||||||
font-weight: 200;
|
|
||||||
line-height: @baseLineHeight * 1.5;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// Emphasis & misc
|
|
||||||
// -------------------------
|
|
||||||
|
|
||||||
// Ex: 14px base font * 85% = about 12px
|
|
||||||
small { font-size: 85%; }
|
|
||||||
|
|
||||||
strong { font-weight: bold; }
|
|
||||||
em { font-style: italic; }
|
|
||||||
cite { font-style: normal; }
|
|
||||||
|
|
||||||
// Utility classes
|
|
||||||
.muted { color: @grayLight; }
|
|
||||||
a.muted:hover,
|
|
||||||
a.muted:focus { color: darken(@grayLight, 10%); }
|
|
||||||
|
|
||||||
.text-warning { color: @warningText; }
|
|
||||||
a.text-warning:hover,
|
|
||||||
a.text-warning:focus { color: darken(@warningText, 10%); }
|
|
||||||
|
|
||||||
.text-error { color: @errorText; }
|
|
||||||
a.text-error:hover,
|
|
||||||
a.text-error:focus { color: darken(@errorText, 10%); }
|
|
||||||
|
|
||||||
.text-info { color: @infoText; }
|
|
||||||
a.text-info:hover,
|
|
||||||
a.text-info:focus { color: darken(@infoText, 10%); }
|
|
||||||
|
|
||||||
.text-success { color: @successText; }
|
|
||||||
a.text-success:hover,
|
|
||||||
a.text-success:focus { color: darken(@successText, 10%); }
|
|
||||||
|
|
||||||
.text-left { text-align: left; }
|
|
||||||
.text-right { text-align: right; }
|
|
||||||
.text-center { text-align: center; }
|
|
||||||
|
|
||||||
|
|
||||||
// Headings
|
|
||||||
// -------------------------
|
|
||||||
|
|
||||||
h1, h2, h3, h4, h5, h6 {
|
|
||||||
margin: (@baseLineHeight / 2) 0;
|
|
||||||
font-family: @headingsFontFamily;
|
|
||||||
font-weight: @headingsFontWeight;
|
|
||||||
line-height: @baseLineHeight;
|
|
||||||
color: @headingsColor;
|
|
||||||
text-rendering: optimizelegibility; // Fix the character spacing for headings
|
|
||||||
small {
|
|
||||||
font-weight: normal;
|
|
||||||
line-height: 1;
|
|
||||||
color: @grayLight;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
h1,
|
|
||||||
h2,
|
|
||||||
h3 { line-height: @baseLineHeight * 2; }
|
|
||||||
|
|
||||||
h1 { font-size: @baseFontSize * 2.00; } // ~38px
|
|
||||||
h2 { font-size: @baseFontSize * 1.75; } // ~32px
|
|
||||||
h3 { font-size: @baseFontSize * 1.50; } // ~24px
|
|
||||||
h4 { font-size: @baseFontSize * 1.25; } // ~18px
|
|
||||||
h5 { font-size: @baseFontSize; }
|
|
||||||
h6 { font-size: @baseFontSize * 0.85; } // ~12px
|
|
||||||
|
|
||||||
h1 small { font-size: @baseFontSize * 1.75; } // ~24px
|
|
||||||
h2 small { font-size: @baseFontSize * 1.25; } // ~18px
|
|
||||||
h3 small { font-size: @baseFontSize; }
|
|
||||||
h4 small { font-size: @baseFontSize; }
|
|
||||||
|
|
||||||
|
|
||||||
// Page header
|
|
||||||
// -------------------------
|
|
||||||
|
|
||||||
.page-header {
|
|
||||||
padding-bottom: (@baseLineHeight / 2) - 1;
|
|
||||||
margin: @baseLineHeight 0 (@baseLineHeight * 1.5);
|
|
||||||
border-bottom: 1px solid @grayLighter;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Lists
|
|
||||||
// --------------------------------------------------
|
|
||||||
|
|
||||||
// Unordered and Ordered lists
|
|
||||||
ul, ol {
|
|
||||||
padding: 0;
|
|
||||||
margin: 0 0 @baseLineHeight / 2 25px;
|
|
||||||
}
|
|
||||||
ul ul,
|
|
||||||
ul ol,
|
|
||||||
ol ol,
|
|
||||||
ol ul {
|
|
||||||
margin-bottom: 0;
|
|
||||||
}
|
|
||||||
li {
|
|
||||||
line-height: @baseLineHeight;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Remove default list styles
|
|
||||||
ul.unstyled,
|
|
||||||
ol.unstyled {
|
|
||||||
margin-left: 0;
|
|
||||||
list-style: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Single-line list items
|
|
||||||
ul.inline,
|
|
||||||
ol.inline {
|
|
||||||
margin-left: 0;
|
|
||||||
list-style: none;
|
|
||||||
> li {
|
|
||||||
display: inline-block;
|
|
||||||
.ie7-inline-block();
|
|
||||||
padding-left: 5px;
|
|
||||||
padding-right: 5px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Description Lists
|
|
||||||
dl {
|
|
||||||
margin-bottom: @baseLineHeight;
|
|
||||||
}
|
|
||||||
dt,
|
|
||||||
dd {
|
|
||||||
line-height: @baseLineHeight;
|
|
||||||
}
|
|
||||||
dt {
|
|
||||||
font-weight: bold;
|
|
||||||
}
|
|
||||||
dd {
|
|
||||||
margin-left: @baseLineHeight / 2;
|
|
||||||
}
|
|
||||||
// Horizontal layout (like forms)
|
|
||||||
.dl-horizontal {
|
|
||||||
.clearfix(); // Ensure dl clears floats if empty dd elements present
|
|
||||||
dt {
|
|
||||||
float: left;
|
|
||||||
width: @horizontalComponentOffset - 20;
|
|
||||||
clear: left;
|
|
||||||
text-align: right;
|
|
||||||
.text-overflow();
|
|
||||||
}
|
|
||||||
dd {
|
|
||||||
margin-left: @horizontalComponentOffset;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// MISC
|
|
||||||
// ----
|
|
||||||
|
|
||||||
// Horizontal rules
|
|
||||||
hr {
|
|
||||||
margin: @baseLineHeight 0;
|
|
||||||
border: 0;
|
|
||||||
border-top: 1px solid @hrBorder;
|
|
||||||
border-bottom: 1px solid @white;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Abbreviations and acronyms
|
|
||||||
abbr[title],
|
|
||||||
// Added data-* attribute to help out our tooltip plugin, per https://github.com/twbs/bootstrap/issues/5257
|
|
||||||
abbr[data-original-title] {
|
|
||||||
cursor: help;
|
|
||||||
border-bottom: 1px dotted @grayLight;
|
|
||||||
}
|
|
||||||
abbr.initialism {
|
|
||||||
font-size: 90%;
|
|
||||||
text-transform: uppercase;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Blockquotes
|
|
||||||
blockquote {
|
|
||||||
padding: 0 0 0 15px;
|
|
||||||
margin: 0 0 @baseLineHeight;
|
|
||||||
border-left: 5px solid @grayLighter;
|
|
||||||
p {
|
|
||||||
margin-bottom: 0;
|
|
||||||
font-size: @baseFontSize * 1.25;
|
|
||||||
font-weight: 300;
|
|
||||||
line-height: 1.25;
|
|
||||||
}
|
|
||||||
small {
|
|
||||||
display: block;
|
|
||||||
line-height: @baseLineHeight;
|
|
||||||
color: @grayLight;
|
|
||||||
&:before {
|
|
||||||
content: '\2014 \00A0';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Float right with text-align: right
|
|
||||||
&.pull-right {
|
|
||||||
float: right;
|
|
||||||
padding-right: 15px;
|
|
||||||
padding-left: 0;
|
|
||||||
border-right: 5px solid @grayLighter;
|
|
||||||
border-left: 0;
|
|
||||||
p,
|
|
||||||
small {
|
|
||||||
text-align: right;
|
|
||||||
}
|
|
||||||
small {
|
|
||||||
&:before {
|
|
||||||
content: '';
|
|
||||||
}
|
|
||||||
&:after {
|
|
||||||
content: '\00A0 \2014';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Quotes
|
|
||||||
q:before,
|
|
||||||
q:after,
|
|
||||||
blockquote:before,
|
|
||||||
blockquote:after {
|
|
||||||
content: "";
|
|
||||||
}
|
|
||||||
|
|
||||||
// Addresses
|
|
||||||
address {
|
|
||||||
display: block;
|
|
||||||
margin-bottom: @baseLineHeight;
|
|
||||||
font-style: normal;
|
|
||||||
line-height: @baseLineHeight;
|
|
||||||
}
|
|
||||||
|
Loading…
Reference in New Issue
Block a user